Menu
CoddyTech

Przejścia

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

Kto decyduje o zmianie stanu? Powierzenie tego właścicielowi sprawia, że wszystkie reguły znów trafiają do jednej metody Update, tak jak w przypadku instrukcji switch. Zwykle przyjmuje się, że każdy stan zna własne wyjście: w swojej metodzie Tick sprawdza warunek i prosi maszynę o przejście do następnego stanu. Ta bomba czeka, aż gracz się zbliży, a potem zaczyna palić lont i wraca do oczekiwania, jeśli gracz ucieknie:

public class Bomb : MonoBehaviour
{
    public Transform player;
    public StateMachine machine = new StateMachine();
    public IState idle;
    public IState fuse;

    void Start()
    {
        idle = new IdleState(this);
        fuse = new FuseState(this);
        machine.ChangeState(idle);
    }

    void Update() { machine.Tick(); }

    public bool PlayerNear()
    {
        return Vector3.Distance(transform.position, player.position) < 3f;
    }
}

public class IdleState : IState
{
    private Bomb bomb;
    public IdleState(Bomb bomb) { this.bomb = bomb; }

    public void Enter() { }
    public void Exit() { }

    public void Tick()
    {
        if (bomb.PlayerNear()) bomb.machine.ChangeState(bomb.fuse);
    }
}

public class FuseState : IState
{
    private Bomb bomb;
    private float timer;
    public FuseState(Bomb bomb) { this.bomb = bomb; }

    public void Enter() { timer = 2f; }
    public void Exit() { }

    public void Tick()
    {
        if (!bomb.PlayerNear())
        {
            bomb.machine.ChangeState(bomb.idle);
            return;
        }
        timer -= Time.deltaTime;
        if (timer <= 0f)
        {
            Debug.Log("Boom!");
            Object.Destroy(bomb.gameObject);
        }
    }
}

Każdy stan otrzymuje bombę w konstruktorze i za jej pośrednictwem uzyskuje dostęp do maszyny, sprawdzania, czy gracz jest blisko, oraz pozostałych stanów. Bomba tworzy każdy stan raz, w metodzie Start, więc stan nigdy nie tworzy innego za pomocą new: dwa stany, które tworzyłyby się nawzajem w swoich konstruktorach, zapętliłyby się, aż do przepełnienia stosu. Metoda Update bomby jedynie wykonuje Tick maszyny, a reguły znajdują się w stanach, do których należą: lont palący się przez 2 sekundy to wyłącznie sprawa FuseState.

ChangeState uruchamia Exit stanu FuseState i Enter stanu IdleState, ale pozostała część metody Tick stanu FuseState nadal wykonałaby się po tym wywołaniu. return ją zatrzymuje; w przeciwnym razie lont paliłby się jeszcze przez jedną klatkę, mimo że stan już się zakończył. Zapis Destroy ma postać Object.Destroy: MonoBehaviour dziedziczy tę metodę po klasie Object z Unity, a zwykła klasa musi podać nazwę klasy.

challenge icon

Wyzwanie

Średni

Zapisz przejścia pułapki na muchy w każdym wywołaniu Tick w pliku FlytrapStates.cs.

  1. Otwarta: gdy trap.PlayerInReach(), wywołaj trap.machine.ChangeState(trap.snap);.
  2. Kłapnięcie: dodawaj Time.deltaTime do timer; po osiągnięciu 0.5 przejdź do trap.chew, jeśli gracz nadal jest w zasięgu, w przeciwnym razie do trap.open.
  3. Żucie: odliczaj timer od 3; po osiągnięciu 0 przejdź do trap.open.

Naciśnij „Graj”, wejdź w pułapkę, a potem jej uniknij. Następnie naciśnij „Sprawdź”.

Spróbuj swoich sił

using UnityEngine;

public class OpenState : IState
{
    private Flytrap trap;

    public OpenState(Flytrap trap)
    {
        this.trap = trap;
    }

    public void Enter()
    {
        trap.Paint(new Color(0.3f, 0.8f, 0.2f));
    }

    public void Tick()
    {
        // Zatrzaśnij się, gdy gracz znajdzie się w zasięgu
    }

    public void Exit()
    {
    }
}

public class SnapState : IState
{
    private Flytrap trap;
    private float timer;

    public SnapState(Flytrap trap)
    {
        this.trap = trap;
    }

    public void Enter()
    {
        timer = 0f;
        trap.Paint(new Color(1f, 0.55f, 0.1f));
    }

    public void Tick()
    {
        // Po 0.5 sekundy: żuj, jeśli gracz nadal jest w zasięgu; w przeciwnym razie otwórz się ponownie
    }

    public void Exit()
    {
    }
}

public class ChewState : IState
{
    private Flytrap trap;
    private float timer;

    public ChewState(Flytrap trap)
    {
        this.trap = trap;
    }

    public void Enter()
    {
        timer = 3f;
        trap.Paint(new Color(0.5f, 0.05f, 0.1f));
        Debug.Log("Chomp!");
    }

    public void Tick()
    {
        // Po 3 sekundach: otwórz się ponownie
    }

    public void Exit()
    {
    }
}

Wszystkie lekcje w sekcji Architektura gier w Unity

Poćwicz samodzielnie: Edytor online Unity