Sistema de componentes de entidades - Como implementar a transformação de um objeto?

11

Ao projetar um sistema de entidade-componente para o meu mecanismo, deparei-me com um pequeno obstáculo na maneira de armazenar e recuperar um tipo específico de componente.

Primeiro, deixe-me esclarecer um pouco da terminologia que vou usar nesta pergunta:

  • Eu chamo de " Componente " uma estrutura de dados que armazena dados relevantes para um sistema específico.
  • Eu chamo de " sistema " uma agregação de métodos e estruturas de dados que utiliza componentes para atualizar o estado / interface do jogo com o usuário.
  • Uma " entidade " é basicamente apenas um ID usado para recuperar componentes específicos e modificar seus dados na lógica do jogo.

Cada sistema possui uma matriz (mapeada por ID) de seu tipo de componente (por exemplo, Física-> Componente físico, AI-> AIComponent, Renderização-> RenderingComponent), para que possa iterar eficientemente os dados.

Porém, nem todos os componentes pertencem especificamente a um sistema. Por exemplo, um componente Transform armazena a posição, rotação e escala de um objeto. É uma das partes mais importantes de uma entidade (o Unity o torna obrigatório, mesmo), pois é usado por muitos sistemas, por exemplo, Física, IA, Renderização etc.

Esse é praticamente o problema que estou enfrentando. Como o Transform é usado por muitos outros sistemas, como devo recuperar um para usar em cada componente? Uma solução possível que vejo é fazer com que cada componente armazene seu próprio ID de entidade. Seria fácil recuperar qualquer componente como esse, mas não seria tão eficiente e também iria contra o conceito de um componente como um pacote de dados isolado e independente, que não conhece nenhum outro.

Existe uma maneira adequada de resolver esse problema? O Transform deve mesmo ser um componente?

CRefice
fonte
3
+1 para "Primeiro, deixe-me esclarecer um pouco a terminologia que vou usar nesta pergunta:"
Vaillancourt
Gostaria muito de ver mais este tipo de perguntas neste site. +1
S. Tarik Çetin
Basta armazenar todos os componentes como variáveis ​​globais
Miles Rout

Respostas:

2

Essa é uma pergunta bastante ampla, cuja resposta depende fortemente da sua arquitetura. No entanto, tentarei dar uma resposta geral.

Seus sistemas de física e renderização certamente exigirão a transformação; no entanto, o sistema de IA não. Portanto, faz sentido encapsular a transformação em sua própria classe de componentes. Todos esses sistemas interessados ​​usariam os mesmos dados; portanto, faz sentido que a entidade tenha um ponteiro para o objeto de transformação ou um ID para um objeto de transformação armazenado em outro local.

Se você escolher a última solução, cada sistema que estiver interessado em uma transformação precisará acessar onde quer que o objeto de transformação esteja armazenado.

Se você escolher o primeiro, tudo o que cada sistema precisa fazer é acessar a própria entidade e solicitar a transformação.

No primeiro caso, o problema passa a ser como conceder acesso ao armazenamento para transformações em cada sistema, sem violar as regras de POO, se você se preocupa com essas coisas.

O último caso não tem esses problemas, mas requer a alteração do design do objeto da entidade para armazenar ponteiros em objetos, em vez de IDs de objetos componentes.

Minha preferência pessoal é projetar a classe de entidade para armazenar ponteiros para objetos componentes, pois isso simplifica muitos problemas de design. Dessa forma, cada sistema que requer uma transformação pode solicitá-la à entidade e ignorá-lo, se não o fizer. No entanto, isso carrega uma sobrecarga computacional inerente aos ponteiros, que é o custo do cache em falta.

Veja esta Visão geral do ECS para obter mais informações sobre isso.

No final do dia, cabe a você decidir o que é mais importante para você: facilidade de desenvolvimento ou desempenho.

Por fim, gostaria de salientar que sua pergunta é um excelente exemplo das questões de design que os proponentes da ECS pensam, e não há uma solução definitiva para a bala de prata.

Ian Young
fonte
Obrigado por suas sugestões. Mas eu tenho uma pergunta: por que o sistema de IA não precisaria da posição de um objeto?
CRefice
Você está confundindo a posição (vetor de 3 flutuadores) com uma translação (matriz de transformação construída a partir de um vetor de posição). Uma matriz de transformação é construída a partir de transformações de translação, rotação e escala. Isso é muito mais informações do que um sistema de IA precisaria, embora você certamente possa extrair o vetor de posição a partir dele. Pessoalmente, eu separaria posição, orientação e tamanhos em seu próprio componente e os usaria para criar e atualizar a Transformação.
22617 Ian
@IanYoung Separá-los pode causar mais mal do que bem, potencialmente se você achar que precisa de posição e orientação juntos com mais frequência do que posição ou orientação separadamente. Nesse caso, a colocação de atributos de dados de posição e orientação em um único componente pode melhorar o desempenho do cache.
Naros
1
Minha preferência é combinar todos os três, posição, orientação e escala em um único componente e, nos casos em que um subsistema específico precisa apenas de uma posição ou orientação, eu recomendaria duplicar os dados e sincronizá-los em pontos claramente definidos no ciclo do jogo .
Naros
@ Naros sim, é isso que eu quis dizer: Dois Componentes, Transformação e (no meu quadro) SpatialData, que contém posição, velocidade, orientação e velocidade angular. A posição e a orientação são usadas para construir e atualizar a transformação.
22717 Ian Ian