top of page

Créer des PNJ dans Ordalie : comportement, perception et optimisation :

18 sept.
8 min de lecture

Pour rendre l’univers d’Ordalie plus vivant, il fallait tôt ou tard donner au joueur la possibilité d’interagir avec autre chose que son environnement. Les PNJ sont donc rapidement devenus une composante essentielle du projet : des personnages capables de se déplacer, d’observer leur environnement, de réagir aux événements et, à terme, de participer pleinement à la vie du monde.

La création de ces personnages m’a cependant rapidement amené à une problématique plus large que celle de simplement « faire bouger une IA ». Je devais concevoir un système capable de gérer un grand nombre de PNJ tout en restant suffisamment flexible pour pouvoir faire évoluer leurs caractéristiques, leurs comportements et leurs interactions sans devoir reconstruire chaque personnage individuellement.


Comprendre les outils natifs d'Unreal Engine

J'ai commencé par explorer les différentes solutions natives proposées par Unreal Engine 5 pour la création d'IA. Cela m'a notamment amené à travailler avec des outils comme le Behavior Tree, Blackboards et le AI Controllers, mais aussi à mieux comprendre les relations entre l'Actor représentant le PNJ et le système d'intelligence artificielle qui le contrôle.

L'un des premiers objectifs était de comprendre comment ces différents éléments communiquent entre eux. Quelles informations doivent être transmises ? À quel moment ? Par quel système ? Et surtout, comment éviter de multiplier inutilement les échanges et les calculs ?

Cette réflexion était importante car mon objectif n'était pas simplement de créer quelques PNJ fonctionnels. Je souhaite à terme pouvoir peupler l'univers d'Ordalie avec un nombre important de personnages sans que chacun d'entre eux ne devienne une charge trop importante pour les performances du jeu.

Il fallait donc réfléchir dès le départ à l'architecture du système.


Une interface pour centraliser la complexité

C'est en travaillant sur les PNJ que je me suis rapidement rendu compte d'un autre problème : la quantité d'informations à gérer.

Un PNJ ne se résume pas à son modèle 3D et à quelques statistiques. Il possède des caractéristiques propres, des statistiques, des comportements, des paramètres de perception, des informations visuelles et de nombreuses autres données qui peuvent rapidement devenir difficiles à organiser.

J'ai donc créé une interface personnalisée directement dans Unreal Editor à l'aide de l'outil Editor Utility Widget.

L'objectif est de disposer d'un outil évolutif permettant de centraliser et de manipuler plus facilement l'ensemble des données associées à un PNJ. Plutôt que de devoir parcourir différents systèmes et propriétés dans l'éditeur, je peux progressivement regrouper ces informations au sein d'une même interface.

Cette approche me permet surtout de mieux contrôler la complexité du système à mesure qu'il évolue.


Un Behavior Tree pour les gouverner tous

L'une des difficultés majeures est rapidement devenue évidente : les Behavior Trees peuvent devenir extrêmement complexes lorsque l'on cherche à gérer de nombreux comportements différents.

Mon objectif n'était pas de créer un Behavior Tree spécifique pour chaque PNJ. Cette solution aurait rapidement conduit à une multiplication des arbres et à une maintenance particulièrement difficile.

Je voulais au contraire retrouver une logique proche de la programmation orientée objet : construire des systèmes génériques, réutilisables et facilement applicables à différents personnages.

L'idée est donc de disposer d'un ensemble de comportements modulaires pouvant être combinés et configurés en fonction du PNJ.


Des comportements de déplacement modulaires

J'ai commencé par lister les différents comportements de déplacement dont l'IA pourrait avoir besoin :

  • Suivre une trajectoire

  • Patrouiller autour d'une zone

  • Se déplacer vers une position donnée

  • Rester dans une zone

  • Poursuivre une cible

  • Et progressivement, d'autres comportements plus spécifiques.

Ces comportements ne sont pas simplement exécutés les uns après les autres. Ils possèdent également des priorités afin de déterminer lequel doit prendre le dessus lorsqu'une situation particulière survient.

Cette organisation permet de construire des comportements plus complexes à partir de briques relativement simples.




Penser l'optimisation dès la conception

Cette approche modulaire m'a également confronté à une problématique essentielle : l'optimisation.

Lorsqu'un PNJ possède de nombreux systèmes différents, il est facile de laisser fonctionner en permanence des composants dont il n'a pas besoin.

