¿Cuáles son algunos patrones de diseño de programación que son útiles en el desarrollo de juegos? [cerrado]

129

Tengo algunos libros sobre Patrones de diseño, y he leído algunos artículos, pero no puedo entender intuitivamente qué patrones de diseño de programación serían útiles en el desarrollo de juegos.

Por ejemplo, tengo un libro llamado ActionScript 3 con patrones de diseño que detalla varios patrones de diseño como Model View Controller, Singleton, Factory, Command, etc.

Como alguien nuevo en esto, no puedo entender cuál de estos sería útil, o de hecho si alguno de estos son los patrones de diseño que debería aprender y tratar de usar. ¿Quizás hay otros patrones de diseño más específicos de programación de juegos que ni siquiera conozco?

Si tienes experiencia usando un cierto patrón de diseño en el desarrollo de juegos, me encantaría escucharlo. Razonar sobre por qué se usó, ejemplos de código o recursos en línea también sería muy útil si los tiene. En este momento estoy más interesado en las implementaciones de ActionScript 3 y C ++, pero definitivamente podría beneficiarme de la experiencia y los ejemplos de cualquier lenguaje.

¡Gracias!

jcurrie33
fuente
"¿Quizás hay otros patrones de diseño más específicos de programación de juegos que ni siquiera conozco?" - no, estos patrones son genéricos y se aplican más para ampliar las capacidades del lenguaje que está utilizando. No tienen nada que ver con el tema de su solicitud.
Kylotan
3
@Kylotan Parece, desde mi punto de vista limitado, que dado que cada patrón de diseño está destinado a abordar un problema particular de manera efectiva, por su naturaleza, algunos patrones de diseño serían más útiles que otros dado un conjunto de problemas específico, es decir, en este caso, esos problemas son únicos para el desarrollo del juego. ¿Seguramente hay algunas pautas, o en base a su experiencia, patrones de diseño particulares que utiliza más frecuentemente que otros?
jcurrie33
Antes de que alguien se vaya y aprenda 1000 patrones de diseño diferentes, lea esto y esto
BlueRaja - Danny Pflughoeft
@ BlueRaja-DannyPflughoeft El enlace Secon no es válido. ¿Puedes reenviarlo
Emadpres

Respuestas:

163

Ahora para una respuesta menos impertinente, con algunas sugerencias. No los tome como recomendaciones de implementación, más como ejemplos de posible uso.

  • Generador: configure la entidad basada en componentes un componente a la vez, según los datos
  • Método de fábrica: cree widgets NPC o GUI basados ​​en una cadena leída de un archivo
  • Prototipo: almacene un personaje genérico 'Elf' con propiedades iniciales y cree instancias Elf clonándolo.
  • Singleton: este espacio se dejó en blanco deliberadamente.
  • Adaptador: incorpore una biblioteca de terceros opcional envolviéndola en una capa que se parece a su código existente. Muy útil con archivos DLL.
  • Compuesto: haga un gráfico de escena de objetos renderizables, o haga una GUI de un árbol de Widgets
  • Fachada: simplifique las bibliotecas complejas de terceros al proporcionar una interfaz más simple para facilitarle la vida más adelante.
  • Flyweight: almacene los aspectos compartidos de un NPC (p. Ej., Modelos, texturas, animaciones) por separado de los aspectos individuales (p. Ej., Posición, salud) de una manera mayormente transparente
  • Proxy: cree clases pequeñas en un cliente que representen clases más grandes y complejas en un servidor, y envíe las solicitudes a través de la red.
  • Cadena de responsabilidad: manejar los aportes como una cadena de controladores, por ejemplo. teclas globales (por ejemplo, para capturas de pantalla), luego la GUI (por ejemplo, en caso de que un cuadro de texto esté enfocado o un menú esté arriba), luego el juego (por ejemplo, para mover un personaje)
  • Comando: encapsula la funcionalidad del juego como comandos que pueden escribirse en una consola, almacenarse y reproducirse, o incluso crearse una secuencia de comandos para ayudar a probar el juego.
  • Mediador: implemente las entidades del juego como una pequeña clase de mediador que opera en diferentes componentes (p. Ej., Lectura del componente de salud para pasar los datos al componente AI)
  • Observador: haga que la representación representable de un personaje escuche los eventos de la representación lógica, para cambiar la presentación visual cuando sea necesario sin que la lógica del juego necesite saber nada sobre el código de representación
  • Estado: almacene NPC AI como uno de varios estados, por ejemplo. Atacando, errante, huyendo. Cada uno puede tener su propio método update () y cualquier otro dato que necesite (por ejemplo, almacenar de qué personaje está atacando o huyendo, el área en la que está vagando, etc.)
  • Estrategia: cambie entre diferentes heurísticas para su búsqueda A *, dependiendo del tipo de terreno en el que se encuentre, o tal vez incluso para usar el mismo marco A * para hacer una búsqueda de ruta y una planificación más genérica
  • Método de plantilla: configure una rutina genérica de 'combate', con varias funciones de gancho para manejar cada paso, por ejemplo. Disminuya la munición, calcule la probabilidad de golpe, resuelva el golpe o la falla, calcule el daño y cada tipo de habilidad de ataque implementará los métodos de su propia manera específica

