Menu
CoddyTech

Ein Zustandsautomat

Teil des Abschnitts Spielarchitektur in Unity der Unity-Journey von Coddy. Lektion 29 von 50.

Die Methode SetState des Beacons wäre bei jedem Objekt mit Zuständen gleich: einem Geschützturm, einem Gegner, einer Tür. Dieser Code kann in einer eigenen Klasse untergebracht werden, einer Zustandsmaschine, die den aktuellen Zustand speichert und ändert. Jedes Objekt erstellt eine eigene Zustandsmaschine und ruft sie auf, statt den Code zu wiederholen:

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

Beim ersten Aufruf von ChangeState gibt es keinen Zustand, der verlassen werden muss: Current ist null, und ?. überspringt den Aufruf von Exit. Abschnitt 1 warnte davor, dass ?. Unitys vorgetäuschtes null nicht erkennt; das betrifft zerstörte Unity-Objekte. Die Zustände sind jedoch gewöhnliche C#-Objekte, daher ist ?. hier sicher. Current hat einen private set, sodass kein Skript den Zustand ändern kann, ohne ChangeState und dessen Exit und Enter zu durchlaufen.

Die Reihenfolge innerhalb von ChangeState ist wichtig, wenn zwei Zustände dasselbe beeinflussen. Exit macht rückgängig, was der alte Zustand geändert hat, danach richtet Enter den neuen Zustand ein. So hat der neue Zustand das letzte Wort. Wenn Enter eines DarkState die Lampe ausschalten und vor Exit von BlinkState ausgeführt würde, würde dieses Exit die Lampe im dunklen Zustand wieder einschalten. Auch die StateMachine ist eine gewöhnliche Klasse: Der Beacon, ein Geschützturm und ein Gegner erstellen jeweils mit new eine eigene Instanz und rufen deren Tick aus ihrem Update auf.

challenge icon

Aufgabe

Mittel

Halte die Leertaste gedrückt, um zu schleichen. WalkState und SneakState sind in PlayerStates.cs bereit: Ihre Enter- und Exit-Methoden protokollieren, was passiert (Walk: enter, Sneak: exit...), und ihre Tick-Methoden rufen die Move()-Methode des Spielers auf. Schreibe die Zustandsmaschine, die sie ausführt.

  • Schreibe in StateMachine.cs eine einfache Klasse StateMachine mit einer öffentlichen Eigenschaft Current, die nur die Zustandsmaschine setzen kann, einer Methode ChangeState(IState next), die zuerst die Exit-Methode des alten Zustands und dann die Enter-Methode des neuen Zustands ausführt, sowie einer Methode Tick(), die die Tick-Methode des aktuellen Zustands ausführt.
  • Der Spieler fragt in jedem Frame nach seinem Zustand. Deshalb bewirkt ChangeState mit dem bereits aktuellen Zustand nichts: weder Exit noch Enter.
  • Füge in Player.cs ein StateMachine-Feld namens machine hinzu. Erzeuge in Start die Zustandsmaschine und beide Zustände (jeder erhält den Spieler) und beginne mit dem Gehen. Wechsle in Update zum Schleichen, solange die Leertaste gedrückt ist, und andernfalls zum Gehen. Rufe dann die Tick-Methode der Zustandsmaschine auf.

Drücke Play, gehe, halte die Leertaste gedrückt und gehe weiter, dann drücke Check.

Probier es selbst

// StateMachine: Current, ChangeState und Tick
quiz iconTeste dich selbst

Diese Lektion enthält ein kurzes Quiz. Starte die Lektion, um es zu beantworten und deinen Fortschritt zu speichern.

Alle Lektionen in Spielarchitektur in Unity