2010-07-24 19 views
6

Estoy escribiendo un proyecto de juego como un hobby, y estoy buscando algún consejo arquitectónico sobre la mejor manera de organizar mis objetos de juego y sus diversas animaciones.Patrón de arquitectura de animación

Por ejemplo, tengo una clase llamada Wizard, y una clase llamada Dragon. Un asistente tiene, al menos, 10 animaciones diferentes específicas asociadas a él, dependiendo de su estado, y el mismo para Dragon.

Así que mi pregunta es la siguiente: Hay un patrón estándar para organizar este tipo de objetos para que sea eficiente y fácil de extender (es decir, debe ser fácil de añadir nuevos animaciones y nuevos objetos)?

Tengo varias ideas sobre cómo avanzar en esto, pero I no quiero equivocarme ya que es una parte tan importante de la arquitectura del juego. Parece fácil hacer que esto funcione para un juego pequeño , pero tengo miedo de la complejidad inmanejable ya que se vuelve más grande el .

+0

Roba ideas de juegos de código abierto existentes. –

+0

std :: map - para almacenamiento interno de estado a animación, y cualquier formato abierto para almacenamiento externo. – W55tKQbuRu28Q4xv

Respuesta

1

Sugiero tener una interfaz como "Carácter", que define lo que todas estas entidades deberían ser capaces de hacer. Entonces tus clases Dragon y Wizard son solo implementaciones.

Otra ruta es tener una clase Base desde la cual se extiende desde y utilizarla para controlar la "expansión jerárquica" asociada a proyectos grandes, dibujando una jerarquía de objetos e identificando clases base extendidas.

0

No, no hay absolutamente ningún patrón estándar.

Mi consejo es evitar la trampa del diseño OO novato de tratar de encontrar una única interfaz común de "clase base" para todo. Tu Dragón es muy diferente de tu Mago, y no hay nada que ganar al intentar fusionar las dos interfaces, excepto las extrañas abstracciones de código. Recuerde, la herencia no es una herramienta para la reutilización de código.

El enfoque más simple es que cada objeto mantenga su propio estado interno (como ya se ha descrito), y sea capaz de dibujar ese estado. Aquí es donde una declaración de cambio de escuela anterior puede ser más claro que usar polimorfismo para el mismo efecto. Ejemplo:

class Dragon { 
enum State { asleep, flying, breathing_fire }; 
public: 
void draw() { /* old-school switch */ 
    switch (cur_state){ 
    case asleep: draw_asleep(); 
    case flying: draw_flying(); 
    case breathing_fire: draw_breathing_fire(); 
    } 
    } 
private: 
    void draw_asleep(); 
    void draw_flying(); 
    void draw_breathing_fire(); 
}; 

experimentados desarrolladores de C++ se jadear en el código anterior (como debe ser), debido a que la sentencia switch es casi exactamente lo que una llamada al método polimórfico lograría - envío en tiempo de ejecución. (O incluso más críptico: una tabla de direcciones de métodos.) Mi opinión personal es que para este tipo específico de clase, es decir, una única interfaz pública que encapsula una máquina de estados, la declaración de cambio es más clara y fácil de mantener porque hace que la máquina de estados saltar explícitamente Creo que también está claro que reconozco que esto es generalmente mal diseño C++.

La fricción de este diseño es causada por la línea divisoria entre la máquina de estado y la interfaz pública única. Un dragón dormido claramente no es lo mismo que un dragón volador. De hecho, no tendrá casi nada en común. Pero el diseño de nivel superior dice que los dos son el MISMO dragón. ¡Que desastre! ¿Creas diferentes objetos de Dragón para cada estado? No, porque eso expondría el concepto de estado a la persona que llama. ¿Creas diferentes objetos auxiliares internos para cada estado y los envías a esos? Posiblemente, pero se vuelve desordenado rápidamente. El enfoque anterior es un compromiso entre los dos.Piense en la declaración del interruptor como aislando la fealdad. La interfaz pública está limpia, al igual que la interfaz privada. Solo la declaración del interruptor contiene el desastre sucio. Considere este enfoque, y también considere otras sugerencias también.

Por último, señalar a su asistente y su dragón, una plantilla simple envoltorio o funtor un botón:

struct Draw { 
    template <class S> 
    void operator()(S& s) { s.draw(); } 
}; 

El punto es que usted no tiene que combinar dos clases diferentes simplemente porque ambos apoyan la misma operación lógica.

Cuestiones relacionadas