Création d'une IA C # simple dans Unity

image

Presque tous les jeux nĂ©cessitent une intelligence artificielle (IA) qui interagit avec l'utilisateur, le plus souvent sous la forme d'une force hostile au joueur. Dans certains cas, l'IA devrait aider le joueur, dans d'autres, elle devrait le combattre, mais tous les personnages contrĂŽlĂ©s par l'ordinateur ont des similitudes. Selon les exigences du projet, l'IA peut utiliser des comportements simples ou complexes. Ces exigences peuvent ĂȘtre la diplomatie avec un autre joueur ou une simple errance dans les deux sens sur la plate-forme. Quoi qu'il en soit, il est nĂ©cessaire de s'assurer que l'IA fait son travail efficacement.

Dans ce projet, je vais dĂ©montrer une intelligence artificielle trĂšs simple. Supposons que nous crĂ©ons un jeu dans lequel un joueur doit se faufiler prĂšs du quartier gĂ©nĂ©ral ennemi. Lorsqu'un joueur est remarquĂ© par une camĂ©ra de sĂ©curitĂ©, des ennemis sont créés Ă  proximitĂ© et pour une courte pĂ©riode, poursuivez le joueur. C'est ce que nous mettons en Ɠuvre dans le projet au niveau le plus simple. À la fin du projet, vous recevrez un objet de joueur contrĂŽlĂ©, un cercle utilisĂ© comme camĂ©ra d'un ennemi et un objet ennemi qui poursuivra le joueur lorsque l'objet de la camĂ©ra informe de sa prĂ©sence.

La préparation


Nous devons d'abord crĂ©er un projet 3D. Cliquez sur le bouton Nouveau en haut de la fenĂȘtre aprĂšs avoir dĂ©marrĂ© Unity, comme illustrĂ© Ă  la figure 1.


Figure 1: création d'un nouveau projet

Nommez votre projet AI et assurez-vous qu'il s'agit d'un projet 3D. AprÚs avoir choisi un emplacement sur l'ordinateur pour stocker le projet, cliquez sur le bouton Créer un projet en bas, illustré à la figure 2.


Figure 2: écran de configuration du projet

AprĂšs avoir créé le projet, la premiĂšre chose que nous devons faire est de configurer les dossiers dans la fenĂȘtre Actifs pour organiser notre travail. Cliquez avec le bouton droit sur la fenĂȘtre Actifs et sĂ©lectionnez CrĂ©er → Dossier pour crĂ©er un nouveau dossier. Nommez ce dossier MatĂ©riaux . CrĂ©ez ensuite un deuxiĂšme dossier et nommez-le Scripts . La figure 3 montre Ă  quoi cela devrait ressembler.


Figure 3: création d'un nouveau dossier

AprĂšs tout cela, la fenĂȘtre Actifs devrait ressembler Ă  celle illustrĂ©e Ă  la figure 4.


Figure 4: fenĂȘtre Actifs .

Ensuite, crĂ©ez un sol sur lequel tous les objets se poseront. Dans la fenĂȘtre HiĂ©rarchie , sĂ©lectionnez CrĂ©er → Objet 3D → Plan pour crĂ©er un objet plan qui sera utilisĂ© comme sol.


Figure 5: Création d'un objet plan.

Nommez cet objet Floor et changez sa valeur X Scale en 7, et la valeur Z Scale en 3. AprĂšs cela, la fenĂȘtre Inspector avec l'objet Floor sĂ©lectionnĂ© devrait ressembler Ă  la figure 6.


Figure 6: Définition des propriétés de l'objet Floor .

Maintenant, nous devons crĂ©er un nouveau matĂ©riau pour Floor afin de le distinguer du reste des objets qui seront placĂ©s dans la scĂšne. Dans le dossier MatĂ©riaux de la fenĂȘtre Actifs , crĂ©ez un nouveau matĂ©riau en cliquant avec le bouton droit sur la fenĂȘtre Actifs et en choisissant CrĂ©er → MatĂ©riau .


Figure 7: création d'un nouveau matériau

Une fois terminé, nommez le matériau Floor .


Figure 8: Matériau du sol .

En haut de la fenĂȘtre Inspecteur avec Plancher sĂ©lectionnĂ©, sĂ©lectionnez un sĂ©lecteur de couleurs.


Figure 9: choix d'un sélecteur de couleurs.

Bien sûr, vous pouvez choisir n'importe quelle couleur pour le sol, mais dans cet exemple, j'ai choisi le rouge-brun, comme le montre la figure 10.


