La codificación no es tan difícil en realidad . La parte difícil es escribir código que tenga sentido, que sea legible y comprensible. Así que quiero conseguir un mejor desarrollador y crear una arquitectura sólida.
Así que quiero crear una arquitectura para NPC en un videojuego. Es un juego de estrategia en tiempo real como Starcraft, Age of Empires, Command & Conquers, etc. Así que tendré diferentes tipos de NPC. Un NPC puede tener de uno a muchas habilidades (métodos) de estos: Build()
, Farm()
y Attack()
.
Ejemplos:
trabajador puede Build()
y Farm()
Guerrero puede Attack()
ciudadano puede Build()
, Farm()
y Attack()
Fisherman puede Farm()
yAttack()
Espero que todo esté claro hasta ahora.
Así que ahora tengo mis tipos de NPC y sus habilidades. Pero pasemos al aspecto técnico / programático.
¿Cuál sería una buena arquitectura programática para mis diferentes tipos de NPC?
Bien, podría tener una clase base. En realidad, creo que esta es una buena manera de seguir con el principio DRY . Así que puedo tener métodos como WalkTo(x,y)
en mi clase base ya que cada NPC podrá moverse. Pero ahora vamos al verdadero problema. ¿Dónde implemento mis habilidades? (recuerde: Build()
, Farm()
y Attack()
)
Dado que las habilidades consistirán en la misma lógica, sería molesto / romper el principio DRY implementarlas para cada NPC (Trabajador, Guerrero, ...).
Bien, podría implementar las habilidades dentro de la clase base. Para ello sería necesario algún tipo de lógica que verifica si un NPC puede usar la habilidad X. IsBuilder
, CanBuild
.. creo que es claro lo que quiero expresar.
Pero no me siento muy bien con esta idea. Esto suena como una clase base hinchada con demasiada funcionalidad.
Yo uso C # como lenguaje de programación. Entonces, la herencia múltiple no es una opción aquí. Medios: Tener clases base adicionales como Fisherman : Farmer, Attacker
no funcionará.
fuente
Respuestas:
La composición y la herencia de interfaz son las alternativas habituales a la herencia múltiple clásica.
Todo lo que describió anteriormente que comienza con la palabra "can" es una capacidad que se puede representar con una interfaz, como en
ICanBuild
, oICanFarm
. Puede heredar tantas de esas interfaces como crea que necesita.Puede pasar objetos de construcción y agricultura "genéricos" a través del constructor de su clase. Ahí es donde entra la composición.
fuente
ICanBuild
. Que también tenga herramientas para construir es una preocupación secundaria en la jerarquía de objetos.Como otros carteles han mencionado, una arquitectura de componentes podría ser la solución a este problema.
En este caso, extienda la función de actualización para implementar cualquier funcionalidad que deba tener el NPC.
Iterar un contenedor de componentes y actualizar cada componente permite aplicar la funcionalidad específica de cada componente.
Como se desea cada tipo de objeto, puede usar alguna forma del patrón de fábrica para construir los tipos individuales que desea.
Siempre me he encontrado con problemas a medida que los componentes se vuelven cada vez más complejos. Mantener baja la complejidad de los componentes (una responsabilidad) puede ayudar a aliviar ese problema.
fuente
Si define interfaces como
ICanBuild
entonces, su sistema de juego tiene que inspeccionar cada NPC por tipo, lo que generalmente está mal visto en OOP. Por ejemplo:if (npc is ICanBuild)
.Estás mejor con:
Entonces:
... o, por supuesto, podría usar una serie de arquitecturas diferentes, como algún tipo de lenguaje específico de dominio en forma de una interfaz fluida para definir diferentes tipos de NPC, etc., donde construye tipos de NPC combinando diferentes comportamientos:
El constructor de NPC podría implementar un
DefaultWalkBehavior
que podría ser anulado en el caso de un NPC que vuela pero no puede caminar, etc.fuente
if(npc is ICanBuild)
yif(npc.CanBuild)
. Incluso cuando preferiría elnpc.CanBuild
camino de mi actitud actual.Pondría todas las habilidades en clases separadas que heredan de Habilidad. Luego, en la clase de tipo de unidad, tenga una lista de habilidades y otras cosas como ataque, defensa, salud máxima, etc. También tenga una clase de unidad que tenga salud actual, ubicación, etc. y que tenga el tipo de unidad como variable miembro.
Defina todos los tipos de unidades en un archivo de configuración o una base de datos, en lugar de codificarlo.
Luego, el diseñador de niveles puede ajustar fácilmente las habilidades y estadísticas de los tipos de unidades sin volver a compilar el juego, y también las personas pueden escribir modificaciones para el juego.
fuente