Comment câbler une machine à états finis dans une architecture basée sur des composants? [fermé]

23

Les machines à états semblent provoquer des dépendances nuisibles dans les architectures basées sur les composants.

Comment, en particulier, la communication est-elle gérée entre une machine d'état et les composants qui exécutent un comportement lié à l'état?

Où je suis:

  • Je suis nouveau dans les architectures basées sur les composants.
  • Je fais un jeu de combat, même si je ne pense pas que cela devrait avoir d'importance. J'imagine que ma machine à états est utilisée pour basculer des états comme "accroupi", "fringant", "bloquant", etc.
  • J'ai trouvé que cette technique de gestion d'état est le système le plus naturel pour une architecture basée sur des composants, mais elle entre en conflit avec les techniques que j'ai lues: Système de composants d'objet de jeu dynamique pour les personnages à comportement mutable Il suggère que tous les composants s'activent / se désactivent eux-mêmes en vérifiant continuellement une condition d'activation.
  • Je pense que des actions comme "courir" ou "marcher" ont un sens en tant qu'états, ce qui est en désaccord avec la réponse acceptée ici: /gamedev//a/7934
  • J'ai trouvé cela utile, mais ambigu: comment implémenter un comportement dans une architecture de jeu basée sur des composants? Il suggère d'avoir un composant séparé qui ne contient rien d'autre qu'une machine à états. Mais cela nécessite une sorte de couplage entre le composant de la machine d'état et presque tous les autres composants. Je ne comprends pas comment ce couplage doit être géré. Ce sont quelques suppositions:

    A. Les composants dépendent de la machine à états: les
    composants reçoivent une référence aux composants de la machine à états getState(), qui renvoie une constante d'énumération. Les composants se mettent à jour régulièrement et vérifient cela au besoin.

    B. La machine d'état dépend des composants:
    le composant de la machine d'état reçoit des références à tous les composants qu'il surveille. Il interroge leurs getState()méthodes pour voir où elles en sont.

    C. Une certaine abstraction entre eux
    Utiliser un hub d'événements? Modèle de commande?

    D. Des objets d'état distincts qui font référence aux composants
    du modèle d'état sont utilisés. Des objets d'état distincts sont créés, qui activent / désactivent un ensemble de composants. La machine d'état bascule entre les objets d'état.

  • Je regarde les composants comme des implémentations d' aspects . Ils font tout ce qui est nécessaire en interne pour que cet aspect se produise. Il semble que les composants devraient fonctionner seuls, sans dépendre d'autres composants. Je sais que certaines dépendances sont nécessaires, mais les machines d'état semblent vouloir contrôler tous mes composants.

Chiot
la source

Réponses:

7

La vue d'ensemble est assez légère, mais regardez ces diapositives d'une présentation que j'ai faite pour New Game Conf l'année dernière:

https://docs.google.com/presentation/d/110MxOqut_y7KOW1pNwIdcccisIA3ooJwVR-xm-ecuc4/view

(voir les images pertinentes ci-dessous)

L'essentiel de la technique est de combiner le modèle de liste d'actions (expliqué - un peu mal - dans les diapositives) avec des machines à états comportementales qui agissent sur une entité de jeu basée sur des composants.

Cela revient essentiellement à créer un système de composition spécial uniquement pour le comportement de l'IA, orienté vers les types d'intégration inter-comportementale dont vous avez besoin pour des systèmes d'IA plus simples.

Ma partie préférée de ce jeu particulier était de savoir comment nous pouvions créer des types d'ennemis entièrement nouveaux en sélectionnant simplement dans une liste de comportements pré-écrits, en les mettant dans la liste d'actions de l'objet de jeu (résidant dans un composant BrainComponent) dans l'ordre souhaité. priorité, et tout a fonctionné. Avec une liste d'actions qui permet des actions de blocage / non blocage, cela peut faire des choses vraiment cool malgré la simplicité de mise en œuvre.

Même des comportements comme "étourdir" où vraiment juste un StunBehaviorAction poussé en haut de la pile de liste d'actions; si le comportement d'étourdissement est activé (après avoir observé que le composant EarsComponent de l'objet de jeu a entendu une superbe attaque par onde de choc), il a défini son état interne sur Stunned, a dit à AnimationComponent de jouer l'animation d'étourdissement, et défini son état d'action sur Blocking, et son chronomètre sur un délai d'étourdissement extrait du composant EnemyParametersComponent de l'objet de jeu. Puisqu'il était bloquant et en haut de la liste d'actions, aucun des autres BehaviorAction de la liste d'actions ne recevrait sa méthode de mise à jour appelée, ils seraient donc essentiellement désactivés. Lorsque le délai a expiré, le StunBehaviorAction a redéfini son état sur Inactif et son état d'action sur NonBlocking.

Les autres comportements que nous avons implémentés ont été presque tous implémentés avec une seule machine d'état interne. Les deux seuls qui n'avaient pas de machines d'état, en fait, étaient le PatrolPathBehaviorAction (il pousserait une série de PathAction sur la liste d'actions s'il était inactif, ce qui poussait à son tour MoveAction) et le GuardHomeBehaviorAction (toujours au bas de la liste d'actions, et repousserait toujours une PathAction à l'emplacement d'origine de l'ennemi). Tout autre comportement était une machine d'état.

Diapo 10 Diapo 25 Diapo 26

Sean Middleditch
la source
Quelle est la différence fondamentale entre "Comportements" et "Actions"?
Pup
1
@Pup: Du point de vue du code, tel que je l'ai construit, un comportement est une action. D'un point de vue conceptuel, les actions sont généralement transitoires - elles n'existent que jusqu'à ce qu'elles soient «terminées» - tandis que les comportements sont éternels et ne sont jamais supprimés de la liste. J'ai vu une autre équipe construire un système similaire mais avec deux listes, une pour les actions et l'autre pour les comportements, ce qui fonctionne assez bien. J'aime avoir la possibilité pour une action de bloquer certains comportements, cependant, en utilisant les masques de bit et le regroupement (voies, je crois que je les ai appelés dans les diapositives). Désolé, le graphique de la diapositive du milieu est si mauvais. :)
Sean Middleditch
3

