Menu
CoddyTech

Les cerveaux des ennemis

Fait partie de la section Architecture de jeu dans Unity du Journey Unity de Coddy. Leçon 31 sur 50.

Le cerveau d’un ennemi est une machine à états avec un état par comportement. Ce squelette 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 quand il est proche. Chaque état décide de sa propre sortie, et le squelette conserve les assistants 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 restent actifs aussi longtemps que le squelette, leurs champs persistent donc d’une visite à l’autre. Le next de PatrolState conserve sa valeur après une poursuite, et le squelette continue son chemin vers le poste qu’il visait. Enter ne réinitialise que ce qui doit repartir de zéro : celle d’AttackState définit cooldown sur 0, afin que le premier coup soit donné dès que le squelette atteint le joueur.

Tous les déplacements passent par WalkTo, ici MoveTowards sur le transform, qui 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 dans FixedUpdate, où Time.deltaTime correspond au pas de physique. Les trois états ne changent pas : ils indiquent où aller, le propriétaire indique comment.

challenge icon

Défi

Moyen

Un chevalier garde la cour du château. Les flèches indiquent le chemin du joueur, dont la Health possède TakeDamage(int amount) (les deux sont prêts). Knight.cs contient les champs que l’Inspector remplit (waypoints de W0 à W2, player, playerHealth, speed à 3 et les portées ci-dessous) ainsi que des méthodes d’aide utilisant son Rigidbody : DistanceTo(point) et PlayerDistance() mesurent la distance au sol, WalkTo(target) se dirige vers un point, Stop() reste immobile. Donne-lui un cerveau :

  • Dans Knight.cs, crée la machine et les trois états (champs patrol, chase et attack), démarre la patrouille et fais avancer la machine à chaque FixedUpdate.
  • Dans KnightStates.cs, écris PatrolState, ChaseState et AttackState, chacun prenant le chevalier dans son constructeur.
  • Patrouille : dirige-toi vers waypoints[next] ; à moins de 0.3 de celui-ci, dirige-toi vers le suivant, puis retourne au premier après le dernier. À moins de sightRange (5), le joueur est poursuivi. Après une poursuite, la patrouille reprend vers le point de passage qu’elle visait.
  • Poursuite : dirige-toi vers le joueur. À moins de attackRange (1.5) : attaque. Au-delà de loseRange (8) : patrouille. Entre 5 et 8, la poursuite continue, afin que le chevalier n’alterne pas entre les deux états à la limite de son champ de vision.
  • Attaque : reste immobile et frappe immédiatement le joueur pour 1, puis toutes les secondes, tant qu’il est à moins de attackRange ; lorsqu’il est plus loin, reprends la poursuite.

Appuie sur Play, laisse le chevalier te voir, prends un coup, puis cours, et enfin appuie sur Check.

Essayez vous-même

using UnityEngine;

// PatrolState, ChaseState et AttackState
quiz iconTestez-vous

Cette leçon comprend un petit quiz. Commencez la leçon pour y répondre et suivre votre progression.

Toutes les leçons de Architecture de jeu dans Unity