Personnages ennemis
Dans l'Unreal Engine, les PNJ et les ennemis sont généralement configurés de manière très similaire au joueur, en ce sens qu'un ennemi dispose d'un contrôleur et d'un pion. En fait, les ennemis et le joueur partagent certaines fonctionnalités dans une classe de base commune, AParrotCharacterBase. Pour le jeu Parrot, les arbres de comportement sont utilisés pour contrôler le comportement des ennemis ; la classe de contrôleur IA est donc utilisée pour créer nos contrôleurs d'ennemis. Nous commencerons par le blueprint d'animation, puisque cette configuration est commune à tous les ennemis.
Les blueprints d'animation des ennemis
Modèles de blueprint d'animation
Dans les cas où vous avez plusieurs maillages squelettiques qui ont des besoins d'animation identiques, vous pouvez créer ce que l'on appelle un modèle de blueprint d'animation (cf. Animation Blueprint Linking). Ici, il y a quatre types d'ennemis différents : un squelette sans tête, un squelette, un requin et un requin boss. Comme ils partagent tous un squelette et une configuration d'animation identiques, un modèle qui implémente le graphique d'animation et le graphique d'événements peut être réutilisé pour chacun d'entre eux. Vous pouvez voir comment ce modèle est configuré ici : Blueprints > Enemy > EnemyBase > ABT_EnemyBase. Il ressemble beaucoup au blueprint d'animation du joueur, car un modèle est configuré de la même manière que ce blueprint d'animation.
Blueprints d'animation
Dans ce cas, toute l'implémentation se trouve dans le modèle, alors que les animations elles-mêmes sont absentes, puisque le modèle ne fait pas référence à un squelette spécifique. Chacun des ennemis possède son propre blueprint d'animation dérivé du modèle, et les animations de ce squelette sont placées dans les remplacements du graphique d'animation. Vous pouvez en voir un exemple ici : Blueprints > Enemy > HeadlessSkeleton > ABP_Enemy_HeadlessSkeleton.
Ci-dessous, nous avons sélectionné les animations appropriées pour le maillage squelettique du squelette sans tête pour chaque état d'animation.
Le pion ennemi
Les personnages ennemis de Parrot partagent de nombreuses fonctionnalités avec le joueur, notamment les points de vie et les fonctions similaires (comme la mort). Cette implémentation partagée est visible dans AParrotCharacterBase. Pour l'implémentation spécifique à l'ennemi, nous disposons d'une sous-classe AParrotEnemyCharacterBase. Cela guide toute l'implémentation du fonctionnement du système de patrouille, du fonctionnement des combats, et plus encore. Vous pouvez en apprendre plus sur le fonctionnement des combats dans la documentation Les combats dans Parrot.
Dans cette configuration, les vérifications des coups et blessures de combat sont effectuées sur l'ennemi avec une implémentation sur la façon de déclencher les volumes dans la classe de base du blueprint qui se trouve ici : Blueprints > Enemy > EnemyBase > BP_EnemyCharacter_Base.
Cette implémentation est faite ici au lieu d'être gérée dans la classe C++ native, car les volumes de déclenchement doivent être différents pour chaque ennemi en raison des différentes formes, tailles et complexités de leurs maillages. Cela est nécessaire, car un volume de déclenchement hérité ne peut pas être modifié dans la classe dérivée.
Le contrôleur IA des ennemis
Comme indiqué précédemment, les ennemis sont contrôlés par des arbres de comportement. Il existe donc une classe de base dérivée de AIController dans AParrotEnemyAIControllerBase. Vous verrez ici une variété de BlueprintImplementableEvents utilisée pour envoyer des données au tableau noir afin qu'elles soient utilisées par les arbres de comportement.
Vous pouvez voir comment le contrôleur IA transmet les données dans l'arbre de comportement et comment il gère la détection de la présence des joueurs dans Blueprints > AI > EnemyBase > BP_EnemyController_Base.
Créer une IA avec les arbres de comportement
L'Unreal Engine offre une infrastructure puissante et flexible pour la création d'IA à l'aide d'arbres de comportement. Un guide de démarrage rapide pour configurer le modèle de base avec quelques comportements est disponible dans le Behavior Tree Quick Start Guide. Les résultats de ce guide sont utilisés comme base pour l'IA ennemie et pour apporter des modifications afin de configurer les comportements nécessaires.
Nous avons deux tâches de l'arbre de comportement, Blueprints > AI > EnemyBase > BTT_FindNextPatrol et Blueprints > AI > EnemyBase > BTT_AttackPlayerpour fournir les fonctionnalités de base nécessaires à la patrouille et à l'attaque du joueur. Il y a un unique tableau noir partagé, Blueprints > AI > EnemyBase > BB_Enemy_Base, puisque l'infrastructure permettant de prendre en charge toutes les fonctionnalités est présente dans chaque ennemi. Il appartient à l'implémentation de l'arbre de comportement de décider des fonctionnalités à utiliser pour personnaliser les comportements des ennemis.
Chacun des ennemis a une configuration différente de l'arbre de comportement, de sorte que chacun d'entre eux se comporte d'une manière différente. Vous pouvez découvrir les quatre variations aux endroits suivants :
Blueprints> AI > HeadlessSkeleton > BT_HeadlessSkeleton
Blueprints > AI/Skeleton > BT_Skeleton
Blueprints > AI > Sharky > BT_Sharky
Blueprints > AI > BossShark > BT_Boss_Shark
Création d'un système de points de passage de patrouille modifiables
Pour les ennemis, Parrot ne souhaite pas utiliser le même comportement de patrouille que celui démontré dans le guide de l'arbre de comportement, dans lequel l'IA ennemie sélectionne aléatoirement un point atteignable dans un rayon autour d'elle toutes les 4 secondes. Ce que l'on veut, ce sont des ennemis qui suivent activement un parcours de patrouille dans un sens ou dans l'autre, comme dans beaucoup d'autres jeux de plateforme.
Pour cela, Parrot a créé son propre système qui offre les fonctionnalités nécessaires. Il s'agit de UParrotEnemyPatrolRigComponent, qui peut être placé dans la scène pour créer une patrouille. Il utilise les sous-objets par défaut de la classe pour instancier une spline. La spline est utilisée pour créer les points de passage de la patrouille, deux volumes de déclenchement (utilisés pour déclencher le comportement de l'IA) et une visionneuse réservée à l'éditeur qui dessine l'ordre des points de passage. L'ordre des points de passage permet de voir la direction du trajet de la patrouille au moment de l'édition. Vous pouvez voir les détails de l'implémentation C++ dans UParrotEnemyPatrolRigComponent.
Cette implémentation est un composant, ce qui permet d'attacher un squelette de patrouille à n'importe quel acteur d'une scène. Cela permet de placer un squelette sur un objet en déplacement et de s'assurer que la patrouille reste correctement placée dans l'espace local. Pour placer un squelette de patrouille qui n'est pas attaché à un acteur existant dans une scène, nous avons AParrotEnemyPatrolRigActor, qui est un acteur que vous pouvez placer n'importe où dans une scène et qui fait apparaître UParrotEnemyPatrolRigComponent comme sous-objet par défaut sur lui-même.
Cette implémentation permet de sélectionner un ennemi à faire apparaître pendant l'exécution qui suivra le chemin de patrouille. Ce processus utilise une fonctionnalité de l'Unreal Engine appelée apparition d'acteur différée, qui permet de faire apparaître un acteur en deux étapes : la première crée l'objet d'acteur sans effectuer d'action d'initialisation de l'acteur, comme BeginPlay. Cela vous donne la possibilité d'effectuer toute configuration ou tout paramétrage nécessaire à l'acteur avant qu'il soit initialisé. Après avoir effectué cette configuration, vous invoquez la deuxième étape pour finaliser l'apparition et initialiser l'acteur. Cela est effectué pour le squelette de patrouille afin que, lorsque l'acteur ennemi apparaît, la spline de patrouille et les volumes de déclenchement puissent être configurés dans l'acteur afin d'être traités lors de l'initialisation de l'acteur, permettant à la séquence de patrouille de commencer automatiquement.
Vous pouvez voir le code de l'apparition d'acteur différée dans UParrotEnemyPatrolRigComponent. Une fonctionnalité similaire existe dans les blueprints, où vous pouvez baliser les propriétés d'un acteur de blueprint comme Expose on Spawn, ce qui vous permet de passer des arguments dans le nœud de blueprint d'apparition, qui sont définis avant que l'initialisation de l'acteur ait lieu.
L'image ci-dessous montre un exemple de la manière dont l'un de ces squelettes de patrouille est configuré dans Maps > Level_1 > Level_1 avec un squelette de patrouille à deux points, démarrant au point 0 sur la droite. Ce squelette de patrouille est configuré pour faire apparaître un BP_EnemyCharacter_Skeleton.
En dessous, un menu Indicateur d'affichage permet d'identifier les points de passage des squelettes de patrouille pour faciliter leur identification au moment de l'édition. La plupart des cases Indicateur d'affichage ont été sélectionnées. Vous pouvez voir les détails de l'implémentation dans un composant de visionneuse exclusif à l'éditeur, UParrotPatrolRigDebugVisualizer.