Devo compartilhar dados entre gráficos e mecanismo de física no jogo?

9

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:

  1. Muitos dados redundantes (como duas posições para dados físicos e gráficos)
  2. 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:

  1. physicsEngine não pode criar novos objetos, apenas "avaliando" os existentes no engine3D (de alguma forma, parece mais anti-independente para mim)
  2. Transmitindo dados na função assingModel3D
  3. 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?

PolGraphic
fonte
Exatamente minha pergunta também.
Danijar

Respostas:

9

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 um MeshComponente 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, PhysicalComponentgera a transformação mundial para essa variável. Durante a renderização, a MeshComponentvariável é lida.

A lógica por trás desse design é separar os componentes. Nem MeshComponentnem se PhysicalComponentconhecem. 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.

Milo Yip
fonte
Isso não responde à pergunta, ter 2 componentes não diz nada sobre se eles compartilham os dados da malha ou não.
Maik Semder
2
Na verdade, oferece um design melhor, o que é completamente legítimo.
Jcora #
7

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.

Maik Semder
fonte
0

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.

ManicQin
fonte
0

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.

Naros
fonte