o design tradicional do jogo , como eu o conheço, usa polimorfismo e funções virtuais para atualizar os estados dos objetos do jogo. Em outras palavras, o mesmo conjunto de funções virtuais é chamado em intervalos regulares (por exemplo, por quadro) em todos os objetos do jogo.
Recentemente, eu descobri, que há outro - sistema de mensagens orientado a eventos disponível para atualizar estados de objetos de jogo. Aqui, os objetos geralmente não são atualizados por quadro. Em vez disso, um sistema de mensagens de eventos altamente eficiente é construído e os objetos do jogo são atualizados somente após o recebimento de uma mensagem de evento válida.
A arquitetura de jogos orientada a eventos está bem descrita em: Game Coding Complete por Mike McShaffry .
Gostaria de pedir ajuda com as seguintes perguntas:
- Quais são as vantagens e desvantagens das duas abordagens?
- Onde é melhor um sobre o outro?
- O design de jogos orientado a eventos é universal e melhor em todas as áreas? Portanto, é recomendado para uso mesmo em plataformas mombile?
- Qual é mais eficiente e qual é mais difícil de desenvolver?
Para esclarecer, minha pergunta não é sobre remover o polimorfismo completamente de um design de jogo. Eu simplesmente desejo entender a diferença e me beneficiar do uso de mensagens orientadas a eventos versus chamadas regulares (por quadro) para funções virtuais para atualizar o estado do jogo.
Exemplo: Esta questão causou um pouco de controvérsia aqui, então deixe-me dar um exemplo: De acordo com o MVC, o mecanismo de jogo é dividido em três partes principais:
- Camada de Aplicação (Comunicação de Hardware e SO)
- Game Logic
- Visualização do jogo
Em um jogo de corrida, o Game View é responsável por renderizar a tela o mais rápido possível, pelo menos 30 fps. A Visualização do Jogo também escuta as informações do jogador. Agora isso acontece:
- Jogador pressiona o pedal do combustível a 80%
- O GameView cria uma mensagem "Pedal de combustível do carro 2 pressionado em 80%" e a envia para a Game Logic.
- A Game Logic recebe a mensagem, avalia, calcula a posição e o comportamento do carro novo e cria as seguintes mensagens para o GameView: "Draw Car 2 Fuel Pedal Pressed 80%", "Car 2 Sound Acceleration", "Car 2 Coordinates X, Y" .. .
- O GameView recebe as mensagens e as processa de acordo
fonte
update
-los). O segundo você pode fazer com as mensagens por vários motivos.Respostas:
Acredito plenamente na necessidade de ser a mãe da invenção. Não gosto de codificar nada, a menos que sua necessidade seja clara e bem definida. Eu acho que se você iniciar seu projeto configurando um sistema de mensagens de eventos, estará fazendo errado. Acredito que somente depois de criar e testar sua infraestrutura e ter todas as peças do seu projeto bem definidas, os módulos de trabalho devem se concentrar em como você irá conectar esses módulos. Tentar projetar um sistema de mensagens de eventos antes de entender a forma e as necessidades de cada módulo está com defeito.
Quais são as vantagens e desvantagens de ambas as abordagens?
Eu acho que algumas pessoas argumentariam que existem bons sistemas de mensagens por aí prontos para serem instalados e usados. Talvez isso seja verdade. Certamente, o desempenho de uma solução de construção personalizada especificamente adaptada às suas necessidades seria maior do que um barramento de mensagens de uso geral. A grande questão é: quanto tempo você gasta construindo um sistema de mensagens em vez de usar algo que já foi construído. Obviamente, se você pudesse encontrar algum tipo de sistema de eventos com exatamente o conjunto de recursos necessário, será uma decisão bastante fácil. É por isso que eu entendo exatamente o que preciso antes de tomar essa decisão.
Onde é melhor um sobre o outro?
Poderíamos falar sobre memória e recursos aqui. Se você está desenvolvendo para qualquer hardware com recursos limitados, certamente é um problema usar um sistema de eventos que o corte significativamente. Realmente, porém, acho que a questão se resume ao que você precisa, o que, como já mencionei, é algo que você não sabe até ver como são todas as peças. Se você tem experiência suficiente na construção desses sistemas e sabe com antecedência exatamente como serão todas as peças, poderá responder a essa pergunta com antecedência. Acho que você não tem essa experiência, pois não faria essa pergunta se tivesse.
O design de jogos orientado a eventos é universal e melhor em todas as áreas? Portanto, é recomendado para uso mesmo em plataformas móveis?
Universal e melhor em todas as áreas? Uma declaração bastante abrangente como essa é facilmente rejeitada. Qualquer coisa que acrescente sobrecarga precisa transportar sua parte da carga de trabalho. Se você não estiver usando eventos suficientes para garantir a sobrecarga do design, será o design errado.
Qual é mais eficiente e qual é mais difícil de desenvolver?
A eficiência depende de como é implementada. Penso que um design tradicional bem desenvolvido superará o desempenho de um sistema baseado em eventos em qualquer dia da semana. Isso ocorre porque a comunicação entre as peças pode ser microgerenciada e super eficiente. Obviamente, isso também torna mais difícil projetar do ponto de vista da experiência e do tempo necessários para completá-lo e torná-lo mais eficiente. Por outro lado, se você não tiver essa experiência ou não tiver tempo para desenvolver bem o aplicativo, o uso de um design baseado em eventos que atenda às suas necessidades será mais eficiente. Se você tiver necessidades personalizadas de eventos que não se encaixam facilmente em uma estrutura baseada em eventos, isso poderá dificultar o design da estrutura baseada em eventos - especialmente para manter o design eficiente.
fonte
Acho que você está comparando maçãs e laranjas aqui. O polimorfismo não é substituído por mensagens. Você provavelmente desejaria que eventos / mensagens conectassem componentes fracamente acoplados. Por exemplo. enviar uma mensagem de uma entidade quando ocorrer uma colisão, atualizar a pontuação do jogador ou talvez acionar um efeito sonoro. Para que essas classes individuais não conheçam as outras classes e apenas enviem e / ou manejem mensagens.
Mas é provável que o seu jogo tenha um loop de atualização em algum lugar e, como você possui esse loop de atualização, ele pode ser facilmente usado para atualizar todas as entidades do jogo que precisam ser atualizadas a cada quadro também. Isso não impede que você use as mensagens ...
Se você tem algum tipo de estrutura na qual você adiciona / remove entidades do jogo, também pode incluí-las no loop de atualização, em vez de enviar uma mensagem de atualização para cada quadro. Então, por que não chamar a atualização diretamente nas entidades do jogo enquanto você usa as mensagens para conectar diferentes subsistemas do jogo? Também gosto do conceito de Sinal / Slot ( veja o exemplo qt ) para sistemas semelhantes a eventos.
Conclusão: não existe uma abordagem melhor nem exclusiva.
fonte
Isso começou como um comentário à resposta de bummzack, mas demorou muito.
A menos que você realmente assíncrono (eventos de despacho em um novo thread), seus objetos ainda estão recebendo o memorando de forma síncrona. Supondo que o distribuidor de eventos use uma tabela de hash básica com uma lista vinculada em uma célula, a ordem será a ordem na qual os objetos foram adicionados a essa célula.
Além disso, a menos que você decida usar ponteiros de função por algum motivo, ainda estará usando chamadas de função virtual, pois cada objeto que recebe uma mensagem deve implementar o IEventListener (ou o que você chamar). Eventos são uma abstração de alto nível que você constrói usando polimorfismo.
Use eventos em que você precise chamar uma lista completa de métodos para vários acontecimentos no jogo, a fim de sincronizar sistemas diferentes no jogo ou em que a reação de vários objetos e sistemas, para que os acontecimentos não possam ser claramente definidos ou você queira para adicionar mais reações aos acontecimentos mencionados no futuro.
Eles são uma ótima ferramenta, mas, como disse Bummzack, não assuma que o polimorfismo e os eventos resolvam o mesmo problema.
fonte
Eu diria que escolher um ou outro é muito errado. Alguns objetos precisam chamar todos os quadros - outros não. Se você tiver um objeto que deseja renderizar, precisará fazer uma chamada de renderização a cada quadro. Eventos não podem fazer essa alteração. O mesmo vale para qualquer objeto de física baseado no tempo - você deve chamá-lo de todos os quadros.
No entanto, eu não faço chamadas a cada quadro para meus objetos de gerenciamento de objetos, meus objetos de entrada do usuário ou qualquer coisa assim. Chamadas virtuais em massa para todos os objetos no quadro são uma péssima idéia.
O design usado para qualquer objeto em particular deve ser baseado nas necessidades desses objetos e não em alguma ideologia para o sistema como um todo.
Editado para ficar mais claro na minha primeira frase.
fonte