Figure 10: sélecteur de couleurs.

SĂ©lectionnez l'objet Floor dans la fenĂȘtre HiĂ©rarchie et dans le composant Mesh Renderer , sĂ©lectionnez la petite flĂšche en regard de MatĂ©riaux .


Figure 11: Préparation d'un changement important.

Faites glisser le matĂ©riau Floor depuis la fenĂȘtre Assets vers le champ Element 0 du composant Mesh Renderer dans la fenĂȘtre Inspector .


Figure 12: Définition du matériau Floor comme matériau de l'objet Floor .

AprĂšs avoir terminĂ© avec l'objet Floor , nous devons crĂ©er autour de la zone du mur afin que le joueur ne puisse pas tomber du bord. Revenez Ă  CrĂ©er → Objet 3D → Plan pour crĂ©er un nouveau plan. Nous appelons ce plan de mur et le dĂ©finissons aux mĂȘmes dimensions que le sol , c'est-Ă -dire l' Ă©chelle X avec une valeur de 7 et l' Ă©chelle Z avec une valeur de 3. Ensuite, crĂ©ez trois autres murs, sĂ©lectionnez un objet et appuyez trois fois sur Ctrl + D. Ensuite, placez les murs autour selon les donnĂ©es du tableau.

Le titre
Position X
Position Y
Position z
Rotation x
Rotation z
Mur
-35
21
0
0
-90
Mur (1)-1
11
-15
90
0
Mur (2)
-1
11
13,5
-90
0
Mur (3)
34
21
0
0
90

Tableau 1: Positions et rotations de tous les objets Mur .

AprÚs avoir terminé tout cela, vous devez changer la position de la caméra afin qu'elle regarde le sol par le haut. Sélectionnez l'objet Caméra principale et définissez Position Y sur 30, Position Z sur 0 et Rotation X sur 80.


Figure 13: configuration de l'objet caméra.

La scĂšne est prĂ©parĂ©e, il est donc temps de crĂ©er le personnage du joueur. Dans la fenĂȘtre HiĂ©rarchie , cliquez sur CrĂ©er → Objet 3D → SphĂšre pour crĂ©er un objet sphĂšre. Nommez cet objet Player , puis cliquez sur le bouton Ajouter un composant en bas de la fenĂȘtre Inspecteur .


Figure 14: ajout d'un nouveau composant.

Maintenant, trouvez le Rigidbody . AprÚs cela, sélectionnez le composant Rigidbody dans la liste et ajoutez le Rigidbody à l'objet Player .


Figure 15: ajout d'un composant Rigidbody .

Ensuite, vous devez attribuer au joueur un tag, qui nous sera plus tard utile dans le code. Cliquez sur le menu dĂ©roulant Tag dans le coin supĂ©rieur gauche de la fenĂȘtre Inspecteur et sĂ©lectionnez la balise Player .


Figure 16: Définition d'une nouvelle balise.

Nous devons définir la position du joueur afin qu'il ne se trouve pas sous l'objet Floor . Dans l'exemple, j'ai placé le joueur dans le coin supérieur gauche avec une position X égale à 26, une position Y égale à 1 et une position Z égale à -9.


Figure 17: placement du joueur.

Pour que notre futur code fonctionne correctement, nous devons, bien sĂ»r, l'attacher Ă  l'objet. Revenez Ă  la fenĂȘtre HiĂ©rarchie et sĂ©lectionnez cette fois CrĂ©er → Objet 3D → Cube . Appelez ce cube Guard , ajoutez-y le composant Rigidbody et le composant NavMesh Agent Ă  l'aide du bouton Ajouter un composant dans la fenĂȘtre Inspecteur . Ensuite, placez-le quelque part dans le coin supĂ©rieur gauche de la scĂšne. AprĂšs cela, la fenĂȘtre Inspecteur de l'objet Guard ressemblera Ă  ceci:


Figure 18: Objet de garde dans la fenĂȘtre Inspecteur .

Et cet objet doit ĂȘtre situĂ© comme ceci:


Figure 19: Placement de l'objet Guard .