Algunos patrones quedaron fuera por falta de inspiración.

Kylotan
fuente
Una discusión muy esclarecedora sobre los singleton se puede encontrar aquí: misko.hevery.com/2008/08/25/root-cause-of-singletons
Andrew Wang
+1 para el patrón de estrategia. Lo he usado para el propósito exacto mencionado anteriormente (conectando diferentes heurísticas A *).
Mike Strobel
1
gracias por esta respuesta, esos suenan más como un patrón de diseño que el "singleton" habitual que estoy escuchando en todas partes ...
jokoon
Gran lista de ejemplos. A pesar del abuso crónico del patrón singleton (estado global disfrazado), existen usos legítimos: cuando representa un recurso del que en realidad solo tiene (o quiere) uno. Esto puede ser algo como envolver hardware (por ejemplo, teclado / mouse) o envolver una biblioteca que no es reentrante (sucede, y no todos los idiomas tienen palabras clave de sincronización mágicas).
Charstar
11
Todavía no usaría singletons para recursos de hardware: elementos que cree que solo tendrá 1 de ellos tienden a multiplicarse más tarde, al igual que las tarjetas de video y los monitores a medida que pasaban los años. Del mismo modo, en algunas API debe leer 2 joysticks para comprender 1 gamepad. Entonces, diría que si solo necesita uno de algo, solo cree una instancia, no imponga restricciones arbitrarias que probablemente no sean necesarias.
Kylotan
59

Escribí un libro sobre exactamente ese tema: Patrones de programación de juegos . Los capítulos que están allí pueden ser útiles para usted.

munificente
fuente
2
¡+1 esperaba que alguien se hubiera vinculado a eso y veo que el autor sí! La descripción del patrón del componente allí fue bastante útil, y me gusta que intentes usar ejemplos de código completos para demostrar.
CodexArcanum
2
Sí, recuerdo haber leído tu enlace hace unos años. ¡Deberías terminar esos artículos!
onedayitwillmake
2
Ahora el libro está terminado :)
dusan
1
Un recurso increíble que me ayudó a traducir mis conocimientos de programación existentes en programación para juegos. Gracias por escribirlo!
¡Esta explicación de los patrones de programación de juegos realmente me ayudó a comprender los patrones de diseño de una manera que ningún libro de patrones de diseño de software realmente entendió! Esto es en parte el poder del desarrollo del juego (ejemplos concretos en un lenguaje que me habla y me permite mejorar mi desarrollo en general), pero en gran parte porque la escritura es excelente.
Kzqai
19

Una cosa que Brandon Eich tuvo el buen sentido de mencionar en Coders at Work es que los patrones son hacks y soluciones alternativas: [los patrones] muestran algún tipo de defecto en el lenguaje. Estos patrones no son gratuitos. No hay almuerzo gratis. Por lo tanto, deberíamos buscar la evolución en el lenguaje que agrega los bits correctos.

