Estou lendo a Game Coding Complete e o autor recomenda a comunicação orientada a eventos entre os objetos e módulos do jogo.
Basicamente, todos os atores vivos do jogo devem se comunicar com os módulos principais (Física, IA, Lógica do jogo, Visualização do jogo etc.) por meio de um sistema interno de mensagens de eventos. Isso significa ter que projetar um gerenciador de eventos eficiente. Um sistema mal projetado consome ciclos de CPU, afetando especialmente as plataformas móveis.
Essa é uma abordagem comprovada e recomendada? Como devo decidir se devo usá-lo?
architecture
software-engineering
events
Bunkai.Satori
fonte
fonte
libuv
surgiu recentemente como uma biblioteca de eventos de sucesso. (É em C. Node.js é o seu mais famoso caso de uso.)Respostas:
Esta é uma expansão do meu comentário para uma resposta completa, como sugerido.
Sim , pura e simples. A comunicação precisa acontecer e, enquanto há situações em que 'já chegamos?' A pesquisa de tipo é necessária, solicitando que as coisas verifiquem se elas deveriam estar fazendo outra coisa e geralmente perde tempo. Em vez disso, você pode fazê-los reagir às coisas que lhes dizem para fazer. Além disso, um caminho de comunicação bem definido entre objetos / sistemas / módulos aumenta significativamente as configurações paralelas.
Forneci uma visão geral de alto nível de um sistema de mensagens de eventos no Stack Overflow . Eu usei da escola em títulos de jogos profissionais e agora produtos que não são de jogos, adaptados ao caso de uso todas as vezes, é claro.
EDIT : Para abordar uma pergunta de comentário sobre como você sabe quais objetos devem receber a mensagem : Os próprios objetos devem
Request
ser notificados sobre os eventos. SeuEventMessagingSystem
(EMS) precisará de umaRegister(int iEventId, IEventMessagingSystem * pOjbect, (EMSCallback)fpMethodToUseForACallback)
correspondência e de uma correspondênciaUnregister
(criando uma entrada exclusiva para umiEventId
ponteiro fora do objeto e retorno de chamada). Dessa forma, quando um objeto deseja saber sobre uma mensagem, pode fazê-loRegister()
com o sistema. Quando não precisar mais conhecer os eventos, poderáUnregister()
. Claramente, você deseja um conjunto desses objetos de registro de retorno de chamada e uma maneira eficaz de adicioná-los / removê-los das listas. (Normalmente, usei matrizes de auto-ordenação; uma maneira elegante de dizer que elas rastreiam suas próprias alocações entre uma pilha de objetos não utilizados e matrizes que mudam de tamanho quando necessário).Edição : Para um jogo completamente funcional com um loop de atualização e um sistema de mensagens de eventos, você pode conferir um projeto antigo da minha escola . A postagem Stack Overflow vinculada acima também se refere a ela.
fonte
Minha opinião é que você deve começar a fazer seu jogo e implementar o que lhe agrada. Ao fazer isso, você se encontrará usando o MVC em alguns lugares, mas não em outros; eventos em alguns lugares, mas não em outros; componentes em alguns lugares, mas herança em outros; design limpo em alguns lugares, e design sujo em outros.
E tudo bem, porque quando terminar, você realmente terá um jogo, e um jogo é muito mais legal do que um sistema de transmissão de mensagens.
fonte
Uma pergunta melhor é: que alternativas existem? Em um sistema tão complexo com módulos adequadamente divididos para física, IA, etc., de que outra forma você pode orquestrar esses sistemas?
A passagem de mensagens parece ser a "melhor" solução para esse problema. Não consigo pensar em alternativas agora. Mas existem muitos exemplos de mensagens transmitidas na prática. De fato, os sistemas operacionais usam a passagem de mensagens para várias de suas funções. Da Wikipedia :
(Comunicação entre processos é a comunicação entre processos (por exemplo, executando instâncias de programas) dentro do ambiente do sistema operacional)
Então, se é bom o suficiente para um sistema operacional, provavelmente é bom o suficiente para um jogo, certo? Também existem outros benefícios, mas deixarei o artigo da Wikipedia sobre a passagem de mensagens fazer a explicação.
Também fiz uma pergunta no Stack Overflow, "Estruturas de dados para passagem de mensagens dentro de um programa?" , que você pode querer ler novamente.
fonte
As mensagens geralmente funcionam bem quando:
Quanto mais suas necessidades corresponderem a essa lista, melhores serão as mensagens adequadas. Em um nível muito geral, eles são muito bons. Eles fazem um bom trabalho em não desperdiçar ciclos de CPU apenas para fazer nada diferente de pesquisas ou outras soluções mais globais. Eles são fantásticos ao desacoplar partes de uma base de código, o que é sempre útil.
fonte
Ótimas respostas até agora de James e Ricket, eu apenas respondo para adicionar uma nota de cautela. A comunicação de passagem de mensagem / evento é certamente uma ferramenta importante no arsenal do desenvolvedor, mas pode ser facilmente usada em excesso. Quando você tem um martelo, tudo se parece com um prego e assim por diante.
Você absolutamente, 100%, deve pensar no fluxo de dados em torno de seu título e estar totalmente ciente de como as informações estão passando de um subsistema para outro. Em alguns casos, a passagem de mensagens é claramente a melhor; em outros, pode ser mais apropriado que um subsistema opere sobre uma lista de objetos compartilhados, permitindo que outros subsistemas também operem na mesma lista compartilhada; e muitos outros métodos além disso.
Em todos os momentos, você deve estar ciente de quais subsistemas precisam acessar a quais dados e quando eles precisam acessá-los. Isso afeta sua capacidade de paralelizar e otimizar, além de ajudá-lo a evitar problemas mais insidiosos quando diferentes partes do seu motor se tornam muito entrelaçadas. Você precisa pensar em minimizar a cópia desnecessária de dados e como o layout dos dados afeta o uso do cache. Tudo isso o guiará para a melhor solução em cada caso.
Dito isto, praticamente todos os jogos em que trabalhei tiveram um sólido sistema de notificação de eventos / passagem de mensagens assíncronas. Ele permite que você escreva códigos de manutenção eficientes e sucintos, mesmo diante de necessidades de projeto complexas e que mudam rapidamente.
fonte
Bem, eu sei que este post é bastante antigo, mas não pude resistir.
Recentemente, construí um mecanismo de jogo. Ele usa bibliotecas de partes 3d para renderização e física, mas eu escrevi a parte principal, que define e processa as entidades e a lógica do jogo.
O mecanismo certamente segue uma abordagem tradicional. Existe um loop de atualização principal que chama a função de atualização para todas as entidades. As colisões são relatadas diretamente por retorno de chamada nas entidades. As comunicações entre entidades são feitas usando ponteiros inteligentes trocados entre entidades.
Existe um sistema de mensagens primitivo, que processa apenas um pequeno grupo de entidades para criar mensagens. É preferível que essas mensagens sejam processadas no final de uma interação do jogo (por exemplo, criação ou destruição de uma entidade) porque podem interferir na lista de atualizações. Portanto, no final de cada ciclo do jogo, uma pequena lista de mensagens é consumida.
Apesar do sistema de mensagens primitivo, eu diria que o sistema é amplamente "baseado em loop de atualização".
Bem. Depois de usar este sistema, acho que é muito simples, rápido e bem organizado. A lógica do jogo é visível e independente dentro das entidades, não dinâmica como uma fila de mensagens. Eu realmente não faria isso orientado a eventos, porque, na minha opinião, os sistemas de eventos introduzem complexidade desnecessária à lógica do jogo e tornam o código do jogo muito difícil de entender e depurar.
Mas também acho que um sistema "baseado em loop de atualização" puro como o meu também tem alguns problemas.
Por exemplo, em alguns momentos, uma entidade pode estar em um estado "não faça nada", pode estar esperando o jogador se aproximar ou algo mais. Na maioria dos casos, a entidade gasta o tempo do processador por nada e é melhor desligá-la e ativá-la quando um determinado evento acontece.
Então, no meu próximo mecanismo de jogo, adotarei uma abordagem diferente. As entidades se registrarão para operações do mecanismo, como atualização, desenho, detecção de colisão e assim por diante. Cada um desses eventos terá listas separadas de interfaces de entidade para as entidades reais.
fonte
Sim. É uma maneira muito eficiente de os sistemas de jogos se comunicarem. Os eventos ajudam a dissociar muitos sistemas e tornam possível compilar as coisas separadamente, sem conhecer a existência um do outro. Isso significa que suas aulas podem ser prototipadas com mais facilidade e os tempos de compilação são mais rápidos. Mais importante, você acaba com um design de código simples em vez de uma bagunça de dependência.
Outro grande benefício dos eventos é que eles são facilmente transmitidos por uma rede ou outro canal de texto. Você pode gravá-los para reprodução posterior. As possibilidades são infinitas.
Outro benefício: Você pode ter vários subsistemas ouvindo o mesmo evento. Por exemplo, todas as suas visualizações remotas (players) podem se inscrever automaticamente no evento de criação da entidade e gerar entidades em cada cliente com pouco trabalho da sua parte. Imagine quanto mais trabalho seria se você não usasse eventos: teria que fazer
Update()
chamadas em algum lugar ou talvez chamarview->CreateEntity
da lógica do jogo (onde o conhecimento sobre a exibição e as informações necessárias não pertencem). É difícil resolver esse problema sem eventos.Com os eventos, você obtém uma solução elegante e dissociada que suporta um número infinito de objetos de tipos ilimitados que podem simplesmente se inscrever em eventos e fazer o que precisam quando algo acontece no seu jogo. É por isso que os eventos são ótimos.
Mais detalhes e uma implementação aqui .
fonte
Pelo que vi, não parece ser muito comum ter um mecanismo completamente baseado em mensagens. Obviamente, existem subsistemas que se prestam muito bem a esse sistema de mensagens, como rede, GUI e possivelmente outros. Em geral, porém, existem alguns problemas em que posso pensar:
Com a abordagem comum dos desenvolvedores de jogos de "deve ser o mais eficiente possível", esse sistema de mensagens não é tão comum.
No entanto, concordo que você deve apenas ir em frente e experimentá-lo. Certamente, existem muitas vantagens com esse sistema e o poder de computação está disponível hoje em dia.
fonte