Enfin, nous avons besoin d'un objet utilisĂ© comme «Ɠil» de l'objet Guard , qui informera le Guard que le joueur le touche. Pour la derniĂšre fois, allez dans la fenĂȘtre HiĂ©rarchie et sĂ©lectionnez CrĂ©er → Objet 3D → SphĂšre pour crĂ©er un autre objet sphĂšre. Nommez cet objet Looker . Cette fois, nous n'avons pas besoin d'y ajouter d'autres composants. Cependant, nous allons redimensionner l'objet. AprĂšs avoir choisi Looker , modifiez les variables de composant Transform suivantes dans la fenĂȘtre Inspector .

  • Échelle X Ă  9.
  • Échelle Y Ă  0,5.
  • Échelle Z Ă  9.

AprÚs cela, positionnez le Looker de maniÚre à ce qu'il soit situé dans la partie supérieure centrale du sol, comme illustré à la figure 20.


Figure 20: Emplacement du Looker.

C'est le bon moment pour donner Ă  Looker un matĂ©riau unique afin que vous puissiez voir qu'il vaut la peine d'ĂȘtre Ă©vitĂ©. Dans le dossier MatĂ©riaux de la fenĂȘtre Actifs , cliquez avec le bouton droit et crĂ©ez un nouveau matĂ©riau. Nommez-le Looker et donnez-lui une couleur rouge vif. AprĂšs cela, dĂ©signez ce matĂ©riau comme le matĂ©riau de l'objet Looker pour changer sa couleur. AprĂšs cela, la scĂšne devrait ressembler Ă  ceci:


Figure 21: objet Looker avec un nouveau matériau.

Il ne nous reste plus qu'Ă  crĂ©er un maillage de navigation pour la Garde , sur lequel il pourra se dĂ©placer. Il y a un menu FenĂȘtre en haut de l'Ă©diteur Unity. Choisissez FenĂȘtre → Navigation pour ouvrir la fenĂȘtre de navigation illustrĂ©e Ă  la figure 22.


Figure 22: FenĂȘtre de navigation .

SĂ©lectionnez l'objet Floor dans la hiĂ©rarchie , puis dans la fenĂȘtre Navigation , cochez la case Navigation Static .


Figure 23: Navigation statique .

Ensuite, sĂ©lectionnez l'option Bake en haut de la fenĂȘtre.


Figure 24: Basculez vers le menu Bake .

Le menu Bake s'ouvre, dans lequel vous pouvez modifier les propriĂ©tĂ©s du maillage de navigation que nous allons crĂ©er. Dans notre exemple, rien ne doit ĂȘtre changĂ©. Cliquez simplement sur le bouton Bake en bas Ă  droite.


Figure 25: création d'un nouveau maillage de navigation.

À ce stade, Unity vous demandera de sauvegarder la scĂšne. Enregistrez-le, aprĂšs quoi un maillage de navigation sera créé. Maintenant, la scĂšne ressemblera Ă  ceci:


Figure 26: La scÚne actuelle avec le maillage de navigation ajouté.

Maintenant, tout dans Unity est configurĂ©, il est donc temps de crĂ©er les scripts nĂ©cessaires au fonctionnement du projet. Dans la fenĂȘtre Actifs , cliquez avec le bouton droit et sĂ©lectionnez CrĂ©er → Script C # . Nommez ce script Player . RĂ©pĂ©tez cette opĂ©ration deux fois de plus, en crĂ©ant des scripts avec les noms Guard et Looker .


Figure 27: création d'un nouveau script.

AprĂšs cela, le dossier Scripts dans la fenĂȘtre Actifs ressemblera Ă  ceci:


Figure 28: dossier Scripts .

Tout d'abord, nous allons commencer Ă  Ă©crire le code du script Player . Double-cliquez sur le script Player dans la fenĂȘtre Actifs pour ouvrir Visual Studio et commencer Ă  crĂ©er le code.

Code


Le script Player est assez simple, il ne fait que dĂ©placer l’objet balle. Sous la dĂ©claration de classe, nous devons obtenir un lien vers le composant Rigidbody que nous avons prĂ©cĂ©demment créé dans le projet.

private Rigidbody rb; 

Juste aprÚs cela, dans la fonction Démarrer , nous commandons à Unity de définir le composant Rigidbody actuel de l'objet Player sur rb .

 rb = GetComponent<Rigidbody>(); 

AprĂšs cela, le script Player ressemblera Ă  ceci:


Figure 29: Script du joueur pour le moment.

