Menu
CoddyTech

Maszyna stanów

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

Metoda SetState obiektu Beacon byłaby taka sama dla każdego obiektu ze stanami: wieżyczki, przeciwnika, drzwi. Ten kod może znajdować się we własnej klasie — maszynie stanów, która przechowuje bieżący stan i go zmienia. Każdy obiekt tworzy jedną maszynę i ją wywołuje, zamiast powtarzać kod:

public class StateMachine
{
    public IState Current { get; private set; }

    public void ChangeState(IState next)
    {
        Current?.Exit();
        Current = next;
        Current.Enter();
    }

    public void Tick()
    {
        Current?.Tick();
    }
}

public class Beacon : MonoBehaviour
{
    public Renderer lamp;
    private StateMachine machine = new StateMachine();
    private IState blink;
    private IState steady;

    void Start()
    {
        blink = new BlinkState(lamp);
        steady = new SteadyState();
        machine.ChangeState(steady);
    }

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

Pierwsze wywołanie ChangeState nie ma stanu, z którego mogłoby wyjść: Current ma wartość null, a ?. pomija wywołanie Exit. W sekcji 1 było ostrzeżenie, że ?. nie wykrywa fałszywego null w Unity; dotyczy to zniszczonych obiektów Unity, a stany są zwykłymi obiektami C#, więc ?. jest tutaj bezpieczne. Właściwość Current ma private set, więc żaden skrypt nie może zmienić stanu bez przejścia przez ChangeState oraz jego Exit i Enter.

Kolejność wewnątrz ChangeState ma znaczenie zawsze, gdy dwa stany wpływają na ten sam element. Exit cofa zmiany wprowadzone przez stary stan, a następnie Enter przygotowuje nowy, więc ostatnie słowo należy do nowego stanu. Gdyby Enter stanu DarkState wyłączało lampę i uruchamiało się przed Exit stanu BlinkState, to Exit ponownie włączyłoby lampę w ciemnym stanie. StateMachine również jest zwykłą klasą: latarnia, wieżyczka i przeciwnik tworzą własne maszyny za pomocą new i wywołują ich Tick z poziomu Update.

challenge icon

Wyzwanie

Średni

Przytrzymaj Spację, aby skradać się. WalkState i SneakState są gotowe w PlayerStates.cs: ich Enter i Exit zapisują w logu, co się dzieje (Walk: enter, Sneak: exit...), a ich Tick wywołuje Move() gracza. Napisz maszynę, która nimi zarządza.

  • W StateMachine.cs napisz zwykłą klasę StateMachine z publiczną właściwością Current, którą może ustawiać tylko maszyna, metodą ChangeState(IState next), która wywołuje Exit poprzedniego stanu, a następnie Enter nowego stanu, oraz metodą Tick(), która wywołuje Tick bieżącego stanu.
  • Gracz pyta o swój stan w każdej klatce, więc wywołanie ChangeState ze stanem, który jest już bieżący, nic nie robi: nie wywołuje Exit ani Enter.
  • W Player.cs dodaj pole StateMachine o nazwie machine. W Start utwórz maszynę i oba stany (każdy przyjmuje gracza) oraz rozpocznij chodzenie. W Update przełącz na skradanie, gdy Spacja jest wciśnięta, a w przeciwnym razie na chodzenie, a następnie wykonaj Tick maszyny.

Naciśnij Play, chodź, przytrzymaj Spację i dalej chodź, a następnie naciśnij Check.

Spróbuj swoich sił

// StateMachine: Current, ChangeState i Tick
quiz iconSprawdź się

Ta lekcja zawiera krótki quiz. Zacznij lekcję, żeby na niego odpowiedzieć i śledzić swoje postępy.

Wszystkie lekcje w sekcji Architektura gier w Unity