Problema nos Conjuntos de Componentes de Processamento - Subsistema de Entidades

8

Descrição da arquitetura

Estou criando (projetando) um sistema de entidades e tive muitos problemas. Estou tentando mantê-lo orientado a dados e eficiente, tanto quanto possível. Meus componentes são estruturas de POD (matriz de bytes para ser mais preciso) alocadas em conjuntos homogêneos. Cada pool possui um ComponentDescriptor - ele contém apenas o nome do componente, os tipos e os nomes dos campos.

A entidade é apenas um ponteiro para a matriz de componentes (onde o endereço atua como um ID da entidade). EntityPrototype contém o nome da entidade e a matriz dos nomes dos componentes. Finalmente, subsistema (sistema ou processador) que funciona em conjuntos de componentes.

Problema real

O problema é que alguns componentes dependem de outros (Model, Sprite, PhysicalBody, Animation depende do componente Transform), o que cria muitos problemas quando se trata de processá-los.

For example, lets define some entities using [S]prite, [P]hysicalBody and [H]ealth:
Tank:   Transform, Sprite, PhysicalBody
BgTree: Transform, Sprite
House:  Transform, Sprite, Health

and create 4 Tanks, 5 BgTrees and 2 Houses and my pools will look like:

TTTTTTTTTTT // Transform pool
SSSSSSSSSSS // Sprite pool
PPPP        // PhysicalBody pool
HH          // Health component

Não há como processá-los usando índices. Passo 3 dias trabalhando nisso e ainda não tenho nenhuma idéia. Em projetos anteriores, o TransformComponent estava vinculado à entidade - mas não era uma boa ideia. Você pode me dar alguns conselhos sobre como processá-los? Ou talvez eu deva mudar o design geral? Talvez eu deva criar pools de entidades (pools de pools de componentes) - mas acho que será um pesadelo para caches de CPU.

obrigado

mani3xis
fonte
Multiplayer? (É relevante)
Jonathan Dickinson

Respostas:

2

Isenção de responsabilidade: puramente fora do meu conhecimento de classe de sistemas.

Inicialmente, pensei: por que não usar apenas uma função hash no ID da entidade para o seu índice?

Dessa forma, você obteria

T[A]nk:   Transform, Sprite, PhysicalBody
B[G]Tree: Transform, Sprite
H[O]use:  Transform, Sprite, Health

and create 4 Tanks, 5 BgTrees and 2 Houses and my pools will look like:

OGAGAGGOGGG // Entity pool (letters corresopnding to entity type)
TTTTTTTTTTT // Transform pool
SSSSSSSSSSS // Sprite pool
P P P  P    // PhysicalBody pool
H      H    // Health component

Ou, no entanto, foram as entidades que foram colocadas. Você pode ter conjuntos para todos os componentes e entidades e usar o conjunto de entidades como "mestre", para que as colisões sejam verificadas na matriz de entidades. Mas é claro que você tem o problema de reciclar componentes e entidades.

Se o design do seu jogo permitir, você pode planejar com antecedência para onde cada tipo de entidade vai, para obter a embalagem mais eficiente possível. Digamos que as entidades 0-20 são reservadas para tanques, as entidades 21-30 para casas e 31-60 para BGTrees. Talvez você não consiga gerar com eficiência infinitos erros e meio que derrote o dinamismo dos sistemas de componentes, mas isso resolveria o problema. Não vejo uma maneira de comer seu bolo e comê-lo também.

Eu estava pensando em maneiras de talvez acelerar o passe de renderização, onde você tem um RenderingComponentque contém todos os dados de que o sistema de renderização precisa, para que ele possa passar por uma série dessas coisas, mas há uma sobrecarga de cópia de dados. Além disso, sempre que você desdiferenciar um ponteiro, estará pensando se ele ainda está no cache.

Se você quer um jogo super rápido, eu diria que planeje sua alocação. Se você deseja uma arquitetura de jogo flexível, implante as hashtables e os IDs de string. Sempre que você desejar flexibilidade, precisará criar abstração e, portanto, sofrerá sobrecarga.

TL; DR;
Com base no que você descreveu, eu criaria um nível mais alto RenderComponentcom ponteiros Spritee Transformcomponentes e daria as referências necessárias ao inicializar a entidade.

(Desculpas por qualquer divagação percebida, estive pensando sobre isso no meu sistema também, então essa foi uma oportunidade para refletir sobre isso)

michael.bartnett
fonte
Não sei se os mapas de hash são tão eficazes. Eu quero ter sistemas de uma entidade em que os subsistemas contenham funções do DOD como: void update(u32 n, PhysicalBodyComponents* bodys, Transform* transforms)Quero trabalhar em muitas entradas e dividir essa função em vários núcleos. É possível com hashmaps?
Mani3xis
Os hashmaps são simplesmente uma maneira de identificar relacionamentos entre entidades e componentes. Isso depende de como o seu jogo está configurado, mas não vejo uma maneira eficiente de garantir que o seu bodyse o transformsarray estejam alinhados. Isso é algo que você não pode solucionar sem adicionar uma camada de abstração ou planejar sua alocação. Sinto que não tenho o conhecimento necessário para falar sobre o dimensionamento para vários núcleos. Talvez encontre uma pergunta sobre segmentação e dimensionamento ou escreva sua própria.
precisa saber é o seguinte
O dimensionamento é fácil quando as funções estão trabalhando em matrizes lineares - eu posso configurar um intervalo para cada núcleo e apenas executá-lo. É por isso que estou tentando evitar hashmaps. Vou tentar redesenhar esse sistema de entidades. Eu tenho que ter muito cuidado com caches acidentes - PS2 tem RAM muito limitado, etc. BTW: Nada é impossível :)
mani3xis
Nada é impossível, mas nem tudo é possível;). Você pode se esforçar pela simplicidade e elegância da implementação, velocidade de execução e consumo de memória: escolha duas. Quando você encontrar sua solução, poste-a como resposta. Tenho certeza de que não sou a única pessoa que gostaria de vê-la.
precisa saber é o seguinte