Maintenant que la valeur rb est affectée, nous devons laisser bouger l'objet Player lorsque nous appuyons sur les touches fléchées. Pour déplacer l'objet, nous utiliserons la physique, en appliquant une force à l'objet lorsque l'utilisateur appuie sur les touches fléchées. Pour ce faire, ajoutez simplement le code suivant à la fonction de mise à jour :

 if (Input.GetKey(KeyCode.UpArrow)) rb.AddForce(Vector3.forward * 20); if (Input.GetKey(KeyCode.DownArrow)) rb.AddForce(Vector3.back * 20); if (Input.GetKey(KeyCode.LeftArrow)) rb.AddForce(Vector3.left * 20); if (Input.GetKey(KeyCode.RightArrow)) rb.AddForce(Vector3.right * 20); 

Avec cela, nous avons terminé le script Player . Le script terminé ressemblera à ceci:


Figure 30: le script Player terminé.

Enregistrez votre travail et revenez Ă  Unity. Cette fois, sĂ©lectionnez le script Guard dans la fenĂȘtre Actifs . Pour que le code Guard fonctionne, vous devez ajouter la construction using en haut du script.

 using UnityEngine.AI; 

Ensuite, déclarez les variables suivantes immédiatement aprÚs la déclaration de classe.

 public GameObject player; private NavMeshAgent navmesh; 

L'objet Player est utilisé comme valeur de la variable player de l'objet Guard . Cela vous sera utile plus tard lorsque nous ordonnerons à l'objet Garde de poursuivre le joueur. Ensuite, la variable navmesh est déclarée pour recevoir le composant NavMeshAgent de l'objet. Nous l'utiliserons plus tard lorsque le garde commencera à chasser le joueur aprÚs avoir appris que le joueur touche l'objet Looker . Dans la fonction Démarrer , nous devons définir la valeur de la variable navmesh sur le composant NavMesh Agent de l' objet:

 navmesh = GetComponent<NavMeshAgent>(); 

Ensuite, dans la fonction Update , nous ajoutons une seule ligne de code:

 navmesh.destination = player.transform.position; 

Cette ligne définit la destination de l'objet Guard . Dans notre cas, il prendra la position actuelle de l'objet Player et se déplacera jusqu'à ce point. AprÚs l'opération, l'objet poursuivra constamment le joueur. La question est de savoir comment se déroule le processus de réponse? Il ne sera pas encodé dans le script Guard , mais dans le script Looker . Avant de passer au script Looker, consultez la figure 31 pour vérifier le code de votre script Guard .


Figure 31: le script Guard terminé.

Dans Looker, nous devons à nouveau déclarer les variables suivantes:

 public GameObject guard; private float reset = 5; private bool movingDown; 

AprÚs cela, nous commentons la fonction Démarrer , dont nous n'avons pas besoin dans ce script. Passons à la fonction de mise à jour et ajoutons le code suivant:

 if (movingDown == false) transform.position -= new Vector3(0, 0, 0.1f); else transform.position += new Vector3(0, 0, 0.1f); if (transform.position.z > 10) movingDown = false; else if (transform.position.z < -10) movingDown = true; reset -= Time.deltaTime; if (reset < 0) { guard.GetComponent<Guard>().enabled = false; GetComponent<SphereCollider>().enabled = true; } 

C'est lĂ  que se dĂ©roulent les principales actions du projet, analysons donc le code. PremiĂšrement, selon la valeur de la variable boolĂ©enne movingDown , l'objet auquel ce script est attachĂ© se dĂ©placera vers le haut ou vers le bas. DĂšs qu'il atteint un certain point, il change de direction. Ensuite, Looker rĂ©duira la valeur de rĂ©initialisation en fonction du temps rĂ©el. DĂšs que le chronomĂštre devient infĂ©rieur Ă  zĂ©ro, il prendra le script Guard de l'objet Guard et le dĂ©sactivera, aprĂšs quoi l'objet Guard commencera Ă  se dĂ©placer vers la derniĂšre position connue du joueur jusqu'Ă  ce moment, puis s'arrĂȘtera. Looker rallume Ă©galement son collisionneur pour que l'ensemble du processus puisse recommencer. Maintenant, notre script ressemble Ă  ceci:


Figure 32: script Looker .

En parlant de collisionneurs: il est temps de créer un code de conflit qui réinitialise le minuteur Looker et inclut le script Guard . Dans la fonction de mise à jour , créez le code suivant:

 private void OnCollisionEnter(Collision collision) { if (collision.gameObject.tag == "Player") { guard.GetComponent<Guard>().enabled = true; reset = 5; GetComponent<SphereCollider>().enabled = false; } } 

