Muitas fontes de movimento em um sistema de entidades

9

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 MoveByclasse, 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 MoveBye aplicava à posição. Se a MoveByatingir 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

Entityque tem um PositionComponente umMoveByComponent

MoveBySystemque procura uma entidade com esses dois componentes e agrega o valor de MoveByComponenta 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, MoveByComponento mesmo que acima

MoveByCollectionComponentque contém uma matriz de MoveByComponents

MoveByCollectionSystemque procura uma entidade com a PositionComponente a MoveByCollectionComponent, iterando através dos MoveByComponents 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.

  1. É este o caminho certo para olhar para isso?

  2. Uma entidade deve sempre ter um componente de um determinado tipo o tempo todo?

Pegajoso
fonte
11
Parece que a MoveByfuncionalidade é 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.
MichaelHouse
Mais ou menos, mas a diferença é que essa velocidade é válida apenas de uma vez para outra, e muitas delas podem ser combinadas de uma só vez. Acho que só precisava de uma certa tranquilidade, fui rigoroso (anal, quase) OO para meus jogos no passado - que anos depois no mesmo projeto prejudicaram nossa velocidade de produção - e este é um território assustadoramente desconhecido;) . Grande resposta no outro post, a propósito, ajudou a esclarecer algumas coisas
Fixo
Eu faço assim: tenho PlayerInputComponent e AIInputComponent (ou sistemas) que informarão ao MobileBehaviorComponent que, no teclado ou no AI, achando que o celular deve se mover para algum lugar, o MobileBehaviorComponent armazenará que ele deve se mover para algum lugar (tem FSM interno para ações móveis) e algum sistema irá movê-lo. Sua granularidade é demais, com componentes de nível superior, como Transform, Model, Light, Mob, tudo funciona da mesma maneira. Também nunca precisei remover componentes - penso neles mais como algo que descreve o objeto do jogo, para que ele não possa simplesmente desaparecer.
Kikaimaru
Este exemplo específico de MoveBy foi apenas um exemplo. A questão era mais sobre como você compõe as coisas assim. Se eu precisar dizer especificamente 'mover por x = 5 ey = 6 em 5 segundos' 'mover por x = 10 y = 2 em 10 segundos', ao mesmo tempo, é assim que eu faria?
Sticky
O que você quer dizer com "compostos juntos"? Como adicionar velocidades? Então, se você compôs move x by 10 in 2 secondse move x by -10 in 2 secondsa entidade permanecesse perfeitamente imóvel?
precisa

Respostas:

6

Para o seu cenário, normalmente adicionamos três componentes a um objeto de jogo:

  1. TransformComponent (posição, orientação, escala)
  2. VelocityComponent (velocidade, direção)
  3. ControllerComponent

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:

BehaviorTree* tree(new SequentialNode());
tree->addChild(new MoveToNode(x,y,z));
tree->addChild(new WaitNode(30));
tree->addChild(new MoveToNode(a,b,c));
tree->addChild(new WaitNode(30));
gameObject->addComponent(new AIController(tree));

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.

Naros
fonte
1

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.

Hatoru Hansou
fonte
Esse é basicamente o design OO que já temos no momento. Uma Entidade, com derivativos (Personagem, Monstro) etc., eu tenho liderado uma equipe que trabalha neste jogo em tempo integral há quase 2 anos, e com todos mudando as coisas à vontade, tornou-se horrível, horrível codebase - e está começando a levar um tempo embaraçosamente longo para o lançamento de novos recursos. A ideia do sistema de entidades parece ser exatamente o que estou procurando. Portanto, embora sua resposta não seja relevante, você deve ler os links na parte superior da pergunta e verificar se eles podem ajudá-lo :)
Sticky
@Skyky Eu tenho que admitir que o Node System plus Entity feito de componentes é uma maneira inteligente de representar os diferentes sistemas necessários do que a abordagem sugerida pelos meus controladores, que é como uma versão menos evoluída. Você realmente não precisa da minha resposta, afinal.
Hatoru Hansou 25/11
Não se preocupe. A maneira OO tem suas vantagens, mas as coisas ficam feias, rápido
Fixo