De nombreuses sources de mouvement dans un système d'entités


9

Je suis assez nouveau dans l'idée des systèmes d'entités, après avoir lu un tas de choses (le plus utile, ce grand blog et cette réponse ).

Bien que j'aie un peu de mal à comprendre comment quelque chose d'aussi simple que de pouvoir manipuler la position d'un objet par un nombre indéfini de sources.

Autrement dit, j'ai mon entité, qui a une composante de position. J'ai alors un événement dans le jeu qui dit à cette entité de se déplacer sur une distance donnée, dans un temps donné.

Ces événements peuvent survenir à tout moment et auront des valeurs différentes pour la position et l'heure. Le résultat est qu'ils seraient combinés ensemble.

Dans une solution OO traditionnelle, j'aurais une sorte de MoveByclasse, qui contient la distance / temps, et un tableau de ceux à l'intérieur de ma classe d'objets de jeu. Chaque image, je répéterais à travers tout MoveBy, et l'appliquerais à la position. Si a MoveBya atteint son heure de fin, supprimez-le du tableau.

Avec le système d'entités, je suis un peu confus quant à la façon de reproduire ce type de comportement.

S'il n'y en avait qu'un à la fois, au lieu de pouvoir les mélanger ensemble, ce serait assez simple (je crois) et ressembler à ceci:

PositionComponent contenant x, y

MoveByComponent contenant x, y, time

Entityqui a à la fois un PositionComponentet unMoveByComponent

MoveBySystemqui recherche une entité avec ces deux composants et ajoute la valeur de MoveByComponentau PositionComponent. Lorsque le timeest atteint, il supprime le composant de cette entité.

Je suis un peu confus quant à la façon dont je ferais la même chose avec de nombreux déménagements.

Mes premières pensées sont que j'aurais:

PositionComponent, MoveByComponentcomme ci-dessus

MoveByCollectionComponentqui contient un tableau de MoveByComponents

MoveByCollectionSystemqui recherche une entité avec un PositionComponentet un MoveByCollectionComponent, itérant à travers le MoveByComponents à l'intérieur, en appliquant / supprimant si nécessaire.

Je suppose que c'est un problème plus général, d'avoir beaucoup du même composant, et de vouloir un système correspondant pour agir sur chacun. Mes entités contiennent leurs composants dans un hachage de type composant -> composant, donc strictement 1 seul composant d'un type particulier par entité.

  1. Est-ce la bonne façon de voir les choses?

  2. Une entité ne devrait-elle avoir à tout moment qu'un seul composant d'un type donné?


1
Sonne un peu comme la MoveByfonctionnalité est une sorte de vitesse? On dirait que vous êtes sur la bonne voie. Pour votre deuxième question, il existe de nombreuses implémentations différentes de systèmes d'entités / composants. Celui décrit dans ma réponse que vous avez lié n'aurait qu'un seul composant d'un type donné.
MichaelHouse

En quelque sorte, mais la différence étant que cette vitesse n'est valable que d'une fois à l'autre, et beaucoup d'entre elles peuvent être combinées ensemble à la fois. Je pense que j'avais juste besoin d'être rassuré, j'ai été strict (anal, presque) OO pour mes jeux dans le passé - ce qui, plus tard, sur le même projet, a paralysé notre vitesse de production - et c'est un territoire qui ne nous est pas familier;) . En passant, une excellente réponse sur l'autre post a aidé à clarifier certaines choses
Sticky

Je le fais comme ceci: j'ai PlayerInputComponent et AIInputComponent (ou des systèmes) qui diront à MobileBehaviorComponent qu'au clic du clavier ou sur AI pensant que le mobile devrait se déplacer quelque part, MobileBehaviorComponent stockera qu'il devrait se déplacer quelque part (il a FSM à l'intérieur pour les actions mobiles) et un système le déplacera. Votre granularité est tout simplement trop, avec des composants de niveau supérieur, comme Transform, Model, Light, Mob tout fonctionne aussi bien. De plus, je n'ai jamais eu besoin de supprimer des composants - je pense à eux plus comme quelque chose qui décrit un objet de jeu afin qu'il ne puisse pas simplement disparaître.
Kikaimaru

Cet exemple MoveBy particulier n'était qu'un exemple. La question était plutôt de savoir comment vous composez les choses ensemble comme ça. Si j'ai besoin de dire spécifiquement «se déplacer de x = 5 et y = 6 en 5 secondes» «se déplacer de x = 10 y = 2 en 10 secondes», en même temps, est-ce ainsi que je procéderais?
Sticky

Qu'entendez-vous par «composé ensemble»? Vous aimez ajouter des vitesses? Donc, si vous composiez move x by 10 in 2 secondset que move x by -10 in 2 secondsl'entité resterait parfaitement immobile?
Tom Dalling

Réponses:


6

Pour votre scénario, nous ajoutons généralement trois composants à un objet de jeu:

  1. TransformComponent (position, orientation, échelle)
  2. VelocityComponent (vitesse, direction)
  3. ControllerComponent

Lorsque les objets de jeu ont besoin d'un certain type de fonctionnalité d'IA, comme se déplacer le long d'un chemin comme vous l'avez décrit, nous affectons un AIController à sa liste de composants. Les contrôleurs AIC ne sont en réalité rien de plus qu'un wrapper qui parcourt un arbre comportemental. L'arbre de comportement est l'endroit où nous concevons les fonctionnalités réelles que nous voulons que l'objet de jeu exécute, telles que:

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));

