Estructura de la unidad de juego RTS

18

Quiero una manera de hacer muchas unidades diferentes sin tener que programar cosas como moveTo y Attack más de una vez

A mi modo de ver, hay 2 formas en que puedo hacer esto.

  1. Una única clase de Unidad genérica con banderas que especifica lo que puede / no puede hacer (luego cree instancias en una matriz estática y agárrelas cuando sea necesario)
  2. Clase de unidad abstracta con métodos abstractos para acciones específicas de la Unidad como (Ataque, Cosecha, Patrulla), que luego deben implementarse en las subclases , incluso si la unidad no puede cosechar nada.

La primera forma de hacer esto parece la más simple, pero terminaría teniendo una gran cantidad de código sin usar para la mayoría de las unidades.

la segunda forma también podría funcionar. Pero si decido tener dos unidades diferentes que puedan recolectar recursos, tendré exactamente el mismo código en dos clases diferentes, lo que no parece ser la forma correcta de hacerlo.

¿Es este incluso el enfoque correcto para este problema?
En un juego como AoE, cada unidad tiene, lo que supongo es, algún tipo de Lista de Acciones / Órdenes, realmente me gustaría saber cómo lograr algo similar a eso, donde puedo codificar cada Acción / Orden una vez, y luego dáselo a todas las unidades que necesiten dicha Acción.

Si no estoy claro (muy plausible) o si necesita más información sobre lo que estoy buscando exactamente, solo pregúnteme en un comentario.

Daniel Holst
fuente

Respuestas:

25

Un enfoque común es tener un enfoque basado en componentes donde la "Unidad" de clase base simplemente implemente los aspectos más básicos que todas las unidades tienen en común, mientras que cada unidad tiene una lista de múltiples objetos componentes que dicen lo que puede hacer y como lo hace

Por ejemplo, un tanque podría tener los componentes Mobile, Destructible, Attacker, una torreta inmóvil única Destructible, Attackery una cosechadora Mobile, Destructible, Harvester. Estas clases incluirían todo el código necesario para implementar estos comportamientos. Las interacciones entre componentes (un Attackersolo puede dañar lo que es Destructible) se pueden implementar haciendo que el componente verifique si la otra unidad tiene el componente requerido y luego interactúe directamente con ese componente.

La ventaja sobre una herencia de clase clásica es que puedes combinar fácilmente habilidades. Por ejemplo, cuando desea tener una cosechadora que también pueda atacar, transportar infantería y volar, solo necesita agregar los componentes necesarios. También puede agregar y eliminar fácilmente nuevas funciones en forma de nuevos componentes sin tener que hinchar la clase básica de Unidad.

Unity lo apoya en dicha arquitectura, porque todo el motor ya está basado en componentes. Por lo tanto, los componentes lógicos del juego como estos se pueden agregar en forma de scripts.

Philipp
fuente
Entonces, en la unidad, ¿deshabilitaría y habilitaría los componentes según sea necesario?
Daniel Holst
@DanielHolst No, los agregaría y eliminaría según sea necesario. Puede hacerlo en el editor de Unity o con scripts usando gameObject.AddComponenty gameObject.RemoveComponent.
Philipp
ah bien, pero digamos para una acción / orden "moveTo". ¿Cómo sabría la unidad cuándo se realiza el pedido?
Daniel Holst
2
@DanielHolst Creo que entendiste mal algo. El Movingcomponente significa que "esta unidad es generalmente capaz de moverse". El componente está permanentemente conectado a él, independientemente de si la unidad se está moviendo o no. No significa que se esté moviendo en este momento . Aunque también podría hacerlo de esta manera agregando un MoveOrdercomponente y haciendo que ese componente se retire de la unidad cuando se complete o cancele el pedido.
Philipp
1
@DanielHolst Ahora estás a la deriva en la dirección de la unidad AI, que es otra lata de gusanos. Un posible enfoque sería tener una biblioteca de componentes AIScript que suponga que ciertos componentes están presentes o cambie su comportamiento dependiendo de los componentes que tenga la unidad. Pero ese es realmente un tema demasiado complejo para manejarlo en un comentario.
Philipp
4

Muchos juegos usan un sistema basado en componentes para entidades, que es donde se pueden agregar un montón de comportamientos y habilidades a un tipo de unidad más genérico en lugar de codificarse como parte de la clase de la entidad (o equivalente).

Ross Taylor-Turner
fuente
¿Sería extremadamente difícil de implementar?
Daniel Holst
Patrones como este se utilizan para facilitar la implementación en general. Si no puede decidir qué enfoque tomar, es una buena idea comenzar tan simple como sea posible y aumentar su elección a medida que tenga más funcionalidad. Una vez que tenga una idea más clara del problema, puede refactorizar o reescribir un enfoque que se adapte mejor a su situación.
Ross Taylor-Turner
1
@DanielHolst Noto que tu pregunta tiene la Unitybandera. Unity ya tiene un sistema de componentes incorporado y favorece fuertemente la composición sobre la herencia . Un método sencillo sería crear un MonoBehaviourpara cada uno de sus tipos de acción, luego adjuntar a cada tipo de unidad prefabricadas las acciones que puede realizar (personalizando las instancias de acción con detalles por tipo como valores de daño y costos). Esto mantiene la creación de su unidad basada en datos, por lo que puede crear fácilmente muchos tipos de unidades personalizadas.
DMGregory
@DanielHolst Eso depende de tu definición de "extremadamente difícil". Mi respuesta entra en más detalles sobre cómo se podría implementar esto.
Philipp