Comment implémenter un comportement dans une architecture de jeu basée sur des composants?

21

Je commence à implémenter l'IA du joueur et de l'ennemi dans un jeu, mais je ne sais pas comment l'implémenter au mieux dans une architecture de jeu basée sur les composants.

Disons que j'ai un personnage de joueur suivant qui peut être stationnaire, courir et balancer une épée. Un joueur peut passer à l'état d'épée pivotante à la fois à partir de l'état stationnaire et en cours d'exécution, mais ensuite le swing doit être terminé avant qu'il ne puisse reprendre la position debout ou courir. Pendant le swing, le joueur ne peut pas se déplacer.

Selon moi, j'ai deux approches de mise en œuvre:

  • Créez un seul composant AI contenant toute la logique du joueur (soit découplé du composant réel, soit incorporé en tant que PlayerAIComponent). Je peux facilement appliquer les restrictions d'état sans créer de couplage entre les composants individuels composant l'entité du joueur. Cependant, le composant AI ne peut pas être décomposé. Si j'ai, par exemple, un ennemi qui ne peut que se tenir debout et marcher ou se promener et parfois balancer une épée, je dois créer de nouveaux composants d'IA.
  • Décomposez le comportement en composants, chacun identifiant un état spécifique. J'obtiens alors un StandComponent, WalkComponent et SwingComponent. Pour appliquer les règles de transition, je dois coupler chaque composant. SwingComponent doit désactiver StandComponent et WalkComponent pendant la durée du swing. Lorsque j'ai un ennemi qui ne fait que rester debout, balançant une épée de temps en temps, je dois m'assurer que SwingComponent ne désactive WalkComponent que s'il est présent. Bien que cela permette de meilleurs mélanges et correspondances, cela peut conduire à un cauchemar de maintenabilité car chaque fois qu'une dépendance est ajoutée, les composants existants doivent être mis à jour pour bien jouer avec les nouvelles exigences que la dépendance impose au personnage.

La situation idéale serait qu'un concepteur puisse construire de nouveaux ennemis / joueurs en faisant glisser des composants dans un conteneur, sans avoir à toucher une seule ligne de moteur ou de code de script. Bien que je ne sois pas sûr que le codage de script puisse être évité, je veux le garder aussi simple que possible.

Pour résumer le tout: dois-je lober toute la logique de l'IA en un seul composant ou décomposer chaque état logique en composants séparés pour créer plus facilement des variantes d'entité?

edit : Je soupçonne qu'il y a une certaine confusion sur ce que je voulais dire avec la première et la deuxième situation. J'ai essayé de l'expliquer dans le diagramme ci-dessous.

Diagramme des composants

Notez la relation entre les états individuels et l'entité. Dans la première situation, un composant AI est pré-construit avant d'être mis dans l'entité. Un concepteur peut uniquement choisir parmi un ensemble distinct de composants AIC mis à disposition par le programmeur. La deuxième situation a les différents états au même niveau que les autres composants. Un concepteur peut désormais créer une entité avec une IA unique sans interférence d'un programmeur.

La question est, sont-ce les deux seules options pour structurer l'IA dans une entité basée sur des composants et, si oui, qu'est-ce qui donnerait la flexibilité maximale?

