Zustände als Klassen
Teil des Abschnitts Spielarchitektur in Unity der Unity-Journey von Coddy. Lektion 35 von 64.
Der Schalter über eine Enumeration in Abschnitt 3 bündelt die Arbeit aller Zustände in einem einzigen Update. Das lässt sich nicht mehr gut erweitern, sobald Zustände eigene Daten haben: Ein Timer, den nur ein Zustand verwendet, wird zu einem Feld des MonoBehaviour, neben den Feldern aller anderen Zustände, und jeder Fall muss daran denken, das jeweils Verwendete zurückzusetzen. Das Zustandsmuster aus C# gibt jedem Zustand eine eigene Klasse, und jede Klasse implementiert dieselbe Schnittstelle. Dieses Straßenleuchtfeuer blinkt oder bleibt eingeschaltet, und die Leertaste wechselt zwischen den beiden Zuständen:
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();
}
}Die Zustände sind einfache C#-Klassen, keine MonoBehaviours. Du erstellst sie mit new und übergibst ihnen über den Konstruktor, was sie benötigen – hier den Renderer der Lampe –, denn sie sind keine Komponenten und können weder GetComponent aufrufen noch Felder im Inspector anzeigen. Unity ruft ihre Methoden ebenfalls nie auf: Beacon ist das MonoBehaviour, daher ruft sein Update in jedem Frame current.Tick() auf.
Der timer gehört allein zu BlinkState, und sein Enter setzt ihn jedes Mal auf 0, wenn das Leuchtfeuer zu blinken beginnt. Exit räumt auf, wenn der Zustand endet: Die Leertaste kann gedrückt werden, während die Lampe ausgeschaltet ist, und Exit schaltet sie wieder ein, sodass SteadyState nie mit einer dunklen Lampe beginnt. SetState führt Exit des alten Zustands aus und danach Enter des neuen Zustands. Ein dritter Zustand, etwa ein langsames Pulsieren, ist eine weitere Klasse, und Beacons Update ändert sich nicht.
Aufgabe
MittelSchreibe den Scan-Zustand des Geschützturms.
- Definiere in
IState.cspublic interface IStatemitvoid Enter();,void Tick();undvoid Exit();. - Schreibe in
TurretStates.csScanState : IState, der den Kopf übergeben wird. Enter: Winkel 0, KopfColor.green. Tick: Schwenke den lokalen y-Winkel des Kopfes zwischen-45und45mit90Grad pro Sekunde. Turret: Starte einen Zustand in Start und führe Tick in Update aus.
Drücke „Spielen“: Der grüne Kopf schwenkt. Drücke dann „Prüfen“.
Probier es selbst
using UnityEngine;
// ScanState
Alle Lektionen in Spielarchitektur in Unity
1Komponenten statt Hierarchien
Kleine KomponentenEin Basis-GegnerskriptAbstrakte KomponentenZusammenwirkende KomponentenRückblick: Modulares GeschützRückblick: Zwillingskanone4Serialisierte Daten
Serialisierbare KlassenListen im InspectorEnums im InspectorRückblick: Loot-TabelleRückblick: Beute auswürfeln7Zustandsautomaten
Zustände als KlassenDer AlarmzustandEin ZustandsautomatÜbergängeGegner-KIDer Ritter greift anRückblick: Türzustände2Schnittstellen in Unity
IDamageableSchnittstellen und TryGetComponentGetComponentsZusammenfassung: InteraktionstasteZusammenfassung: Nächstes in Reichweite5ScriptableObjects
Daten-AssetsWaffenwerteGemeinsame EinstellungenDen Wind speichernWellen als DatenRückblick: Item-DatenbankRückblick: Im Shop einkaufen8Wiederverwendbarer Code
ErweiterungsmethodenEin generisches SingletonGenerische HilfsmethodenRückblick: FindNearestÜbe selbstständig: Unity-Playground