Stany jako klasy
Część sekcji Architektura gier w Unity ścieżki Unity w Coddy. Lekcja 28 z 50.
Sekcja 3 pokazuje przełącznik oparty na wyliczeniu, który skupia obsługę każdego stanu w jednej metodzie Update. Takie rozwiązanie przestaje się skalować, gdy stany mają własne dane: timer używany tylko przez jeden stan staje się polem MonoBehaviour, obok pól wszystkich pozostałych stanów, a każdy przypadek musi pamiętać o resetowaniu używanych danych. Wzorzec stanu z C# przypisuje każdemu stanowi własną klasę, a każda klasa implementuje jeden interfejs. Ta lampa drogowa miga lub świeci światłem ciągłym, a klawisz Space przełącza między tymi dwoma stanami:
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();
}
}Stany są zwykłymi klasami C#, a nie MonoBehaviour. Tworzysz je za pomocą new i przekazujesz im potrzebne dane przez konstruktor — tutaj Renderer lampy — ponieważ nie są komponentami i nie mogą wywoływać GetComponent ani wyświetlać pól w Inspectorze. Unity również nie wywołuje ich metod: Beacon jest MonoBehaviour, więc jego Update wywołuje current.Tick() w każdej klatce.
timer należy wyłącznie do BlinkState, a jego Enter ustawia go na 0 za każdym razem, gdy lampa zaczyna migać. Exit sprząta po zakończeniu stanu: Space można nacisnąć, gdy lampa jest wyłączona, a Exit włącza ją z powrotem, więc SteadyState nigdy nie rozpoczyna działania przy zgaszonej lampie. SetState uruchamia Exit poprzedniego stanu, a następnie Enter nowego stanu. Trzeci stan, taki jak powolne pulsowanie, wymaga tylko jednej dodatkowej klasy, a Update w Beacon pozostaje bez zmian.
Wyzwanie
ŚredniWieżyczka strażnicza pilnuje podwórka. Strzałkami steruj obiektem Player (gotowy). Nadaj wieżyczce dwa stany zapisane jako klasy:
- W pliku
IState.cszadeklarujpublic interface IStatez metodamivoid Enter(),void Tick()ivoid Exit(). - W pliku
TurretStates.csnapisz dwie zwykłe klasy, które implementują ten interfejs.ScanStatepobiera głowicę wieżyczki w konstruktorze. Zamiata głowicą z boku na bok: lokalny kąt y głowicy zmienia się z szybkością 90 stopni na sekundę, między-45a45, zaczynając od 0 i za każdym razem, gdy rozpoczyna się skanowanie, obracając się w górę. Jego metoda Enter koloruje również głowicę naColor.green. AlertStatepobiera głowicę i gracza. Jego metoda Enter koloruje głowicę naColor.redi zapisuje w loguIntruder!; metoda Tick obraca głowicę tak, aby była skierowana w stronę gracza wyłącznie wokół osi y, bez przechylenia; metoda Exit zapisuje w loguAll clear.- W pliku
Turret.csutwórz oba stany w metodzie Start i rozpocznij skanowanie. W każdej klatce przełączaj się na stan alarmu, gdy gracz znajduje się bliżej wieżyczki niżrange(4), a gdy nie, wracaj do skanowania, a następnie uruchamiaj metodę Tick bieżącego stanu. Przy zmianie uruchom metodę Exit starego stanu, a następnie metodę Enter nowego stanu.
Naciśnij Play, podejdź do wieżyczki, a potem oddal się od niej i naciśnij Check.
Spróbuj swoich sił
using UnityEngine;
// ScanState i AlertState
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
1Komponenty, nie hierarchie
Małe komponentyPodstawowy skrypt przeciwnikaKomponenty abstrakcyjneWspółpracujące komponentyPodsumowanie: modułowa wieżyczka4Dane serializowane
Klasy serializowalneListy w InspectorzeWyliczenia w InspectorzePodsumowanie: tabela łupów10Projekt: Arena przetrwania
BohaterTypy wrogów2Interfejsy w Unity
IDamageableInterfejsy i TryGetComponentGetComponentsPodsumowanie: klawisz interakcji5ScriptableObjects
Zasoby danychStatystyki broniWspółdzielone ustawieniaFale jako danePowtórka: baza danych przedmiotów8Kod wielokrotnego użytku
Metody rozszerzająceGeneryczny singletonGeneryczne metody pomocniczePodsumowanie: FindNearest