Or, si mon objectif est de pouvoir avoir un monde peuplé de nombreux PNJ, chaque ressource économisée sur un personnage peut devenir importante lorsqu'elle est multipliée par plusieurs dizaines, voire plusieurs centaines d'instances.

J'ai donc commencé à réfléchir à une logique de compartimentation des ressources.

Si un PNJ utilise un comportement particulier, les systèmes nécessaires à ce comportement sont activés, tandis que les modules inutilisés ne doivent pas continuer à consommer inutilement des ressources.

Cette philosophie m'a progressivement poussé à repenser la manière dont je concevais les comportements de déplacement : plutôt que d'avoir une IA qui fait constamment tourner l'ensemble de ses systèmes, je cherche à faire en sorte que chaque PNJ n'utilise réellement que ce dont il a besoin.

L'objectif est simple : réduire le travail effectué par chaque IA afin de pouvoir en faire fonctionner davantage simultanément.


Donner des sens aux PNJ

Une fois les premiers systèmes de déplacement mis en place, je me suis intéressé à une question beaucoup plus importante pour rendre les PNJ crédibles :

Comment peuvent-ils intéragir avec ce qui se passe autour d'eux ?

Pour qu'une IA puisse réagir correctement au joueur, elle doit d'abord être capable de percevoir sa présence.

Je me suis donc naturellement tourné vers les systèmes de perception proposés nativement par Unreal Engine, notamment pour permettre à l'IA de détecter un personnage à travers différents sens.

L'idée était ensuite de transmettre ces informations au Behavior Tree afin d'adapter le comportement du PNJ en fonction de la situation.

Un même personnage pourrait ainsi avoir des réactions différentes selon son état : agressif, neutre, passif, méfiant, etc.

Pourquoi ne pas utiliser directement AI Perception ?

Le système AI Perception d'Unreal Engine constitue une solution intéressante, mais il ne correspondait pas complètement à mes besoins.

Dans mon cas, son utilisation complète m'aurait notamment amené à mélanger du C++ et du Blueprint, certains paramètres n'étant pas directement accessibles comme je le souhaitais dans Blueprint.

Au-delà de cette limitation, c'est surtout la philosophie générale du système qui ne correspondait pas totalement à l'architecture que j'étais en train de construire.

AI Perception est pensé comme un système relativement généraliste pouvant fonctionner avec différents modules et différents types de perception. Or, je n'avais pas nécessairement besoin de l'ensemble de cette architecture.

Plutôt que de remettre en question tout ce que j'avais déjà construit, j'ai donc choisi une autre approche :

concevoir mon propre système de perception.

Je me suis inspiré du fonctionnement général d'AI Perception tout en construisant un système adapté aux besoins spécifiques d'Ordalie, avec une attention particulière portée à la simplicité, à la modularité et aux performances.


Un système de vision personnalisé

Le premier sens que j'ai développé est naturellement la vision.

Le principe est relativement simple : lorsqu'un acteur entre dans le champ de vision d'un PNJ, une vérification est effectuée afin de déterminer si celui-ci peut réellement être vu.

Pour cela, mon système utilise notamment un lancé de rayon (raycast) permettant de vérifier la visibilité réelle de la cible.

Il ne suffit donc pas qu'un joueur se trouve dans le champ de vision théorique du PNJ : un obstacle peut empêcher la détection.

Cette information est ensuite transmise au système comportemental afin que le PNJ puisse adapter sa réaction.

Cela permet par exemple de faire la distinction entre un joueur réellement visible et un joueur situé derrière un obstacle.



La vision ne sert pas uniquement à détecter

Le système de vision peut également servir à alimenter d'autres éléments du comportement du personnage.

Certaines animations sont directement liées à la perception. Par exemple, lorsqu'un PNJ détecte le joueur, sa tête peut progressivement s'orienter vers celui-ci.

Ce genre de détail peut sembler secondaire, mais il contribue énormément à donner l'impression que le personnage observe réellement son environnement, plutôt que de simplement recevoir une information abstraite provenant du jeu.


Entendre le monde qui l'entoure

Après la vision, je me suis intéressé à un autre sens particulièrement important : l'ouïe.

L'objectif de mon système sonore est de permettre aux PNJ d'être attentifs aux sons qui les entourent, tout en évitant de faire subir ce traitement à des personnages qui n'en ont pas besoin.

Chaque PNJ peut donc disposer ou non d'un module de détection sonore.

