Quais são alguns padrões de design de programação que são úteis no desenvolvimento de jogos? [fechadas]

129

Eu tenho alguns livros sobre Design Patterns e li alguns artigos, mas não consigo descobrir intuitivamente quais padrões de design de programação seriam úteis no desenvolvimento de jogos.

Por exemplo, eu tenho um livro chamado ActionScript 3 com Design Patterns que detalha vários padrões de design, como Model View Controller, Singleton, Factory, Command, etc.

Como alguém novo nisso, não consigo descobrir qual deles seria útil ou, de fato, se algum desses são os padrões de design que eu deveria aprender e tentar usar. Talvez existam outros padrões de design mais específicos da programação de jogos que eu nem conheço?

Se você tem experiência em usar um determinado padrão de design no desenvolvimento de jogos, eu adoraria ouvi-lo. Raciocinar sobre o motivo pelo qual foi usado, amostras de código ou recursos online também seria muito útil se você os tiver. No momento, estou mais interessado nas implementações do ActionScript 3 e C ++, mas definitivamente posso me beneficiar da experiência e exemplos de qualquer linguagem.

Obrigado!

jcurrie33
fonte
"Talvez existam outros padrões de design mais específicos da programação de jogos que eu nem conheço?" - não, esses padrões são genéricos e se aplicam mais à extensão dos recursos do idioma que você está usando. Eles não têm nada a ver com o assunto do seu aplicativo.
Kylotan
3
@Kylotan Parece do meu ponto de vista limitado que, como cada padrão de design visa solucionar um problema específico de maneira eficaz, por natureza, alguns padrões de design seriam mais úteis do que outros, devido a um conjunto de problemas específico, ou seja, neste caso, esses problemas são únicos no desenvolvimento de jogos. Certamente, existem algumas diretrizes ou, com base na sua experiência, padrões de design específicos que você se utiliza com mais frequência do que outros?
Jcurrie33 29/09/10
Antes que alguém saia e aprenda 1000 padrões de design diferentes, leia isto e isto
BlueRaja - Danny Pflughoeft
@ O link BlueRaja-DannyPflughoeft Secon é inválido. Você pode reenviá-lo
Emadpres

Respostas:

163

Agora, para uma resposta menos irreverente, com algumas sugestões. Não as tome como recomendações de implementação, mas como exemplos de uso possível.

  • Construtor: configure a entidade baseada em componente, um componente por vez, com base em dados
  • Método de fábrica: crie NPCs ou widgets da GUI com base em uma sequência de leitura de um arquivo
  • Protótipo: armazene um caractere 'Elf' genérico com propriedades iniciais e crie instâncias Elf clonando-o.
  • Singleton: este espaço foi deliberadamente deixado em branco.
  • Adaptador: incorpore uma biblioteca de terceiros opcional, envolvendo-a em uma camada semelhante ao seu código existente. Muito útil com DLLs.
  • Composto: faça um gráfico de cena de objetos renderizáveis ​​ou faça uma GUI de uma árvore de Widgets
  • Fachada: simplifique bibliotecas complexas de terceiros, fornecendo uma interface mais simples para facilitar sua vida mais tarde.
  • Flyweight: armazene os aspectos compartilhados de um NPC (por exemplo, modelos, texturas, animações) separadamente dos aspectos individuais (por exemplo, posição, saúde) de maneira quase transparente
  • Proxy: Crie classes pequenas em um cliente que representem classes maiores e mais complexas em um servidor e encaminhe solicitações pela rede.
  • Cadeia de responsabilidade: manipule a entrada como uma cadeia de manipuladores, por exemplo. teclas globais (por exemplo, para capturas de tela), depois a GUI (por exemplo, no caso de uma caixa de texto estar focada ou um menu aparecer), depois o jogo (por exemplo, para mover um personagem)
  • Comando: encapsula a funcionalidade do jogo como comandos que podem ser digitados em um console, armazenados e reproduzidos ou mesmo com script para ajudar a testar o jogo
  • Mediador: implemente entidades de jogo como uma pequena classe de mediador que opera em diferentes componentes (por exemplo, leitura do componente de integridade para passar os dados para o componente de IA)
  • Observador: faça com que a representação renderizável de um personagem ouça eventos da representação lógica, para alterar a apresentação visual quando necessário, sem que a lógica do jogo precise saber algo sobre o código de renderização
  • Estado: armazene o NPC AI como um dos vários estados, por exemplo. Atacando, Vagando, Fugindo. Cada um pode ter seu próprio método update () e quaisquer outros dados necessários (por exemplo, armazenar de qual personagem está atacando ou fugindo, a área em que está vagando etc.)
  • Estratégia: alterne entre diferentes heurísticas para sua pesquisa A *, dependendo do tipo de terreno em que você está, ou talvez até mesmo use a mesma estrutura A * para fazer buscas de caminhos e um planejamento mais genérico
  • Método de modelo: configure uma rotina genérica de 'combate', com várias funções de gancho para lidar com cada etapa, por exemplo. diminuir munição, calcular chance de acerto, resolver acerto ou erro, calcular dano e cada tipo de habilidade de ataque implementará os métodos de maneira específica