Como programadores de juegos en lugar de diseñadores de compiladores, rara vez tenemos la opción de desarrollar los idiomas que usamos, pero podemos aprender a desarrollar nuestro propio estilo para que se adapte mejor a nuestro idioma y requisitos. Los patrones son parte de esto, pero no usar patrones es otra parte, especialmente porque, como dice Brandon, los patrones rara vez pasan sin un rendimiento notable o un costo de memoria o agilidad de código. MVC simplemente no es un gran patrón para muchas cosas en los juegos. Singleton es una solución alternativa para las reglas de inicialización estáticas de C ++, y probablemente no debería hacerlo de todos modos. Factory simplifica la creación de objetos complicados, tal vez tus objetos deberían ser más simples para comenzar. Los patrones populares son herramientas a las que recurrir cuando los necesitamos para administrar algo complejo, no herramientas que deberíamos desear usar para construir algo complejo desde el principio.

Un buen código (de juego) puede usar patrones, o puede que no. Si usa patrones, está bien: son una excelente herramienta de comunicación para explicar la estructura del código a otros programadores en un nivel alto e independiente del lenguaje. Si crees que el código es mejor sin usar un patrón, no te rindas, probablemente lo sea.

usuario744
fuente
44
Sí, una de las cosas aclaradas en el libro original (pero a menudo se pasa por alto) es que si se escribiera para C en lugar de C ++ / Smalltalk, podrían haber incluido un patrón de "Herencia" y, por lo mismo, algunos lenguajes podría contener algunos de los patrones GoF ya incorporados.
Kylotan
13
La otra cosa a menudo pasada por alto en el libro original (el libro original original de Alexander, no GoF) fue que los patrones son una herramienta de comunicación , no de implementación . Permiten que los diseñadores se comuniquen sobre la implementación en un nivel superior, y se identifican porque son recurrentes, no necesariamente porque deben usarse cuando sea posible.
1
Sin embargo, simplemente tener la terminología puede ayudarlo a razonar sobre el problema y reconocer cuándo tal enfoque es una buena solución. Los mejores patrones generalmente han sido refinados a lo largo del tiempo por trabajadores calificados y experimentados, y los trabajadores menos calificados no descubrirían los mismos patrones por sí mismos sin estos ejemplos codificados.
Kylotan
Estoy de acuerdo en que tener la terminología es excelente, y parte de la definición de un patrón es que es una buena solución recurrente para algún problema. Desafortunadamente, los trabajadores menos calificados tienden a encontrar en su mayoría Singleton, y lo aplican a todos los problemas, incluso cuando todavía no hay un problema.
Gracias por esta respuesta; Me siento aliviado al leer que los patrones de diseño están hechos para resolver problemas creados por el diseño del software. Creo que la estructura de todo un gran software debería pensarse desde el principio hasta el final antes de comenzar a codificar cualquier cosa. No siempre puede implementar funcionalidades de una en una, a veces tiene que pensar en cada característica en particular y verificar si no afectará la estructura global del software o simplemente interfiere en la forma en que se supone que el software comportarse. Dividir tareas para varios programadores en algún momento puede crear contradicciones ...
jokoon
7

Por supuesto, como han dicho otros, todos los patrones son útiles en las circunstancias correctas, y parte de aprender a usarlos es aprender cuándo usarlos. Sin embargo, el excelente libro Core Techniques and Algorithms in Game Programming de Daniel Sanchez-Crespo Dalmau, enumera seis patrones de programación y seis patrones de usabilidad como especialmente útiles en la programación de juegos.

Programación:

  • Singleton: No odio este como lo hace mucha gente; se puede usar para cosas como el reproductor de un jugador o el lector de teclado.
  • Fábrica: le permite crear y destruir objetos de manera eficiente.
  • Estrategia: te permite cambiar las estrategias de inteligencia artificial con elegancia.
  • Índice espacial: ayuda a realizar consultas en conjuntos de datos espaciales.
  • Compuesto: configura una jerarquía de objetos útil.
  • Flyweight: Libera memoria al genérico de cosas como enemigos idénticos.

