Gli stati come classi
Fa parte della sezione Architettura dei giochi in Unity del percorso Unity di Coddy. Lezione 35 di 64.
Lo switch su un enum della sezione 3 mantiene il lavoro di ogni stato in un unico Update. Questo approccio non è scalabile quando gli stati hanno dati propri: un timer usato da un solo stato finisce per essere un campo di MonoBehaviour, accanto ai campi di tutti gli altri stati, e ogni case deve ricordarsi di reimpostare ciò che usa. Il pattern degli stati di C# assegna a ogni stato una classe dedicata e ogni classe implementa la stessa interfaccia. Questo segnalatore stradale lampeggia o resta acceso, e Space alterna le due modalità:
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();
}
}Gli stati sono classi C# semplici, non MonoBehaviours. Li crei con new e fornisci loro ciò di cui hanno bisogno tramite il costruttore, in questo caso il Renderer della lampada, perché non sono componenti e non possono chiamare GetComponent né mostrare campi nell'Inspector. Unity non chiama nemmeno i loro metodi: Beacon è il MonoBehaviour, quindi il suo Update chiama current.Tick() a ogni frame.
Il timer appartiene solo a BlinkState e il suo Enter lo imposta a 0 ogni volta che il segnalatore inizia a lampeggiare. Exit riporta tutto alla normalità quando lo stato termina: Space può essere premuto mentre la lampada è spenta ed Exit la riaccende, così SteadyState non inizia mai con la lampada spenta. SetState esegue Exit dello stato precedente, poi Enter del nuovo stato. Un terzo stato, come un impulso lento, richiede un'altra classe e Update di Beacon non cambia.
Sfida
MedioScrivi lo stato di scansione della torretta.
- In
IState.cs, dichiarapublic interface IStateconvoid Enter();,void Tick();evoid Exit();. - In
TurretStates.cs, scriviScanState : IState, passando la testa. Enter: angolo 0, testaColor.green. Tick: fai oscillare l'angolo y locale della testa tra-45e45, a90gradi al secondo. Turret: inseriscine uno in Start e aggiornalo con Tick in Update.
Premi «Gioca»: la testa verde oscilla. Poi premi «Verifica».
Provalo tu
using UnityEngine;
// ScanState
Tutte le lezioni di Architettura dei giochi in Unity
1Componenti, non gerarchie
Componenti piccoliUno script base per i nemiciComponenti astrattiComponenti che collaboranoRipasso: torretta modulareRipasso: cannone doppio4Dati serializzati
Classi serializzabiliElenchi nell'InspectorEnum nell'InspectorRiepilogo: tabella del bottinoRiepilogo: tira il bottino7Macchine a stati
Gli stati come classiLo stato di allertaUna macchina a statiTransizioniIntelligenza dei nemiciIl cavaliere attaccaRiepilogo: stati delle porte2Interfacce in Unity
IDamageableInterfacce e TryGetComponentGetComponentsRiepilogo: tasto InteragisciRiepilogo: il più vicino a portata5ScriptableObjects
Asset di datiStatistiche delle armiImpostazioni condiviseSalva il ventoOnde come datiRiepilogo: database degli oggettiRiepilogo: comprare dal negozioEsercitati da solo: Playground Unity