Alguns padrões ficaram de fora devido à falta de inspiração.

Kylotan
fonte
Uma discussão muito esclarecedora sobre singletons podem ser encontrados aqui: misko.hevery.com/2008/08/25/root-cause-of-singletons
Andrew Wang
+1 para o padrão de estratégia. Eu usei para o propósito exato indicado acima (conectando diferentes heurísticas A *).
Mike Strobel
1
obrigado por esta resposta, os soar mais como padrão de design do que o "singleton" usual que estou ouvindo em todos os lugares ...
jokoon
Ótima lista de exemplos. Apesar do abuso crônico do padrão singleton (estado global disfarçado), há usos legítimos: Quando representa um recurso do qual você realmente só tem (ou deseja) um. Pode ser algo como empacotar hardware (por exemplo, teclado / mouse) ou empacotar uma biblioteca que não é reentrada (isso acontece, e nem todos os idiomas têm palavras-chave mágicas de sincronização).
charstar
11
Eu ainda não usaria singletons para recursos de hardware - itens que você acha que só terá 1 tendem a se multiplicar mais tarde, assim como as placas de vídeo e os monitores fizeram com o passar dos anos. Da mesma forma, em algumas APIs, você precisa ler 2 joysticks para entender 1 gamepad. Então, eu diria que, se você precisar apenas de algo, instancie um único, não imponha restrições arbitrárias que provavelmente não são necessárias.
Kylotan
59

Escrevi um livro exatamente sobre esse tópico: Padrões de programação de jogos . Os capítulos que estão lá podem ser úteis para você.

maravilhoso
fonte
2
+1 Eu esperava que alguém tivesse se vinculado a isso e vejo que o autor tem! A descrição do padrão do componente foi bastante útil, e eu gosto que você tente usar exemplos de código completos para demonstrar.
CodexArcanum 28/10/10
2
Sim - lembro-me de ler seu link há alguns anos. Você deve terminar esses artigos!
Onedayitwillmake
2
Agora o livro está terminado :)
dusan
1
Um recurso incrível que me ajudou a traduzir meus conhecimentos de programação existentes em programação para jogos. Obrigado por escrever!
Essa explicação dos padrões de programação de jogos realmente me ajudou a entender os padrões de design de uma maneira que nenhum livro de padrões de design de software realmente fez! Isso é em parte o poder do desenvolvimento de jogos (exemplos concretos em uma linguagem que me fala e me permite melhorar meu desenvolvimento em geral), mas em uma parte maior porque a escrita é excelente.
Kzqai
19

Uma coisa que Brandon Eich teve o bom senso de mencionar em Coders at Work é que os padrões são hacks e soluções alternativas: [Padrões] mostram algum tipo de defeito no idioma. Esses padrões não são livres. Não há almoço grátis. Portanto, devemos procurar a evolução na linguagem que adiciona os bits certos.

