Menu
CoddyTech

Stany jako klasy

Część sekcji Architektura gier w Unity ścieżki Unity w Coddy. Lekcja 35 z 64.

Przełącznik z sekcji 3, oparty na enumie, skupia obsługę wszystkich stanów w jednej metodzie Update. To rozwiązanie przestaje się skalować, gdy stany mają własne dane: timer używany tylko przez jeden stan staje się polem MonoBehaviour, obok pól wszystkich pozostałych stanów, a każdy przypadek musi pamiętać o zresetowaniu używanych wartości. Wzorzec stanu z C# przypisuje każdemu stanowi osobną klasę, a każda klasa implementuje jeden interfejs. Ta latarnia drogowa miga albo świeci światłem ciągłym, a klawisz Space przełącza między tymi dwoma stanami:

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();
    }
}

Stany to zwykłe klasy C#, a nie MonoBehaviours. Tworzysz je za pomocą new i przekazujesz im potrzebne elementy przez konstruktor — tutaj Renderer lampy — ponieważ nie są komponentami i nie mogą wywoływać GetComponent ani wyświetlać pól w Inspectorze. Unity również nie wywołuje ich metod: Beacon jest MonoBehaviour, więc jego Update wywołuje current.Tick() w każdej klatce.

timer należy wyłącznie do BlinkState, a jego Enter ustawia go na 0 za każdym razem, gdy latarnia zaczyna migać. Exit porządkuje stan po jego zakończeniu: klawisz Space może zostać naciśnięty, gdy lampa jest wyłączona, a Exit ponownie ją włącza, dzięki czemu SteadyState nigdy nie zaczyna działania przy zgaszonej lampie. SetState wywołuje Exit poprzedniego stanu, a następnie Enter nowego. Trzeci stan, na przykład powolne pulsowanie, to kolejna klasa, a Update w Beacon pozostaje bez zmian.

challenge icon

Wyzwanie

Średni

Napisz stan skanowania wieżyczki.

  1. W pliku IState.cs zadeklaruj public interface IState z metodami void Enter();, void Tick(); i void Exit();.
  2. W pliku TurretStates.cs napisz ScanState : IState, przekazując głowicę. Enter: kąt 0, głowica Color.green. Tick: obracaj głowicę wokół lokalnej osi y między -45 a 45, z prędkością 90 stopni na sekundę.
  3. Turret: rozpocznij działanie jednego stanu w Start, wywołuj jego Tick w Update.

Naciśnij „Graj”: zielona głowica będzie się obracać. Następnie naciśnij „Sprawdź”.

Spróbuj swoich sił

using UnityEngine;

// ScanState

Wszystkie lekcje w sekcji Architektura gier w Unity

Poćwicz samodzielnie: Edytor online Unity