Dans une entreprise précédente, je travaillais pour un système basé sur des composants avec une IA basée sur l'état. Nous avions un composant AI qui contrôlait tous les comportements de cet objet / unité. Lorsque l'IA était active, comme l'errance, l'attaque, etc., elle recevrait une mise à jour à chaque trame pour faire la logique nécessaire. Lorsque l'IA était au ralenti ou ne se déplaçait pas, le composant était désactivé et n'était pas mis à jour à chaque image. Le composant, bien que désactivé, pourrait toujours recevoir des messages basés sur des événements, il recevrait donc un message pour quelque chose comme un joueur entrant dans son rayon d'aggro, et pourrait répondre à cela en réactivant le composant AI afin qu'il puisse faire des mises à jour basées sur des trames.

Le composant AI a des sous-composants, qu'il pourrait créer et détruire à la volée, en fonction du type d'actions qu'il effectuait. Par exemple, s'il errait, il pourrait créer un sous-composant errant et mettre à jour chaque image pendant l'errance, puis s'il était agressé pendant l'errance, il fermerait ce sous-composant et ouvrirait un sous-composant d'attaque. Le composant AI doit être indépendant de tous les autres composants d'un objet. Par exemple, nous avions un composant d'entrée, qui demandait simplement les valeurs de mouvement sur une unité. La requête qu'il a faite était quelque chose à laquelle les objets humains et IA répondraient. Cela a permis au composant AI de simplement définir des valeurs de mouvement sur lui-même pendant des choses comme l'errance, que le composant d'entrée pourrait capter, tout comme un composant contrôlable par l'homme définirait des valeurs que le composant d'entrée pourrait capter.

Nic Foster
la source
Alors, les sous-composants de l'IA font vraiment le travail? Existaient-ils en tant que composants d'entité, au même niveau que le composant AI?
Pup
Les sous-composants de notre moteur faisaient partie de la classe des composants de base. Donc, n'importe Componentqui, qui en dérive BaseComponent, pourrait avoir n'importe quel nombre de SubComponents dessus. La Update()méthode dans BaseComponentvérifierait la liste des sous-composants et les invoquerait Update(). Subcomponentsétaient entièrement facultative si la BaseComponentpuissance a pas. En outre, tous les messages envoyés à un composant ont également été acheminés vers les sous-composants.
Nic Foster
1

On ne sait pas trop ce que vous entendez par composants, car vos termes sont très vagues, sans exemples concrets. Souvent, les entités de jeu sont construites en utilisant la composition plutôt que l'héritage. Ainsi, vous pouvez les transformer en quelque chose qui peut subir des dommages en ajoutant un composant de santé à l'entité ou vous pouvez les rendre animés en ajoutant un composant animé. On pourrait également mettre l'IA dans un tel composant. Il y aura une logique de prise de décision dans votre composant AI et si vous êtes soucieux de le coupler à la plupart des autres codes du système, vous pouvez collecter les informations dans un tableau noir auquel la logique AI n'est autorisée qu'à accéder. Il y a aussi le problème des dépendances sur la sortie du système AI. Fondamentalement, votre IA contrôle une entité et ce contrôle a besoin d'une interface. Un concept utile est celui d'un contrôleur ou d'une manette de jeu. Votre IA peut remplir une structure similaire à celle d'une manette de jeu pour joueur (bien qu'elle puisse avoir des "boutons" supplémentaires pour des capacités spécifiques). Maintenant, cette structure pourrait ensuite être transmise à votre composant d'animation qui l'interpréterait et sélectionnerait les animations appropriées à jouer. Différents sous-composants de l'IA pourraient même écrire dans différents champs de la structure ou dans les mêmes champs avec des priorités différentes. Viser et marcher par exemple. Différents sous-composants de l'IA pourraient même écrire dans différents champs de la structure ou dans les mêmes champs avec des priorités différentes. Viser et marcher par exemple. Différents sous-composants de l'IA pourraient même écrire dans différents champs de la structure ou dans les mêmes champs avec des priorités différentes. Viser et marcher par exemple.

Jesse Cluff
la source