L’intelligence des ennemis
Fait partie de la section Architecture de jeu dans Unity du Journey Unity de Coddy. Leçon 39 sur 64.
Le cerveau d’un ennemi est une machine à états avec un état par comportement. Cette armature se déplace entre ses postes, poursuit un joueur qui s’approche à moins de 6 unités et donne un coup d’épée une fois par seconde lorsqu’il est proche. Chaque état décide de sa propre sortie, et le squelette conserve les fonctions auxiliaires qu’ils partagent :
public class Skeleton : MonoBehaviour
{
public Transform player;
public Transform[] posts;
public float speed = 2f;
public StateMachine machine = new StateMachine();
public IState patrol, chase, attack;
void Start()
{
patrol = new PatrolState(this);
chase = new ChaseState(this);
attack = new AttackState(this);
machine.ChangeState(patrol);
}
void Update() { machine.Tick(); }
public float PlayerDistance() { return Vector3.Distance(transform.position, player.position); }
public void WalkTo(Vector3 target)
{
target.y = transform.position.y;
transform.position = Vector3.MoveTowards(transform.position, target, speed * Time.deltaTime);
}
}
public class PatrolState : IState
{
private Skeleton skel;
private int next;
public PatrolState(Skeleton skel) { this.skel = skel; }
public void Enter() { }
public void Exit() { }
public void Tick()
{
if (skel.PlayerDistance() < 6f) { skel.machine.ChangeState(skel.chase); return; }
Vector3 post = skel.posts[next].position;
post.y = skel.transform.position.y;
skel.WalkTo(post);
if (skel.transform.position == post) next = (next + 1) % skel.posts.Length;
}
}
public class ChaseState : IState
{
private Skeleton skel;
public ChaseState(Skeleton skel) { this.skel = skel; }
public void Enter() { }
public void Exit() { }
public void Tick()
{
float d = skel.PlayerDistance();
if (d > 6f) { skel.machine.ChangeState(skel.patrol); return; }
if (d < 1.5f) { skel.machine.ChangeState(skel.attack); return; }
skel.WalkTo(skel.player.position);
}
}
public class AttackState : IState
{
private Skeleton skel;
private float cooldown;
public AttackState(Skeleton skel) { this.skel = skel; }
public void Enter() { cooldown = 0f; }
public void Exit() { }
public void Tick()
{
if (skel.PlayerDistance() > 1.5f) { skel.machine.ChangeState(skel.chase); return; }
cooldown -= Time.deltaTime;
if (cooldown <= 0f) { Debug.Log("Swing!"); cooldown = 1f; }
}
}Les états sont créés une seule fois et vivent aussi longtemps que le squelette, leurs champs persistent donc entre les visites. next de PatrolState conserve sa valeur après une poursuite, et le squelette continue vers le poste qu’il était en train de rejoindre. Enter ne réinitialise que ce qui doit repartir de zéro : celui de AttackState définit cooldown à 0, pour que le premier coup soit donné dès que le squelette atteint le joueur.
Tous les déplacements passent par WalkTo, qui utilise ici MoveTowards sur le transform et traverse les murs. Pour déplacer le squelette avec un Rigidbody à la place, WalkTo définit la vélocité du corps et le squelette fait avancer la machine avec FixedUpdate, où Time.deltaTime correspond au pas de la simulation physique. Les trois états ne changent pas : ils indiquent où aller, le propriétaire indique comment.
Défi
MoyenAjoute au chevalier PatrolState et ChaseState dans KnightStates.cs, en passant le chevalier à chacun d’eux.
- Patrouille : marche jusqu’à
waypoints[next]; à moins de0.3, passe au suivant en bouclant, et conserve cette valeur entre les visites. À moins desightRange, poursuis le joueur. - Poursuite : marche jusqu’au joueur ; au-delà de
loseRange, patrouille. - Dans
Knight, crée la machine et les états dans Awake, lance la patrouille dans Start et appelle Tick dans FixedUpdate.
Appuie sur « Jouer », puis approche-toi et cours. Ensuite, appuie sur « Vérifier ».
Essayez vous-même
using UnityEngine;
// PatrolState et ChaseState
Toutes les leçons de Architecture de jeu dans Unity
1Des composants, pas des hiérarchies
De petits composantsUn script de base pour les ennemisComposants abstraitsDes composants qui fonctionnent ensembleRécapitulatif : tourelle modulaireRécapitulatif : canon double4Données sérialisées
Classes sérialisablesListes dans l’InspecteurÉnumérations dans l’InspecteurRécapitulatif : table de butinRécapitulatif : tirer le butin7Machines à états
Les états sous forme de classesL’état d’alerteUne machine à étatsTransitionsL’intelligence des ennemisLe chevalier attaqueRécapitulatif : états des portes2Les interfaces dans Unity
IDamageableInterfaces et TryGetComponentGetComponentsRécapitulatif : touche d’interactionLe plus proche à portée5ScriptableObjects
Ressources de donnéesStatistiques des armesParamètres partagésSauver le ventLes vagues comme donnéesRécapitulatif : base de données des objetsRécapitulatif : acheter dans la boutique3Événements
Les événements C# dans UnityS’abonner dans OnEnableChamps UnityEventLes événements pilotent l’interfaceRécapitulatif : fenêtre de succèsRécapitulatif : minuteur de la fenêtreEntraînez-vous par vous-même : Playground Unity