Menu
CoddyTech

Les états sous forme de classes

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

Le commutateur sur une énumération de la section 3 regroupe le travail de chaque état dans un seul Update. Cette approche ne passe plus à l’échelle dès que les états possèdent leurs propres données : un minuteur utilisé par un seul état se retrouve comme champ du MonoBehaviour, à côté des champs de tous les autres états, et chaque cas doit penser à réinitialiser ce qu’il utilise. Le patron de conception d’état de C# donne à chaque état sa propre classe, et chaque classe implémente une interface. Cette balise routière clignote ou reste allumée, et la touche Espace permet de passer de l’un à l’autre :

public interface IState
{
    void Enter();
    void Tick();
    void Exit();
}

public class BlinkState : IState
{
    private Renderer lamp;
    private float timer;

    public BlinkState(Renderer lamp)
    {
        this.lamp = lamp;
    }

    public void Enter() { timer = 0f; }

    public void Tick()
    {
        timer += Time.deltaTime;
        if (timer >= 0.5f)
        {
            timer = 0f;
            lamp.enabled = !lamp.enabled;
        }
    }

    public void Exit() { lamp.enabled = true; }
}

public class SteadyState : IState
{
    public void Enter() { }
    public void Tick() { }
    public void Exit() { }
}

public class Beacon : MonoBehaviour
{
    public Renderer lamp;
    private IState blink;
    private IState steady;
    private IState current;

    void Start()
    {
        blink = new BlinkState(lamp);
        steady = new SteadyState();
        SetState(steady);
    }

    void Update()
    {
        if (Keyboard.current.spaceKey.wasPressedThisFrame) SetState(current == steady ? blink : steady);
        current.Tick();
    }

    void SetState(IState next)
    {
        if (current != null) current.Exit();
        current = next;
        current.Enter();
    }
}

Les états sont de simples classes C#, et non des MonoBehaviours. Tu les crées avec new et tu leur transmets ce dont ils ont besoin via le constructeur, ici le Renderer de la lampe, car ce ne sont pas des composants et ils ne peuvent ni appeler GetComponent ni afficher de champs dans l’Inspector. Unity n’appelle pas non plus leurs méthodes : Beacon est le MonoBehaviour, donc son Update appelle current.Tick() à chaque image.

Le timer appartient uniquement à BlinkState, et son Enter le réinitialise à 0 à chaque fois que la balise se met à clignoter. Exit effectue le nettoyage à la fin de l’état : la barre d’espace peut être actionnée lorsque la lampe est éteinte, et Exit la rallume, si bien que SteadyState ne commence jamais avec une lampe éteinte. SetState exécute Exit de l’ancien état, puis Enter du nouvel état. Un troisième état, par exemple une impulsion lente, correspond à une classe supplémentaire, et le Update de Beacon reste inchangé.

challenge icon

Défi

Moyen

Écris l’état de balayage de la tourelle.

  1. Dans IState.cs, déclare public interface IState avec void Enter();, void Tick(); et void Exit();.
  2. Dans TurretStates.cs, écris ScanState : IState, en lui passant la tête. Entrée : angle à 0, tête en Color.green. Mise à jour : fais pivoter la tête autour de son axe y local entre -45 et 45, à 90 degrés par seconde.
  3. Turret : fais-en entrer une dans Start et mets-la à jour dans Update.

Appuie sur « Jouer » : la tête verte balaie la zone. Puis appuie sur « Vérifier ».

Essayez vous-même

using UnityEngine;

// ScanState

Toutes les leçons de Architecture de jeu dans Unity

Entraînez-vous par vous-même : Playground Unity