Estou escrevendo o mecanismo de jogo que consiste em poucos módulos. Dois deles são os mecanismo gráfico e o mecanismo de física .
Gostaria de saber se é uma boa solução para compartilhar dados entre eles?
Duas maneiras (compartilhando ou não) são assim:
Sem compartilhar dados
GraphicsModel{
//some common for graphics and physics data like position
//some only graphic data
//like textures and detailed model's verticles that physics doesn't need
};
PhysicsModel{
//some common for graphics and physics data like position
//some only physics data
//usually my physics data contains A LOT more informations than graphics data
}
engine3D->createModel3D(...);
physicsEngine->createModel3D(...);
//connect graphics and physics data
//e.g. update graphics model's position when physics model's position will change
Eu vejo dois problemas principais:
- Muitos dados redundantes (como duas posições para dados físicos e gráficos)
- Problema com a atualização de dados (tenho que atualizar manualmente os dados gráficos quando os dados da física são alterados)
Com compartilhamento de dados
Model{
//some common for graphics and physics data like position
};
GraphicModel : public Model{
//some only graphics data
//like textures and detailed model's verticles that physics doesn't need
};
PhysicsModel : public Model{
//some only physics data
//usually my physics data contains A LOT more informations than graphics data
}
model = engine3D->createModel3D(...);
physicsEngine->assingModel3D(&model); //will cast to
//PhysicsModel for it's purposes??
//when physics changes anything (like position) in model
//(which it treats like PhysicsModel), the position for graphics data
//will change as well (because it's the same model)
Problemas aqui:
- physicsEngine não pode criar novos objetos, apenas "avaliando" os existentes no engine3D (de alguma forma, parece mais anti-independente para mim)
- Transmitindo dados na função assingModel3D
- physicsEngine e graphicsEngine deve ter cuidado - eles não podem excluir dados quando não precisam deles (porque o segundo pode precisar). Mas é uma situação rara. Além disso, eles podem simplesmente excluir o ponteiro, não o objeto. Ou podemos assumir que graphicsEngine excluirá objetos, physicsEngine apenas ponteiros para eles.
Qual caminho é melhor?
O que produzirá mais problemas no futuro?
Gosto mais da segunda solução, mas me pergunto por que a maioria dos mecanismos gráficos e de física prefere a primeira (talvez porque normalmente produzem apenas gráficos ou apenas mecanismo de física e alguém os conecte no jogo?).
Eles têm mais prós e contras escondidos?
physics
architecture
graphics
PolGraphic
fonte
fonte
Respostas:
Atualmente, mais mecanismos de jogo adotam um design de componente (por exemplo, Unity, Unreal). Nesse tipo de design, a
GameObject
é composto por uma lista de componentes. Na sua situação, pode haver umMeshComponent
e umPhysicalComponent
, ambos anexados a um único objeto de jogo.Para simplificar, você pode colocar uma variável de transformação mundial no arquivo
GameObject
. Durante a frase de atualização,PhysicalComponent
gera a transformação mundial para essa variável. Durante a renderização, aMeshComponent
variável é lida.A lógica por trás desse design é separar os componentes. Nem
MeshComponent
nem sePhysicalComponent
conhecem. Eles só depende de uma interface comum. E pode ser mais fácil estender o sistema por composição do que usar uma hierarquia única de herança.Em um cenário realista, no entanto, você pode precisar de um tratamento mais sofisticado entre a sincronização física / gráfica. Por exemplo, a simulação física pode precisar ser executada em uma etapa de tempo fixo (por exemplo, 30Hz), enquanto a renderização precisa ser variável. E você pode precisar interpolar os resultados da saída do mecanismo de física. Alguns mecanismos de física (por exemplo, Bullet) têm suporte direto para esse problema.
A Unity forneceu uma boa referência de seus componentes , que vale a pena dar uma olhada.
fonte
Os mecanismos geralmente escolhem a primeira opção (malha física própria e malha renderizada) porque precisam de dados muito diferentes, tanto em qualidade quanto em quantidade.
Qualidade, porque o mecanismo de física não se importa com coordenadas de textura, grupos normais e todo esse material sofisticado, por exemplo. Cada um deles espera que os dados em um layout muito específico se concentrem em questões de alinhamento, empacotamento, intercalação de dados etc.
Quantidade porque a malha física geralmente tem muito menos triângulos, é uma versão simplificada da malha de renderização de alta resolução.
Ao dissociar os dois, garantimos que podemos modificar um, incluindo a alteração do layout dos dados para obter melhor desempenho, sem danificar o outro. É muito mais escalável.
fonte
Além da ótima resposta do @Millo Yip, gostaria apenas de lembrar que você precisará compartilhar os mesmos dados com o módulo Controls e o módulo AI e, se não me engano, a maioria das bibliotecas de áudio tem uma noção da posição do emissor de som então você precisará compartilhar os dados com esse módulo também.
fonte
Como outros já disseram, é bastante comum que a física tenha seu estado interno de dados gerenciado separadamente do estado interno de dados do mecanismo de renderização. Geralmente, é comum ver até os dados de transformação (posição / orientação / escala) armazenados separadamente da física e dos renderizáveis, porque é possível que exista um objeto de jogo que não seja imposto pela física nem seja renderizado, mas que exija uma posição mundial para outras mecânicas.
A decisão de como os dados vão da física para a renderização depende inteiramente de você.
Você pode fazer isso através de algum processo de despacho entre subsistemas usando eventos / mensagens. Você pode fazer isso expondo uma interface pública do subsistema de renderização ao subsistema de física, para que a física possa simplesmente definir a posição de uma renderização particularmente. Outra opção é que o subsistema renderizável consulte a entidade quanto à transformação durante sua atualização e faça a atualização da posição do componente renderizável, seguida pelo desenho.
Naturalmente, dependendo do seu jogo, alguns desses meios serão mais amigáveis ao cache e terão melhor desempenho do que outros. Eu não seria pego muito de uma maneira específica neste momento e escolheria um padrão de comunicação e tentaria. Você pode refazer esta parte facilmente mais tarde para testar vários meios de otimização.
fonte