Usabilidad:

  • Escudo: protege de la activación accidental de acciones dramáticas.
  • Estado: Indicaciones visuales del mundo / estado de la IU.
  • Cancelación automática del modo: hace que el juego funcione de manera más intuitiva.
  • Magnetismo: autoajuste y fácil selección de unidades.
  • Enfoque: Eliminar elementos de IU que distraen.
  • Progreso: universalmente útil.

El libro, por supuesto, entra en más detalles sobre cada uno de estos.

Gregory Avery-Weir
fuente
¡Gracias por el aporte! No conocía ese libro, pero lo examinaré ahora como resultado de tu publicación. ¡Gracias de nuevo!
jcurrie33
2
Singleton para el lector de teclado es exactamente la situación en la que tengo que preguntar: ¿puede realmente no solo convertirlo en un puntero global establecido al principio de su función principal? ¿Alguna vez has instanciado accidentalmente dos lectores de teclado?
Por favor, odia el singleton. Hace dos cosas mal. Acceso global y aridad. A menudo, los desarrolladores piensan que el acceso global == singleton. Hay muy pocos problemas que necesiten un singleton verdadero, y posiblemente algunos más que sean más elegantes cuando se resuelvan con un singleton.
deft_code
7

Los sistemas de entidades son un buen tipo de patrón. No es exactamente un patrón de diseño, ya que no es llamativamente OOP. Sin embargo, puedes mezclarlo con OOP.

Algunos buenos enlaces (comience desde arriba para la introducción):

revs Wernight
fuente
3
"No es exactamente un patrón de diseño, ya que no es estrictamente [sic] OOP". Los patrones de diseño no tienen nada que ver con OOP; en todo caso, OOP en sí mismo es un patrón de diseño. Los patrones de diseño aparecen no solo fuera de OOP, sino completamente fuera del desarrollo de software.
Hay OOP design patternsque suelen mostrar relaciones e interacciones entre clases / objetos. Y hay muchos otros patrones de diseño. OOP es un conjunto de conceptos, no un patrón realmente. Design patternTambién es un concepto.
arriba el
66
En lugar de hablar de semántica, ¿no deberías calificar la utilidad de la respuesta que di?
Wernight
6

Todos ellos. Excepto Singleton. [/ligereza]

Kylotan
fuente
¿Podrías nombrar uno o dos patrones de diseño que hayas utilizado con frecuencia en el desarrollo de tu juego y por qué motivo? Como principiante con respecto a los patrones de diseño, "todos ellos" no es una respuesta particularmente útil. Gracias por responder, sin embargo.
jcurrie33
55
Preguntando "¿qué patrones has usado?" es como preguntar "¿qué nombres de variables has usado?" Se trata de estilo personal y requisitos y dominio. En algún momento, probablemente usará cualquier patrón que haya sido nombrado. Probablemente usará muchos más que no han sido nombrados, y tal vez incluso invente algunos nuevos.
@ jcurrie33: lo siento, no pude resistirme a cavar en singletons primero. ;)
Kylotan
6

No se trata realmente de patrones, sino de principios básicos detrás de ellos. En "Design Patterns: Elementos de software reutilizables orientada a objetos" (1995) , la banda de los cuatro (Gamma, Erich; Richard Helm, Ralph Johnson y John Vlissides) recomienda sólo dos principios para orientado a objetos de diseño: (1) programa para una interfaz y no a una implementación y (2) favorecen la composición de objetos sobre la herencia de clases.

Estos 2 principios son muy útiles en muchas tareas de desarrollo de juegos. Por ejemplo, muchos programadores de juegos han usado una jerarquía de clases profunda para representar entidades de juegos. Existe otro enfoque basado en la composición : los objetos de juego basados ​​en componentes. Artículo sobre este enfoque. Aún más enlaces . Es un ejemplo de patrón Decorador .

