Quero fazer uma pergunta sobre como a troca de informações entre as partes do motor do jogo deve ser implementada.
O mecanismo é separado em quatro partes: lógica, dados, interface do usuário, gráficos. No começo eu fiz essa troca através das bandeiras. Por exemplo, se o novo objeto for adicionado aos dados, o sinalizador isNew
na classe de um objeto será definido como true
. E depois disso, a parte gráfica do mecanismo verificará essa bandeira e adicionará o objeto ao mundo do jogo.
Porém, com essa abordagem, escrevi muito código para processar todos os sinalizadores de cada tipo de objeto.
Pensei em usar algum sistema de eventos, mas não tenho experiência suficiente para saber se essa seria a solução certa.
O sistema de eventos é a única abordagem apropriada ou devo usar outra coisa?
Estou usando o Ogre como o mecanismo gráfico, se isso importa.
fonte
Respostas:
Minha estrutura de mecanismo de jogo favorita é a interface e o objeto <-> modelo de componente usando mensagens para comunicação entre quase todas as partes.
Você tem várias interfaces para as principais partes do mecanismo, como o gerenciador de cenas, o carregador de recursos, o áudio, o renderizador, a física etc.
Eu tenho o gerente de cena encarregado de todos os objetos na cena / mundo 3D.
Objeto é uma classe muito atômica, contendo apenas algumas coisas comuns a quase tudo em sua cena. No meu mecanismo, a classe de objeto mantém apenas posição, rotação, uma lista de componentes e um ID exclusivo. O ID de cada objeto é gerado por um int estático, de modo que nenhum objeto tenha o mesmo ID; isso permite que você envie mensagens para um objeto por seu ID, em vez de precisar de um ponteiro para o objeto.
A lista de componentes no objeto é o que fornece a esses objetos as principais propriedades. Por exemplo, para algo que você pode ver no mundo 3D, você daria ao seu objeto um componente de renderização que contém as informações sobre a malha de renderização. Se você deseja que um objeto possua física, daria a ele um componente de física. Se você quiser que algo atue como uma câmera, forneça um componente para ela. A lista de componentes pode continuar indefinidamente.
A comunicação entre interfaces, objetos e componentes é fundamental. No meu mecanismo, tenho uma classe de mensagem genérica que contém apenas um ID exclusivo e um ID do tipo de mensagem. O ID exclusivo é o ID do objeto para o qual você deseja que a mensagem e o ID do tipo de mensagem é usado pelo objeto que recebe a mensagem para que ele saiba que tipo de mensagem é.
Os objetos podem manipular a mensagem, se necessário, e podem passar a mensagem para cada um de seus componentes, e os componentes geralmente fazem coisas importantes com a mensagem. Por exemplo, se você deseja alterar a posição do objeto e enviar uma mensagem SetPosition ao objeto, o objeto pode atualizar sua variável de posição ao receber a mensagem, mas o componente de renderização pode precisar de uma mensagem para atualizar a posição da malha de renderização e o componente físico pode precisar da mensagem para atualizar a posição do corpo físico.
Aqui está um layout muito simples do gerenciador de cenas, objeto e componente e fluxo de mensagens, que criei em cerca de uma hora, escrito em C ++. Quando executada, define a posição em um objeto e a mensagem passa pelo componente de renderização e recupera a posição do objeto. Aproveitar!
Além disso, eu escrevi uma versão em C # e uma versão em Scala do código abaixo para qualquer pessoa que seja fluente naqueles e não em C ++.
fonte
Eu acho que é a melhor maneira de usar o Scene Manager e Interfaces. As mensagens foram implementadas, mas eu a usaria como abordagem secundária. As mensagens são boas para a comunicação entre threads. Use abstração (interfaces) sempre que puder.
Eu não sei muito sobre o Ogre, então estou falando em geral.
No núcleo, você tem o loop principal do jogo. Ele recebe sinais de entrada, calcula a IA (do movimento simples à IA complexa e lógica do jogo), carrega recursos [, etc] e renderiza o estado atual. Este é um exemplo básico, para que você possa separar o mecanismo nessas partes (InputManager, AIManager, ResourceManager, RenderManager). E você deve ter o SceneManager, que contém todos os objetos presentes no jogo.
Cada uma dessas partes e suas sub-partes têm interfaces. Portanto, tente organizar essas partes para fazer seu e somente seu trabalho. Eles devem usar sub-partes que interagem internamente com o objetivo de sua parte-pai. Dessa forma, você não se envolverá sem chance de desenrolar sem reescrever totalmente.
ps se você estiver usando C ++, considere usar o padrão RAII
fonte