Suivre le chemin et contrôler le trafic
Parfois, nous avons besoin de personnages IA pour parcourir le monde du jeu, en suivant un chemin à peu près défini ou défini avec précision. Par exemple, dans un jeu de course, les adversaires de l'IA doivent se déplacer le long de la route, et dans le RTS, les unités doivent pouvoir se déplacer jusqu'au point souhaité, se déplacer le long du terrain et en tenant compte de la position de l'autre.
Pour paraître intelligents, les agents de l'IA doivent être en mesure de déterminer ce qu'ils font et s'ils ne peuvent pas atteindre le point souhaité, ils doivent être en mesure de tracer l'itinéraire le plus efficace et de changer de trajectoire lorsque des obstacles apparaissent sur le chemin.
Éviter les obstacles est un comportement simple qui permet aux entités IA d'atteindre les points cibles. Il est important de noter que le comportement mis en œuvre dans ce post concerne des comportements tels que la simulation de foule, dans lesquels l'objectif principal de chaque agent est d'éviter d'autres agents et d'atteindre l'objectif. Ils ne déterminent pas le chemin le plus efficace et le plus court.
Exigences techniques
Nécessite Unity 2017 installé sur un système équipé de Windows 7 SP1 +, 8, 10 ou Mac OS X 10.9+. Le code de cet article ne fonctionnera pas sur Windows XP et Vista, et les versions serveur de Windows et OS X n'ont pas été testées.
Les fichiers de code pour cet article peuvent être trouvés sur
GitHub .
Pour apprendre le code en action, regardez
cette vidéo .
Maillage de navigation
Voyons comment utiliser le générateur de maillage de navigation Unity intégré, qui peut grandement simplifier la recherche de chemins pour les agents AI. Dans les premiers stades d'Unity 5.x, la fonction NavMesh est devenue accessible à tous les utilisateurs, y compris ceux disposant de licences d'édition personnelle, bien qu'elle ne l'était auparavant que pour Unity Pro. Avant la sortie de 2017.1, le système a été mis à jour pour fournir un flux de travail basé sur les composants, mais comme il nécessite un package téléchargeable supplémentaire, qui au moment de la rédaction n'est disponible que dans la version d'aperçu, nous respecterons le flux de travail basé sur une scène standard. Ne vous inquiétez pas, les concepts des deux approches sont similaires et lorsque l'implémentation finale atteint finalement 2017.x, il ne devrait pas y avoir de changements significatifs.
En savoir plus sur le système de composants NavMesh dans Unity sur
GitHub .
Nous allons maintenant explorer toutes les possibilités que ce système peut nous offrir. Pour rechercher des chemins AI, la scène doit être présentée dans un format spécifique; sur une carte 2D, une grille bidimensionnelle (tableau) est utilisée pour rechercher des chemins à l'aide de l'algorithme A *. Les agents de l'IA doivent savoir où se trouvent les obstacles, en particulier les obstacles statiques. La gestion des collisions entre des objets en mouvement dynamique est un autre problème communément appelé comportement de direction. Unity dispose d'un outil intégré pour générer NavMesh, représentant la scène dans un contexte pratique pour que les agents IA trouvent le chemin optimal vers la cible. Pour commencer, ouvrez un projet de démonstration et accédez à la scène NavMesh.
Carte d'étude
Après avoir ouvert la scène de démonstration NavMesh, cela devrait ressembler à la capture d'écran:
Scène d'obstacle et de penteCe sera notre bac à sable pour expliquer et tester la fonctionnalité du système NavMesh. Le schéma général est similaire à un jeu dans le genre de RTS (stratégie en temps réel). Nous conduisons un char bleu. Cliquez sur différents points pour que le char se déplace vers eux. L'indicateur jaune est la cible actuelle du réservoir.
Navigation statique
Tout d'abord, vous devez dire que vous devez marquer toute la géométrie de la scène, cuite dans NavMesh, comme
navigation statique . Vous l'avez peut-être déjà vu, par exemple, dans le système de carte d'éclairage Unity. Pour rendre les objets de jeu statiques est très simple, il suffit de cocher la case
Statique pour toutes leurs propriétés (navigation, éclairage, élimination, traitement par lots, etc.), ou utilisez la liste déroulante pour spécifier les propriétés. La case à cocher est située dans le coin supérieur droit de l'inspecteur des objets sélectionnés.
Navigation de propriété statiqueCela peut être fait individuellement pour différents objets ou, si vous avez une hiérarchie intégrée d'objets de jeu, appliquez le paramètre à l'objet parent, après quoi Unity proposera de l'appliquer à tous les objets enfants.
Rôtir un maillage de navigation
Pour la scène entière, les options de navigation navmesh sont appliquées à l'aide de la fenêtre de
navigation . Cette fenêtre peut être ouverte en allant dans
Fenêtre |
La navigation Comme toute autre fenêtre, elle peut être déconnectée pour une liberté de mouvement ou fixée. Dans nos captures d'écran, il est affiché sous la forme d'un onglet ancré à côté de la hiérarchie, mais vous pouvez placer cette fenêtre à n'importe quel endroit pratique.
En ouvrant la fenêtre, vous verrez des onglets individuels. Cela ressemblera à ceci:
Fenêtre de navigationDans notre cas, la capture d'écran précédente montre l'onglet
Bake , mais dans votre éditeur, n'importe quel onglet peut être sélectionné par défaut.
Regardons chacun des onglets, en commençant par la gauche et en se déplaçant vers la droite. Commençons par l'onglet
Agents , qui ressemble à la capture d'écran:
Onglet AgentsSi vous travaillez sur un autre projet, vous pouvez constater que certains paramètres sont différents de ceux que nous avons définis pour l'exemple de projet illustré dans la capture d'écran. En haut de l'onglet, il y a une liste où vous pouvez ajouter de nouveaux types d'agents en cliquant sur le bouton
+ . Vous pouvez supprimer des agents supplémentaires en les sélectionnant et en cliquant sur le bouton
- . La fenêtre montre clairement ce que font les différents paramètres lors de leur modification. Voyons ce que fait chacun des paramètres:
- Nom: nom du type d'agent affiché dans la liste déroulante Types d'agent.
- Rayon: Vous pouvez le considérer comme «l'espace personnel» d'un agent. Les agents tenteront d'éviter un contact trop étroit avec d'autres agents sur la base de cette valeur, car elle est utilisée à des fins d'évitement.
- Hauteur: comme vous pouvez le deviner, ce paramètre définit la hauteur de l'agent qu'il utilise pour l'évitement vertical (par exemple, lors du passage sous des objets).
- Hauteur de marche: cette valeur détermine la hauteur que l'agent peut grimper.
- Pente maximale: comme nous le verrons dans la section suivante, cette valeur détermine l'angle maximal auquel l'agent peut monter. En utilisant ce paramètre, vous pouvez rendre les pentes abruptes de la carte inaccessibles à l'agent.
Ensuite, nous avons l'onglet
Zones , qui ressemble à celui montré dans cette capture d'écran:
Comme vous pouvez le voir sur la capture d'écran, Unity propose plusieurs types de zones qui ne peuvent pas être modifiées:
Walkable ,
Not Walkable et
Jump . En plus de nommer et de créer de nouvelles zones, vous pouvez attribuer à ces zones le coût de leur déplacement.
Les zones ont deux objectifs: rendre les zones accessibles ou inaccessibles à l'agent et marquer les zones comme moins souhaitables en termes de frais de déplacement. Par exemple, vous pouvez développer un RPG dans lequel les ennemis démoniaques ne peuvent pas entrer dans les zones marquées comme «terrain consacré». Vous pouvez également marquer certaines zones de la carte comme un «bourbier» ou un «marais», ce que l'agent évitera en raison du coût élevé du déplacement.
Le troisième onglet
Bake est probablement le plus important. Il vous permet de créer NavMesh lui-même pour la scène. Vous devez déjà être familiarisé avec certaines des options. L'onglet
Bake ressemble à ceci:
Onglet de cuissonLes options de taille d'agent de cet onglet déterminent la manière dont les agents interagiront avec l'environnement, tandis que les options de l'onglet
Agents contrôlent les interactions avec d'autres agents et objets en mouvement. Mais ils contrôlent les mêmes paramètres, nous allons donc les ignorer.
La hauteur de chute et la
distance de saut contrôlent jusqu'où l'agent peut «sauter» pour atteindre la partie de NavMesh qui n'est pas directement liée à celle dans laquelle l'agent se trouve actuellement. Nous examinerons cela plus en détail ci-dessous, donc si vous n'êtes pas sûr, vous ne pourrez toujours pas étudier ces paramètres.
De plus, il existe des options avancées qui sont généralement masquées par défaut. Pour développer ces options, cliquez simplement sur le triangle déroulant à côté de l'en-tête
Avancé .
La taille manuelle du Voxel peut être considérée comme un paramètre de «qualité». Plus la taille est petite, plus les détails seront stockés dans le maillage.
La zone de région minimale est utilisée pour ignorer les plates-formes de cuisson ou les surfaces inférieures au seuil sélectionné.
La hauteur du maillage nous donne des données verticales plus détaillées lors de la cuisson d'un maillage. Par exemple, cette option vous permet de conserver l'emplacement correct de l'agent lors de la montée des escaliers.
Le bouton
Effacer supprime toutes les données NavMesh de la scène et le bouton
Bake crée un maillage pour la scène. Le processus de cuisson est assez rapide. Tant que vous avez une fenêtre sélectionnée, vous pouvez observer la génération de NavMesh avec le bouton
Bake dans la fenêtre de la scène. Cliquons sur le bouton
Bake pour voir les résultats. Dans notre exemple de scène, nous nous retrouvons avec quelque chose de similaire à cette capture d'écran:
Les zones bleues montrent NavMesh. Ci-dessous, nous y reviendrons. En attendant, passons au dernier onglet -
Objet , qui ressemble à ceci:
Les trois boutons illustrés dans la capture d'écran précédente -
Tous ,
Rendu de maillage et
Terrains - sont utilisés comme filtres de scène. Ils sont utiles lorsque vous travaillez dans des scènes complexes avec de nombreux objets dans la hiérarchie. La sélection d'une option filtre le type correspondant dans la hiérarchie, ce qui facilite leur sélection. Vous pouvez utiliser les boutons pour explorer votre scène à la recherche d'objets que vous souhaitez marquer comme navigation statique.
Utilisation de Nav Mesh Agent
Maintenant que nous avons configuré la scène avec NavMesh, nous avons besoin d'un moyen pour l'agent d'utiliser ces informations. Heureusement pour nous, Unity a un composant
Nav Mesh Agent que vous pouvez faire glisser sur un personnage. Dans notre scène d'exemple, il y a un objet de jeu appelé
Tank , auquel un composant est déjà attaché. Regardez la hiérarchie et vous verrez quelque chose comme ceci:
Il y a pas mal de paramètres ici, et nous ne considérerons pas tout car ils sont assez clairs, et la description peut être trouvée dans la documentation officielle de Unity. Mais nous mentionnerons les principales choses:
- Type d'agent : vous vous souvenez de l'onglet Agents dans la fenêtre de navigation ? Les types d'agents attribuables peuvent être sélectionnés ici.
- Traverse automatique hors lien maillé : cette option permet aux agents d'utiliser automatiquement la fonction de liens hors maillage , dont nous parlerons ci-dessous.
- Masque de zone : vous pouvez sélectionner ici les zones configurées dans l'onglet Zones de la fenêtre de navigation .
C’est tout. Cette composante fait 90% du travail acharné pour nous: ouvrir la voie, éviter les obstacles, etc. La seule chose dont vous avez besoin est de transférer le point cible à l'agent. Regardons ce problème.
Réglage du point cible
Après avoir configuré l'agent AI, nous avons besoin d'un moyen de lui dire où aller. Dans notre exemple de projet, il existe un script appelé
Target.cs qui effectue exactement cette tâche.
Il s'agit d'une classe simple qui fait trois choses:
- "Tire" le faisceau de la caméra à la position de la souris dans le monde
- Met à jour la position du marqueur
- Met à jour la propriété de destination pour tous les agents NavMesh.
Le code est assez simple. La classe entière est la suivante:
using UnityEngine; using UnityEngine.AI; public class Target : MonoBehaviour { private NavMeshAgent[] navAgents; public Transform targetMarker; private void Start () { navAgents = FindObjectsOfType(typeof(NavMeshAgent)) as NavMeshAgent[]; } private void UpdateTargets ( Vector3 targetPosition ) { foreach(NavMeshAgent agent in navAgents) { agent.destination = targetPosition; } } private void Update () { if(GetInput()) { Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition); RaycastHit hitInfo; if (Physics.Raycast(ray.origin, ray.direction, out hitInfo)) { Vector3 targetPosition = hitInfo.point; UpdateTargets(targetPosition); targetMarker.position = targetPosition; } } } private bool GetInput() { if (Input.GetMouseButtonDown(0)) { return true; } return false; } private void OnDrawGizmos() { Debug.DrawLine(targetMarker.position, targetMarker.position + Vector3.up * 5, Color.red); } }
Les actions suivantes se produisent ici: dans la méthode
Start , nous initialisons le tableau
navAgents à l'aide de la méthode
FindObjectsOfType () .
La méthode
UpdateTargets () passe par notre tableau
navAgents et définit le point cible pour eux dans le
Vector3 donné. Ceci est la clé du code. Vous pouvez utiliser n'importe quel mécanisme pour obtenir le point cible, et pour que l'agent s'y déplace, il suffit de définir le champ
NavMeshAgent.destination ; l'agent fera le reste.
Dans notre exemple, les clics sont utilisés pour se déplacer, donc lorsqu'un joueur clique sur la souris, nous libérons le rayon de la caméra dans le monde dans la direction du curseur de la souris, et s'il intersecte quelque chose, nous attribuons un point de collision au nouvel agent
targetPosition . Nous ajustons également le marqueur cible en conséquence pour visualiser facilement la destination dans le jeu.
Pour tester l'opération, vous devez cuire NavMesh conformément à la description de la section précédente, puis démarrer le mode Lecture et sélectionner n'importe quelle zone sur la carte. Si vous cliquez plusieurs fois, vous pouvez voir que l'agent ne peut pas atteindre certaines zones - le haut des cubes rouges, la plate-forme supérieure et la plate-forme en bas de l'écran.
Les cubes rouges sont trop hauts. La pente menant à la plate-forme la plus élevée est trop forte pour nos paramètres de
pente maximale , et l'agent ne peut pas la grimper. Les captures d'écran suivantes montrent comment les paramètres
Max Slope affectent NavMesh:
NavMesh avec pente maximale = 45Si vous modifiez la valeur de la
pente maximale à quelque chose comme
51 , puis cliquez à nouveau sur le bouton
Bake pour cuire à nouveau NavMesh, les résultats seront les suivants:
NavMesh avec pente maximale = 51Comme vous pouvez le voir, nous pouvons personnaliser la conception des niveaux, rendant des zones entières inaccessibles en modifiant un seul paramètre. Cela peut être utile, par exemple, lorsque vous avez une plate-forme ou un rebord qui nécessite une corde, une échelle ou un ascenseur pour grimper. Ou peut-être une compétence spéciale, par exemple, la capacité de grimper?
Application hors liens maillés
Vous remarquerez peut-être qu'il y a deux ruptures dans notre scène. Notre agent peut entrer dans le premier, mais celui en bas de l'écran est trop loin. Ces calculs ne sont pas complètement arbitraires.
Les liens hors maillage créent essentiellement un pont à travers les espaces entre les segments NavMesh non liés. Ces liens peuvent être vus dans l'éditeur:
Les cercles bleus avec des lignes de connexion sont des connexions.Unity peut générer ces liens de deux manières. Le premier que nous avons déjà envisagé. Vous vous souvenez de la valeur de
distance de saut dans l'onglet
Bake de la fenêtre de
navigation ? Unity utilise automatiquement cette valeur pour générer ces liens lors de la cuisson de NavMesh. Essayez de changer la valeur de notre scène de test en 5 et de recommencer la cuisson. Vous voyez, les plateformes sont maintenant connectées? Cela est dû au fait que les maillages sont désormais dans le nouveau seuil spécifié.
Changez à nouveau la valeur à 2 et faites cuire. Voyons maintenant la deuxième façon. Créez les sphères qui seront utilisées pour connecter les deux plates-formes. Placez-les approximativement comme indiqué dans la capture d'écran:
Vous pouvez déjà voir ce qui se passe, mais analysons le processus qui leur permet de se connecter. Dans notre cas, j'ai appelé la sphère à droite et la sphère à gauche. Vous comprendrez bientôt pourquoi. Ensuite, j'ai ajouté le composant
Off Mesh Link à la plate-forme à droite (par rapport à la capture d'écran précédente). Vous remarquerez que le composant a des champs de
début et de
fin . Comme vous pouvez le deviner, nous allons faire glisser les sphères précédemment créées dans les emplacements correspondants - la sphère de début dans le champ de
début et la sphère de fin dans le champ de
fin . L'inspecteur ressemblera à ceci:
La valeur de
Cost Override est prise en compte lorsqu'elle reçoit une valeur positive. Il applique un facteur de coût lors de l'utilisation de cette relation, par opposition à un itinéraire plus rentable vers la cible.
Bi-directionnel si vrai permet à l'agent de se déplacer dans les deux sens. Pour créer des liens avec un trafic à sens unique, vous pouvez désactiver cette valeur. La valeur
Activé est utilisée selon son nom. Si faux, l'agent ignore cette association. Vous pouvez l'activer et le désactiver pour créer des scénarios de jeu dans lesquels, par exemple, un joueur doit appuyer sur un interrupteur pour activer une connexion.
Pour activer cette relation, une nouvelle cuisson n'est pas nécessaire. Regardez votre NavMesh et vous verrez qu'il ressemble exactement à la capture d'écran:
Comme vous pouvez le voir, le plus petit espace se connecte toujours automatiquement, et nous avons maintenant une nouvelle connexion générée par le composant
Off Mesh Link entre les deux sphères. Lancez le mode Play et cliquez sur la plate-forme éloignée. Comme prévu, l'agent peut désormais accéder à la plateforme déconnectée:
Aux niveaux de votre jeu, vous devrez peut-être modifier ces paramètres pour obtenir les résultats souhaités, mais une combinaison de ces fonctionnalités vous fournit un outil pratique et prêt à l'emploi. Vous pouvez rapidement créer un jeu simple en utilisant la fonctionnalité NavMesh.
Ce didacticiel fait partie de la programmation AI de jeu Unity 2017 - troisième édition par Ray Barrera, Aung Sithu Kyaw et Thet Naing Swe.