derecha
fuente
Los componentes utilizados en el diseño del juego se parecen más a un patrón de estrategia con estado, que se expresa naturalmente como cierres fuera de C / C ++ / Java / C #, y como objetos componentes dentro de ellos. El patrón decorador es más como un proxy; su propiedad y flujo de datos son opuestos a los que normalmente queremos decir cuando hablamos de sistemas de componentes en juegos.
Los componentes también necesitan comunicarse entre sí, trayendo patrones como Mediador, Observador y Compositor. El "juego basado en componentes" es un patrón de diseño compuesto por sí mismo.
CodexArcanum
@CodexArcanum, Observador, definitivamente, pero no siempre Mediador (en su lugar, se puede utilizar la Cadena de responsabilidad). Es Composer solo si GameObject (compuesto por GameObjectComponent) es GameObjectComponent en sí (no es necesario).
arriba
6

El patrón de plantilla curiosamente recurrente puede ser realmente útil para evitar métodos virtuales y la penalización de rendimiento que puede provenir de las llamadas a funciones virtuales.

Este puede ser el patrón apropiado cuando en realidad no necesita tener un contenedor del tipo de clase base que tenga la interfaz que busca, pero le gustaría tener comportamientos e interfaces con nombres similares.

Por ejemplo, puede usar esto al compilar clases para múltiples plataformas o motores (dx vs. opengl) donde la variación de tipo se conoce en tiempo de compilación.

Almiar
fuente
Siempre odié que la capa de abstracción del sistema operativo fuera virtual. No es como si alguna vez necesitaras dos capas de abstracción del sistema operativo. Mucho mejor usar CRTP.
deft_code
Tal vez solo soy viejo, pero ni siquiera usaría CRTP para DX / OpenGL o interfaces de plataforma. Es demasiado lento para compilar, solo usaría typedefs. CRTP es bueno cuando desea compartir interfaces e implementaciones entre clases pero no tiene otra relación, no cuando solo desea elegir una estructura u otra.
4

Un patrón de diseño que desarrollé a lo largo de muchos años, y que me ha sido espectacularmente útil, es algo a lo que me refiero como "conjuntos de definiciones de intermediación"; cómo resumirlo en términos de GOF parece ser controvertido, pero esta pregunta que escribí al respecto en StackOverflow entra en algunos detalles al respecto.

El concepto central es que alguna propiedad de un modelo, como la especie de una criatura, se configura de modo que cada valor posible para la propiedad tenga un objeto de definición correspondiente, un objeto único y compartido por valor, que especifique su comportamiento, y se accede a ellos a través de un intermediario central (que, según GOF, puede ser un Registro, una Fábrica o ambos). En mi uso, generalmente también se accede a ellos a través de teclas escalares, para facilitar el enlace débil para fines de morfismo en tiempo de ejecución.

3 revoluciones
fuente
No veo cómo esto es un singleton en absoluto y cuando discutimos el patrón de peso mosca, la palabra "registro" es redundante. Esto es solo peso mosca.
Mi comprensión del hilo SO fue que las personas identificaron a Singleton como parte de él debido a que las definiciones se configuraron como clases. En lo que respecta al registro, no veo cómo puede ser redundante cuando se puede reemplazar o combinar con Factory.
caos
-1, en la medida en que los patrones se refieren a la comunicación rápida, este es probablemente el mayor fracaso que he visto. Realmente no puedo tomar esta descripción en serio.
Jesús, perdóname por no ser lo suficientemente cortador de galletas para ti. ¿También va a rechazar la respuesta de "Sistemas de entidades" porque no se puede resumir instantáneamente en términos GOF?
caos
1
Una cierta cantidad de "cortador de galletas", o al menos claridad semántica, es exactamente lo que los patrones deben ser útiles. Términos como "peso mosca" y "singleton", como se los conoce comúnmente, son mutuamente excluyentes. El primero se trata de compartir datos automáticamente entre varias instancias; el segundo trata de tener exactamente una instancia. No digo que su elección de diseño sea inútil o incluso mala, pero agrupar nombres de patrones "lo suficientemente cercanos" simplemente confunde a todos. (Por favor, no tome votos negativos personalmente, especialmente en CW.)