fantôme
la source
Je pense qu'une bonne réponse dépendra de l'endroit où vous souhaitez appliquer l'exclusivité des actions. Si vous voulez qu'il soit dans les objets eux-mêmes, la conception serait très différente par rapport à dire, en l'appliquant via l'interface de glisser-déposer (Cet état a déjà une action de mouvement donc il ne peut pas en avoir une autre, ce conteneur de transition d'état contient déjà un état final basé sur le temps, etc. ou autre).
James
2 n'est pas une option viable.
Coyote

Réponses:

6

Si vous avez l'intention d'avoir plus d'ennemis ou de joueurs possibles que vous ne pouvez pas imaginer en ce moment, alors vous devez absolument le casser. Ce que vous décrivez dans votre deuxième point est essentiellement le modèle d'état .

Je pense que je suis d'accord avec Gregory sur le fait que vous ne devriez pas avoir de composants d'état de marche et de stand séparés. C'est juste un composant de mouvement avec la vitesse 0. D'un autre côté, si vous avez des objets qui ne peuvent pas bouger, vous devez soit le diviser, soit simplement mettre une sorte de restriction booléenne dans l'état de mouvement qui empêche d'avoir une vitesse non nulle .

Pour le joueur, je ne pense pas que cela doive être complètement séparé. Il peut toujours utiliser tous les autres composants, avec l'ajout d'un composant d'entrée. Ce composant pilote les transitions entre les états, tandis que chez l'ennemi, il est contrôlé par une IA par défaut, ou si vous le souhaitez, différentes sous-classes d'IA parmi lesquelles vos concepteurs ennemis peuvent choisir.

modifier: en fait, pour vos ennemis stationnaires, plutôt que de restreindre le composant de mouvement, donnez-leur simplement un composant IA stationnaire qui ne choisit jamais de les déplacer.

Tesserex
la source
Un modèle d'état n'implique-t-il pas la première situation? Il en résulte un seul AIComponent implémentant une machine d'état contenant différents objets d'état. Ce que je voulais dire avec la deuxième option était que WalkComponent et SwingComponent sont du même type que, disons, RenderComponent et PhysicsComponent.
fantôme
@ghostonline En ce qui concerne l'idée, en quelque sorte. Dans la mise en œuvre, pas vraiment. AIComponent serait séparé, comme dans le deuxième diagramme. Il ne contiendrait pas les autres composants. La question la plus importante pour votre deuxième situation est la suivante: si le concepteur choisit simplement des composants sans programmeur, comment l'entité sait-elle quand changer d'état? Différents états impliquent des transitions d'état différentes - quelqu'un doit encore les spécifier.
Tesserex
Voulez-vous dire l'ajout d'un composant AIC à l'entité du diagramme 2, qui contrôlera le composant Stand / Walk / Swing-Component? Mon idée était que les composants envoient des signaux de blocage ou d'activation sous certaines conditions. Par exemple, SwingComponent émettrait des signaux génériques, par exemple le signal "bound_feet" au démarrage et "release_feet" à la fin du swing. WalkComponent se désactiverait et s'activerait en fonction de ces signaux. Parce que les «transitions d'état» sont encapsulées dans les composants eux-mêmes, le concepteur n'aura pas besoin d'un programmeur câblant les composants ensemble.
fantôme
@ghostonline Cela fonctionne bien pour les choses qui ont des règles fixes comme "ne peut pas marcher en se balançant", mais qu'en est-il des transitions entre la position debout et la marche? Si la position debout est en contrôle, comment saura-t-elle essayer de marcher? La logique debout peut vouloir choisir la marche ou le swing, ce qui est affecté par l'absence totale de capacité de marcher - elle doit toujours choisir de se balancer dans ce cas. Mais je pense que vous êtes sur la bonne voie.
Tesserex
2

Je garderais au moins Player AI (ou ce que j'appellerais Player Controller) comme son propre composant. Avec la plupart des jeux, le joueur est suffisamment différent des PNJ que vous ne pouvez pas généraliser de l'un à l'autre, sauf dans les bases comme les points de vie.

Pour les PNJ, je considère StandComponent et WalkComponent comme des aspects de la même chose. Allez-vous jamais avoir un WalkComponent sans StandComponent? J'en doute. De même, un RunComponent ne serait qu'un WalkComponent avec une vitesse plus élevée et des animations différentes. Je peux voir l'intérêt d'avoir un NPCMovementComponent et un NPCSwordFighterComponent séparé, mais même cela me semble être une ingénierie excessive.

Gregory Avery-Weir
la source
Je ne séparerais pas autant le mouvement des PNJ et le mouvement des joueurs. Les actions de mouvement qui animent les animations et la physique pourraient certainement être partagées; c'est ce qui sélectionne les actions ou les transitions qui sont différentes (le joueur prend les entrées tandis que l'IA est ... l'IA). Je suis d'accord que vous auriez un PlayerController, mais vous auriez également un AIController, qui pourraient tous deux utiliser des composants de mouvement / composants de swing pour faire le travail d'animation / physique réel.
homebrew
Vrai. Je suppose que tous les objets en mouvement ont un PhysicsComponent ou MovementComponent qui gère leur mouvement, et que le PlayerController et AIController l'utiliseraient pour gérer le mouvement. Le mouvement devrait certainement être un composant distinct, car il peut y avoir des choses qui doivent se déplacer qui n'ont pas d'IA ou qui ont l'IA la plus simple possible (objets physiques stupides comme des caisses ou des déchets).
Gregory Avery-Weir
2

D'abord, je créerais un composant d'état, puis je créerais une machine d'état pour gérer les transitions. Rendez-le suffisamment générique pour pouvoir l'utiliser pour vos joueurs et votre IA. Cela garantira que l'IA joue selon les mêmes règles et que vous n'avez pas à changer votre logique lorsque vous modifiez le fonctionnement des états du joueur par rapport aux états de l'IA.

Machine à états finis C ++

Ce qui précède a un exemple concret d'une machine d'état en c ++ qui peut être utilisée par les joueurs et l'IA.

Kyle C
la source
1

Ce que vous voulez, c'est un composant gérant le mouvement des personnages (joueur et PNJ). Le composant AI ou un composant joueur enverra des commandes à ce composant de mouvement et il vérifiera si l'action peut être lancée. Cela encapsulera vos contraintes de mouvement en un seul composant. Votre code AI et votre code joueur n'ont pas besoin de savoir comment l'épée swing est exécutée. L'IA aurait des états internes, par exemple inactif, attaquant, fuyant.

Stephen
la source
1
TYPO: "Il recevra ..." qu'en est-il du composant AI?
Pup