Le sous-système AI gère les contrôleurs AIC et de sorte que le sous-système coche le contrôleur qui, à son tour, fait avancer l'arborescence des comportements. MoveToNode () examine la position / orientation actuelle, calcule un vecteur de direction et une vitesse vers laquelle vous souhaitez vous déplacer en fonction de ses arguments de constructeur et définit les valeurs sur la composante de vitesse. Le système de mouvement est chargé de lire les composants de mouvement avec des valeurs et d'appliquer la physique, mettant ainsi à jour la position / orientation en conséquence.

Le code ci-dessus déplace simplement un objet de jeu de l'emplacement d'apparition vers x, y, z dans l'espace mondial, puis attend un minimum de 30 secondes, puis déplace l'objet de jeu vers l'emplacement a, b, c, puis attend encore 30 secondes. Une fois l'attente terminée, la séquence de comportements est terminée, elle se répète donc dès le début.

Cela vous permet de définir facilement la fonctionnalité AI dont vous avez besoin, entièrement autonome dans le sous-système AI, avec un impact minimal sur votre sous-système Entity. Il vous permet également de conserver votre liste de composants système d'entité allégée sans trop de granularité.


1

Une option consiste à ajouter des contrôleurs à votre conception. Les entités possèdent des données pour représenter la position (dans le cas de mon moteur, elles ont aussi des données qui se souviennent des positions précédentes, donc je peux connaître le vecteur vitesse et si elles sont déplacées ou téléportées), mais elles ne savent rien de la physique ou AI. Les contrôleurs déplacent des entités et vous pouvez avoir plusieurs contrôleurs affectant la même entité ou un contrôleur affectant différentes entités.

Par exemple: créez une classe Controller de base avec une méthode run (), ou si vous n'aimez pas le nom, appelez-le think (), update () ou tick (). Ensuite, vous en héritez et créez un MoveController, NPCController, PlayerInputController (pour l'entité du joueur), PhysicController; puis vous implémentez la méthode run (). Je mettrais votre MoveByComponent dans le MoveController et non dans Entity.

Ces contrôleurs peuvent être instanciés par chaque entité s'ils détiennent des données spécifiques à une entité. Ils peuvent être détruits ou réinitialisés pour une réutilisation ultérieure. Vous pouvez également utiliser un contrôleur pour déplacer un groupe d'entités, dans un jeu RTE par exemple, si vous devez déplacer différentes unités en groupe, avoir un contrôleur par chaque unité peut nuire aux performances du jeu, alors vous pouvez simplement assigner toutes les unités à un GroupController ou LegionController et laissez-le déplacer les unités dans le cadre d'un groupe organisé. Lors des combats, si le jeu autorise le comportement d'une unité individuelle, et probablement la plupart des jeux le font, vous devrez passer à un UnitController mais il est préférable de ne le faire qu'en cas de besoin plutôt que depuis le début.

Dans mon jeu en développement, j'ai un MoveController qui déplace les entités suivant un chemin, un MoveController existe pour chaque PNJ et le personnage du joueur. Parfois, un est créé pour les boîtes ou le rock que le joueur peut pousser. Le PhysicController, une seule instance, qui vérifiera les positions de toutes les entités qui lui sont affectées, si une entité entre en collision avec une autre entité affectée, la position résultante des deux est calculée (il fait en fait plus que cela, mais vous avez l'idée). Le NPCController est l'IA, une instance par NPC. Il vérifie la situation du NPC et décide où se déplacer, puis pousse le chemin vers un MoveController, qui déplace réellement le NPC. Les contrôleurs ont une priorité, donc je peux déterminer à l'avance leur ordre, le PhysicController est le dernier à s'exécuter.

Je préconise les contrôleurs, mais ce n'est pas la seule option "correcte". Par exemple, je me souviens d'une interface Entity dans le moteur Cafu qui a la méthode think () dans l'entité elle-même, l'utilisateur de la classe doit hériter d'Entity et implémenter think (), je me souviens d'une classe dérivée appelée CompanyBot (qui vient avec l'exemple jeu) qui effectuent une vérification des collisions dans cette méthode, comme on l'appelle "pensez", nous pouvons supposer que le code AI devrait également être là. Alors que le moteur NeoAxis (la dernière fois que je l'ai étudié) a l'IA et la physique séparées des entités.

Il existe un modèle de contrôleur que j'ai écouté. Peut-être que vous devriez le rechercher, et ce n'est probablement pas exactement ce dont je parle ici, mais cela semble aussi être une bonne solution.


C'est essentiellement la conception OO que nous avons déjà en ce moment. Une entité, avec des dérivés (personnage, monstre), etc., je dirige une équipe d'entre nous qui travaille sur ce jeu à temps plein depuis près de 2 ans, et avec tout le monde changeant les choses à volonté, c'est devenu horrible, horrible codebase - et commence à prendre un temps embarrassant pour obtenir de nouvelles fonctionnalités. L'idée Entity System semble être exactement ce que je recherche, donc bien que votre réponse ne soit pas tout à fait pertinente, vous devriez lire vous-même les liens en haut de la question, voir s'ils peuvent vous aider :)
Sticky

@Sticky Je dois admettre que le Node System plus Entity constitué de composants est une façon intelligente de représenter les différents systèmes nécessaires que mon approche de contrôleurs suggérée, qui ressemble à une version moins évoluée. Vous n'avez vraiment pas besoin de ma réponse après tout.
Hatoru Hansou

Pas de soucis. La méthode OO a ses avantages, mais les choses deviennent laides et rapides
Sticky
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.