Cela permet une nouvelle fois de conserver une architecture modulaire : tous les personnages n'ont pas nécessairement les mêmes capacités perceptives.


Une sensibilité propre à chaque PNJ

La perception sonore ne repose pas uniquement sur la présence ou l'absence d'un son.

J'ai également intégré des paramètres permettant de définir la sensibilité de chaque IA.

Ainsi, deux PNJ peuvent être exposés exactement au même événement sonore tout en réagissant différemment.

Un personnage particulièrement attentif pourra détecter des sons faibles ou éloignés, tandis qu'un autre pourra être beaucoup moins sensible.

Cette approche permet de donner à chaque PNJ une perception qui lui est propre et d'éviter que toutes les créatures du monde réagissent exactement de la même manière.


La propagation du son dans l'environnement

Je voulais également éviter de considérer le son comme une simple information qui se déplace instantanément d'un point A à un point B.

Dans le monde d'Ordalie, l'environnement doit pouvoir modifier la propagation des sons.

Lorsqu'un son est émis, mon système cherche donc à déterminer quels PNJ sont susceptibles de l'entendre et comment le son se propage jusqu'à eux.

Les différents obstacles rencontrés sur son chemin peuvent alors influencer cette propagation.

Un mur, une porte ou une autre surface peut atténuer le son. Plus celui-ci traverse de surfaces et d'obstacles, plus son intensité diminue et plus il devient difficile pour une IA de le percevoir.

L'absorption sonore des matériaux devient donc elle aussi un paramètre configurable.

Un mur en pierre ne devrait évidemment pas se comporter de la même manière qu'une surface en tissu. Cette distinction permet progressivement de construire un environnement dans lequel les matériaux ont également une influence sur les systèmes de perception des PNJ.



Relier tous ces systèmes au comportement de l'IA

L'ensemble de ces modules n'a réellement d'intérêt que s'ils peuvent communiquer entre eux.

La vision, l'ouïe, les déplacements et les différents états du PNJ doivent donc fonctionner conjointement avec le Behavior Tree.

Le Behavior Tree devient ainsi une sorte de point de décision : les différents systèmes lui fournissent des informations sur l'environnement et le PNJ peut adapter son comportement en conséquence.

Un bruit peut attirer son attention.

Une silhouette peut être détectée.

Une cible peut disparaître derrière un mur.

Un événement peut modifier son état.

Et toutes ces informations peuvent progressivement influencer les décisions prises par l'IA.

L'objectif n'est donc pas de créer une intelligence artificielle capable de tout faire seule, mais plutôt de construire un ensemble de systèmes spécialisés capables de fonctionner ensemble.


Construire les fondations d'un monde vivant

La création des PNJ d'Ordalie est donc devenue un projet beaucoup plus large que la simple programmation de personnages capables de se déplacer.

Il s'agit aujourd'hui de construire une véritable architecture permettant de gérer leurs caractéristiques, leurs comportements, leurs perceptions et leurs interactions avec le monde.

L'approche modulaire me permet également de garder une certaine liberté pour la suite du développement. De nouveaux comportements pourront être ajoutés, de nouveaux sens pourront être développés et les paramètres propres à chaque PNJ pourront continuer à évoluer sans remettre en question l'ensemble du système.

L'un des principaux défis restera évidemment l'optimisation. Plus le monde sera peuplé, plus chaque système devra être pensé pour limiter son coût individuel afin que l'accumulation de dizaines ou de centaines d'IA reste compatible avec les performances du jeu.

Mais c'est justement cette contrainte qui rend la conception intéressante.

Petit à petit, ces différents outils commencent à former les fondations du système de population d'Ordalie. Ils évolueront encore au fil du développement, avec l'objectif de créer un monde peuplé de créatures capables d'observer, d'entendre, de se déplacer et surtout de réagir à ce qui les entoure.

Et c'est finalement cette combinaison de petits systèmes qui permettra, je l'espère, de donner au monde d'Ordalie cette impression de vie que je recherche depuis le début du projet.


Merci d'avoir pris le temps de suivre l'avancée du développement d'Ordalie et de découvrir les coulisses de la création de ses PNJ.

Le développement continue, et ces différents systèmes évolueront encore au fil du projet. J'ai hâte de pouvoir montrer comment ces fondations vont progressivement donner vie au monde d'Ordalie.

À bientôt pour la suite du développement ! ;D

Commentaires


bottom of page