Sou bastante novo na idéia de sistemas de entidades, depois de ler várias coisas (muito útil, este ótimo blog e esta resposta ).
Embora eu esteja tendo problemas para entender como algo tão simples quanto poder manipular a posição de um objeto por um número indefinido de fontes.
Ou seja, eu tenho minha entidade, que tem um componente de posição. Então, eu tenho algum evento no jogo que diz a essa entidade para mover uma determinada distância, em um determinado momento.
Esses eventos podem ocorrer a qualquer momento e terão valores diferentes para posição e hora. O resultado é que eles seriam compostos juntos.
Em uma solução OO tradicional, eu teria algum tipo de MoveBy
classe, que contém a distância / tempo e uma matriz daquelas dentro da minha classe de objeto de jogo. Cada quadro, eu percorria todos os MoveBy
e aplicava à posição. Se a MoveBy
atingir o tempo de término, remova-o da matriz.
Com o sistema de entidades, estou um pouco confuso sobre como devo replicar esse tipo de comportamento.
Se houvesse apenas um deles de cada vez, em vez de ser capaz de combiná-los, seria bastante direto (acredito) e seria algo como isto:
PositionComponent
contendo x, y
MoveByComponent
contendo x, y, time
Entity
que tem um PositionComponent
e umMoveByComponent
MoveBySystem
que procura uma entidade com esses dois componentes e agrega o valor de MoveByComponent
a PositionComponent
. Quando o time
é atingido, ele remove o componente dessa entidade.
Estou um pouco confuso sobre como eu faria a mesma coisa com muitos movimentos.
Meu pensamento inicial é que eu teria:
PositionComponent
, MoveByComponent
o mesmo que acima
MoveByCollectionComponent
que contém uma matriz de MoveByComponent
s
MoveByCollectionSystem
que procura uma entidade com a PositionComponent
e a MoveByCollectionComponent
, iterando através dos MoveByComponent
s dentro dela, aplicando / removendo conforme necessário.
Acho que esse é um problema mais geral: ter muitos do mesmo componente e querer que um sistema correspondente atue em cada um. Minhas entidades contêm seus componentes dentro de um hash do tipo de componente -> componente, portanto, possuem apenas 1 componente de um tipo específico por entidade.
É este o caminho certo para olhar para isso?
Uma entidade deve sempre ter um componente de um determinado tipo o tempo todo?
fonte
MoveBy
funcionalidade é apenas uma velocidade? Parece que você está no caminho certo. Para sua segunda pergunta, há diversas implementações diferentes de sistemas de entidade / componente. O descrito na minha resposta que você vinculou teria apenas um componente de um determinado tipo.move x by 10 in 2 seconds
emove x by -10 in 2 seconds
a entidade permanecesse perfeitamente imóvel?Respostas:
Para o seu cenário, normalmente adicionamos três componentes a um objeto de jogo:
Quando os objetos do jogo precisam de algum tipo de funcionalidade de IA, como mover-se ao longo de um caminho, como você descreveu, atribuímos um AIController à sua lista de componentes. Os AIControllers são realmente nada além de um invólucro que percorre uma Árvore Comportamental. A árvore de comportamento é onde projetamos a funcionalidade real que queremos que o objeto do jogo execute, como:
O subsistema AI gerencia o AIControllers e, assim, o sistema controla o controlador que, por sua vez, percorre a Árvore de Comportamento. O MoveToNode () analisa a posição / orientação atual, calcula um vetor de direção e velocidade para onde você deseja mover com base nos argumentos do construtor e define os valores no componente de velocidade. O sistema de movimento é responsável pela leitura dos componentes do movimento com valores e pela aplicação da física, atualizando a posição / orientação de acordo.
O código acima simplesmente move um objeto de jogo do local de spawn para x, y, z no espaço do mundo, aguarda no mínimo 30 segundos, move o objeto de jogo para o local a, b, ce aguarda mais 30 segundos. Depois que a espera termina, a sequência de comportamentos termina e, portanto, se repete desde o início.
Isso permite que você defina facilmente qualquer funcionalidade de AI que você precise, totalmente autônoma no subsistema AI, com impacto mínimo no subsistema Entity. Ele também permite que você mantenha a lista de componentes do sistema de entidades enxuta sem muita granularidade.
fonte
Uma opção é adicionar controladores ao seu design. As entidades possuem dados para representar a posição (no caso do meu mecanismo, eles também têm dados que lembram as posições anteriores, para que eu possa conhecer o vetor de velocidade e se estão sendo movidos ou teletransportados), mas não sabem nada sobre física ou AI. Os controladores movem entidades e você pode ter muitos controladores que afetam a mesma entidade ou um controlador que afeta várias entidades.
Por exemplo: crie uma classe Controller básica com um método run () ou, se você não gostar do nome, chame think (), update () ou tick (). Então você o herda e cria um MoveController, NPCController, PlayerInputController (para a entidade player), PhysicController; então você implementa o método run (). Eu colocaria seu MoveByComponent no MoveController e não na Entity.
Esses controladores podem ser instanciados por cada entidade se eles mantiverem dados específicos de uma entidade. Eles podem ser destruídos ou redefinidos para reutilização. Além disso, você pode usar um Controlador para mover um grupo de entidades, em um jogo RTE, por exemplo, se você precisar mover várias unidades como um grupo, ter um controlador por cada unidade pode prejudicar o desempenho do jogo, então você pode simplesmente atribuir todas as unidades para um GroupController ou LegionController e deixe mover as unidades como parte de um grupo organizado. Nos combates, se o jogo permitir o comportamento individual de cada unidade, e provavelmente a maioria dos jogos permitir, você terá que mudar para um UnitController, mas é melhor fazer isso somente quando necessário do que desde o início.
No meu jogo em desenvolvimento, eu tenho um MoveController que move entidades seguindo um caminho, existe um MoveController para cada NPC e o personagem do jogador. Ocasionalmente, um é criado para caixas ou pedras que o jogador pode empurrar. O PhysicController, apenas uma instância, que verificará as posições de todas as entidades atribuídas a ele, se alguma entidade estiver colidindo com outra entidade atribuída, a posição resultante de ambas será calculada (na verdade, é mais do que isso, mas você entendeu). O NPCController é o AI, uma instância por NPC. Ele verifica a situação do NPC e decide para onde se mover, depois envia o caminho para um MoveController, que realmente move o NPC. Os controladores têm uma prioridade, para que eu possa determinar com antecedência sua ordem, o PhysicController é o último a ser executado.
Eu defendo controladores, mas não é a única opção "correta". Por exemplo, lembro-me de uma interface de entidade no mecanismo Cafu que possui o método think () na própria entidade, o usuário da classe deve herdar de Entity e implementar think (). Lembro-me de uma classe derivada chamada CompanyBot (que acompanha o exemplo game) que fazem alguma verificação de colisão nesse método, como é chamado de "think", podemos assumir que o código de IA também deve estar lá. Enquanto o mecanismo NeoAxis (da última vez que examinei), a IA e a física se separaram das entidades.
Existe um padrão de controlador que eu ouvi. Talvez você deva procurar e provavelmente não é exatamente disso que estou falando aqui, mas também parece uma boa solução.
fonte