Como programadores de jogos, e não como designers de compiladores, raramente temos a opção de evoluir as linguagens que usamos, mas podemos aprender a evoluir nosso próprio estilo para melhor atender nossa linguagem e requisitos. Os padrões são parte disso, mas não usar padrões é outra parte, especialmente porque, como Brandon diz, os padrões raramente ficam sem um desempenho notável ou um custo notável de agilidade na memória ou no código. O MVC simplesmente não é um ótimo padrão para muitas coisas nos jogos. Singleton é uma solução alternativa para as regras de inicialização estática do C ++, e você provavelmente não deveria fazê-las. O Factory simplifica a criação complicada de objetos - talvez seus objetos sejam mais simples para começar. Os padrões populares são ferramentas para recorrer quando precisamos deles para gerenciar algo complexo, não ferramentas que devemos usar para criar algo complexo no início.

Um bom código (do jogo) pode usar padrões ou não. Se ele usa padrões, tudo bem - eles são uma ótima ferramenta de comunicação para explicar a estrutura de código para outros programadores em um nível alto e independente de linguagem. Se você acha que o código é melhor sem usar um padrão, não se importe com isso - provavelmente é.

user744
fonte
4
Sim, uma das coisas deixadas claras no livro original (mas muitas vezes esquecido) é que, se ele fosse escrito para C e não para C ++ / Smalltalk, eles poderiam ter incluído um padrão de "Herança" e, do mesmo modo, alguns idiomas pode conter alguns dos padrões do GoF já incorporados.
Kylotan
13
A outra coisa frequentemente negligenciada no livro original (o livro original de Alexander, não o GoF) foi que os padrões são uma ferramenta de comunicação , não de implementação . Eles permitem que os designers se comuniquem sobre a implementação em um nível superior e são identificados porque são recorrentes, não necessariamente porque devem ser usados ​​quando possível.
1
No entanto, apenas ter a terminologia pode ajudá-lo a raciocinar sobre o problema e a reconhecer quando essa abordagem é uma boa solução. Os melhores padrões foram tipicamente refinados ao longo do tempo por trabalhadores qualificados e experientes, e trabalhadores menos qualificados não descobririam os mesmos padrões sem esses exemplos codificados.
Kylotan
Concordo que ter a terminologia é excelente e parte da definição de um padrão é que é uma boa solução recorrente para algum problema. Infelizmente, os trabalhadores menos qualificados tendem a encontrar principalmente Singleton e aplicá-lo a todos os problemas, mesmo quando ainda não há um problema.
Obrigado por esta resposta; Sinto-me aliviado ao ler que o padrão de design é criado para resolver problemas criados pelo design do software. Penso que a estrutura de todo um grande software deve ser pensada do começo ao fim antes de realmente começar a codificar qualquer coisa. Você nem sempre pode implementar funcionalidades uma vez de cada vez; em algum momento, é necessário pensar em cada recurso em particular e verificar se ele não interfere na estrutura global do software ou apenas interfere na maneira como o software é suposto. comporte-se. Dividindo tarefas para vários programadores podem em algum momento criar contradições ...
jokoon
7

Obviamente, como outros já disseram, todos os padrões são úteis nas circunstâncias certas, e parte de aprender a usá-los é aprender quando usá-los. No entanto, o excelente livro Core Techniques and Algorithms in Game Programming, de Daniel Sanchez-Crespo Dalmau, lista seis padrões de programação e seis padrões de usabilidade, especialmente úteis na programação de jogos.

Programação:

  • Singleton: Eu não odeio esse como muitas pessoas fazem; pode ser usado para coisas como o single-player player ou o leitor de teclado.
  • Fábrica: permite criar e destruir objetos com eficiência.
  • Estratégia: permite alterar as estratégias de IA de maneira elegante.
  • Índice espacial: ajuda a executar consultas em conjuntos de dados espaciais.
  • Composto: configura uma hierarquia útil de objetos.
  • Flyweight: libera memória, gerando coisas como inimigos idênticos.