OnCollisionEnter Unity le reconnaßt automatiquement comme un code de collision et l'exécute donc lorsqu'une collision se produit avec un autre objet. Dans notre cas, il vérifie d'abord si l'objet entrant en collision a une balise Player . Sinon, il ignore le reste du code. Sinon, il active le script Guard , définit le délai de réinitialisation sur 5 (c'est-à-dire cinq secondes) et désactive son collisionneur afin que le joueur puisse toujours se déplacer dans l'objet et ne pas se coincer accidentellement dans l'objet Looker . La fonction est illustrée à la figure 33.


Figure 33: Code de collision pour Looker.

C'est tout le code du projet est prĂȘt! Vous pouvez faire quelques autres choses avant de terminer le projet. Enregistrez tout le travail et revenez Ă  Unity.

AchĂšvement du projet


Pour terminer le projet, nous avons juste besoin d'attacher des scripts aux objets correspondants et de dĂ©finir plusieurs variables. Tout d'abord, passez de la fenĂȘtre Navigation Ă  la fenĂȘtre Inspecteur :


Figure 34: transition vers la fenĂȘtre Inspecteur.

AprĂšs cela, commençons par l'objet Player . SĂ©lectionnez-le dans la fenĂȘtre HiĂ©rarchie , puis en bas de la fenĂȘtre Inspecteur , cliquez sur le bouton Ajouter un composant et ajoutez le script Player . Ceci termine l'objet Player .


Figure 35: Composant de script du lecteur .

Ensuite, sélectionnez l'objet Guard . Comme précédemment, attachez le script Guard à l'objet. Cette fois, nous devons dire au garde qui est le joueur. Pour ce faire, faites glisser l'objet Player de la hiérarchie vers le champ Player du composant de script Guard , comme illustré à la figure 36.


Figure 36: Faire de l'objet Player la valeur du champ Player .

Nous devons Ă©galement dĂ©sactiver le script Guard . Dans notre projet, Guard poursuivra le joueur aprĂšs avoir activĂ© son script. Ce script de garde ne doit ĂȘtre inclus qu'aprĂšs que le joueur a touchĂ© l' objet Looker . Il vous suffit de dĂ©cocher la case Ă  cĂŽtĂ© du texte Guard (Script) dans le composant:


Figure 37: Désactivation du script Guard .

Enfin, passons Ă  l'objet Looker et y attachons le script Looker . Cette fois, l'objet Looker aura besoin d'un objet Guard comme valeur de sa variable Guard . Tout comme nous avons affectĂ© l'objet Player Ă  la variable Player du script Guard , nous ferons de mĂȘme avec l'objet Guard et le script Looker . Faites glisser la Garde de la HiĂ©rarchie dans le champ Garde du script Looker . Et le projet est terminĂ©! Cliquez sur le bouton Lecture en haut de l'Ă©diteur Unity pour tester votre projet.


Figure 38: Test d'un projet.

Essayez de déplacer l'objet Player vers l'objet Looker (rappelez-vous que le déplacement se fait avec des flÚches!). Notez qu'aprÚs cela, l'objet Guard commencera à chasser le joueur. Il poursuivra la poursuite pendant environ 5 secondes, aprÚs quoi il abandonnera.


Figure 39: Un projet entiÚrement achevé en action.

Conclusion


Cette IA est trĂšs simple, mais elle peut facilement ĂȘtre Ă©tendue. Supposons que si nous imaginons que l'objet Looker est une camĂ©ra et que le garde regarde Ă  travers lui pour vous trouver, il sera logique de donner Ă  l'objet Guard sa propre paire d'yeux. Le joueur peut s'approcher des camĂ©ras, mais elles doivent tenir compte des yeux du gardien. Vous pouvez Ă©galement combiner ce projet avec le concept de trouver le chemin : donner au gardien le chemin qu'il suivra, crĂ©ant ainsi un environnement plus intĂ©ressant pour le joueur.

Une IA aussi simple peut ĂȘtre dĂ©veloppĂ©e de diffĂ©rentes maniĂšres. Vous ne voudrez peut-ĂȘtre rien faire de ce qui prĂ©cĂšde et dĂ©cider de faire quelque chose de votre choix. Je vous conseille d'expĂ©rimenter, peut-ĂȘtre aurez-vous l'idĂ©e d'un projet intĂ©ressant, qui mĂ©rite d'ĂȘtre menĂ© Ă  terme.

Source: https://habr.com/ru/post/fr419641/


All Articles