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?
fonte
Respostas:
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.
fonte