Usabilidade:

  • Escudo: Protege da ativação acidental de ações dramáticas.
  • Estado: dicas visuais do mundo / status da interface do usuário.
  • Cancelamento automático do modo: faz com que o jogo funcione de forma mais intuitiva.
  • Magnetismo: Autoaiming e fácil seleção de unidades.
  • Foco: Eliminando elementos de interface do usuário que distraem.
  • Progresso: universalmente útil.

O livro, é claro, entra em mais detalhes sobre cada um deles.

Gregory Avery-Weir
fonte
Obrigado pela contribuição! Eu não conhecia esse livro, mas analisarei agora como resultado de sua postagem. Obrigado novamente!
Jcurrie33
2
Singleton para o leitor de teclado é exatamente a situação em que tenho que perguntar - você não pode realmente torná-lo um ponteiro global definido no início de sua função principal? Você já instanciou acidentalmente dois leitores de teclado?
Por favor, odeie o singleton. Faz duas coisas mal. Acesso global e aridade. Muitas vezes, os desenvolvedores pensam no acesso global == singleton. Existem muito poucos problemas que precisam de um singleton verdadeiro e, possivelmente, mais alguns que são mais elegantes quando resolvidos com um singleton.
deft_code 17/10/10
7

Os sistemas de entidades são um bom tipo de padrão. Não é exatamente um padrão de design, uma vez que não é estritamente OOP. No entanto, você pode misturá-lo com OOP.

Alguns bons links (comece da parte superior para introdução):

Wernight
fonte
3
"Não é exatamente um padrão de design, pois não é estritamente [sic] OOP". Os padrões de design não têm nada a ver com OOP; se alguma coisa, OOP em si é um padrão de design. Os padrões de design aparecem não apenas fora do OOP, mas fora inteiramente do desenvolvimento de software.
OOP design patternsNormalmente, existem os que mostram relacionamentos e interações entre classes / objetos. E existem muitos outros padrões de design. OOP é um conjunto de conceitos, não um padrão realmente. Design patterné um conceito também.
Topright
6
Em vez de falar sobre semântica, você não deveria avaliar a utilidade da resposta que dei?
Wernight 4/10/10
6

Todos eles. Exceto Singleton. [/irreverência]

Kylotan
fonte
Você poderia nomear um ou dois padrões de design que você usou com frequência no desenvolvimento de jogos e por qual motivo? Como iniciante no que diz respeito aos padrões de design, "todos eles" não é uma resposta particularmente útil. Obrigado por responder, no entanto.
precisa saber é o seguinte
5
Perguntando "que padrões você usou?" é como perguntar "que nomes de variáveis ​​você usou?" Tudo se resume ao estilo pessoal, aos requisitos e ao domínio. Em algum momento, você provavelmente usará qualquer padrão que já tenha sido nomeado. Você provavelmente usará muitas outras que não foram nomeadas e talvez até invente algumas novas.
@ jcurrie33: desculpe, eu simplesmente não pude resistir a ter uma escavação em singletons primeiro. ;)
Kylotan
6

Não é realmente sobre padrões, mas sobre princípios básicos por trás deles. Em "Padrões de Design: Elementos de Software Orientado a Objetos Reutilizáveis" (1995) , a turma de quatro (Gamma, Erich; Richard Helm, Ralph Johnson e John Vlissides) recomenda apenas dois princípios para o design orientado a objetos: (1) programa para uma interface e não para uma implementação e (2) favorecem a composição do objeto sobre a herança de classe.

Esses 2 princípios são muito úteis em muitas tarefas de desenvolvimento de jogos. Por exemplo, muitos programadores de jogos usaram uma hierarquia profunda de classes para representar entidades de jogos. Há outra abordagem baseada na composição - objetos de jogo baseados em componentes. Artigo sobre essa abordagem. Ainda mais links . É um exemplo de padrão do Decorator .

direita
fonte
Os componentes usados ​​no design de jogos são mais como um padrão de estratégia com estado - que é naturalmente expresso como fechamentos fora do C / C ++ / Java / C # e como objetos componentes dentro deles. O padrão do decorador é mais como um proxy; sua propriedade e fluxo de dados são opostos aos que normalmente queremos dizer quando falamos de sistemas de componentes em jogos.
Os componentes também precisam conversar entre si, trazendo padrões como Mediador, Observador e Compositor. "Jogo baseado em componentes" é um padrão de design composto por si só.
CodexArcanum 28/10/10
@CodexArcanum, Observer, definitivamente, mas nem sempre Mediador (a Cadeia de Responsabilidade pode ser usada). É Composer apenas se GameObject (composto por GameObjectComponent) for o próprio GameObjectComponent (não é necessário).
Topright
6

O padrão de modelo curiosamente recorrente pode ser realmente útil para evitar métodos virtuais e a penalidade de desempenho que pode advir das chamadas de função virtual.

Esse pode ser o padrão apropriado quando você realmente não precisa ter um contêiner do tipo de classe base que tenha a interface que você procura, mas você gostaria de ter comportamentos e interfaces com nomes semelhantes.

Por exemplo, você pode usar isso ao compilar classes para várias plataformas ou mecanismos (dx vs. opengl) em que a variação do tipo é conhecida no momento da compilação.

Rick
fonte
Eu sempre odiei que a camada de abstração do sistema operacional fosse virtual. Não é como se você precisasse de duas camadas de abtração de sistema operacional. Muito melhor usar o CRTP.
Deft_code 17/10/10
Talvez eu tenha apenas idade, mas eu nem usaria CRTP para DX / OpenGL ou interfaces de plataforma. É muito lento para compilar - eu usaria apenas typedefs. O CRTP é bom quando você deseja compartilhar interfaces e implementações entre classes, mas não possui outra relação, não quando deseja apenas escolher uma estrutura ou outra.
4

Um padrão de design que eu desenvolvi ao longo de muitos anos, e que foi espetacularmente útil para mim, é algo que eu me refiro como "conjuntos de definições intermediadas"; como resumi-lo em termos do GOF parece controverso, mas essa pergunta que escrevi sobre ele no StackOverflow entra em alguns detalhes.

O conceito principal é que algumas propriedades de um modelo, como as espécies de uma criatura, sejam configuradas para que cada valor possível para a propriedade tenha um objeto de definição correspondente - um único objeto compartilhado por valor - que especifique seu comportamento, e eles são acessados ​​através de um intermediário central (que, em termos de GOF, pode ser um registro, uma fábrica ou ambos). No meu uso, eles também são geralmente acessados ​​por meio de chaves escalares, para facilitar a ligação fraca para fins de morfismo em tempo de execução.

caos
fonte
Não vejo como isso é um singleton e, ao discutir o padrão flyweight, a palavra "registro" é redundante. Isso é apenas peso mosca.
Meu entendimento do segmento SO foi que as pessoas identificaram Singleton como parte dele por causa das definições sendo definidas como classes. No que diz respeito ao Registro, não vejo como ele pode ser redundante quando pode ser substituído ou combinado com o Factory.
caos
-1, na medida em que os padrões se comunicam rapidamente, essa é provavelmente a maior falha que eu já vi. Eu realmente não posso levar essa descrição a sério.
Jesus, perdoe-me por não ser suficientemente cortador de biscoitos para você. Você também vai votar na resposta "Sistemas de entidades" porque ela não é resumida instantaneamente nos termos do GOF?
caos
1
Alguma quantidade de "cortador de biscoitos", ou pelo menos clareza semântica, é exatamente o que os padrões devem ser para serem úteis. Termos como "flyweight" e "singleton", como são comumente entendidos, são mutuamente exclusivos. A primeira é sobre o compartilhamento automático de dados entre várias instâncias; a segunda é sobre ter exatamente uma instância. Não estou dizendo que sua escolha de design é inútil ou até ruim, mas juntar nomes de padrões "suficientemente próximos" apenas confunde mais todos. (Por favor, não tome downvotes pessoalmente, especialmente em CW.)