Menu
CoddyTech

ステートマシン

CoddyのUnityジャーニー「Unityにおけるゲームアーキテクチャ」セクションの一部。レッスン 29/50。

ビーコンのSetStateメソッドは、砲塔、敵、ドアなど、状態を持つすべてのオブジェクトで同じになります。このコードは、現在の状態を保持して切り替えるステートマシンという独立したクラスに置けます。各オブジェクトはコードを繰り返す代わりに、ステートマシンを1つ作って呼び出します。

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

最初のChangeStateでは、終了する状態はありません。Currentはnullで、?.はExitの呼び出しをスキップします。セクション1では、?.はUnityの擬似nullを見落とすと説明しました。これは破棄されたUnityオブジェクトについての話で、状態は通常のC#オブジェクトなので、ここで?.を使っても安全です。Currentにはprivate setがあるため、どのスクリプトもChangeStateとそのExit、Enterを通さずに状態を切り替えることはできません。

2つの状態が同じものに作用する場合、ChangeState内の順序が重要です。Exitで古い状態による変更を元に戻してから、Enterで新しい状態を設定するので、新しい状態が最後に反映されます。DarkStateのEnterがランプを消灯し、BlinkStateのExitより先に実行された場合、そのExitによってランプが再び点灯し、暗い状態ではなくなってしまいます。StateMachineも通常のクラスです。ビーコン、砲塔、敵はそれぞれnewで独自のインスタンスを作り、それぞれのUpdateからそのTickを呼び出します。

challenge icon

チャレンジ

中級

Spaceキーを押したままにすると、しゃがみます。WalkState と SneakState は PlayerStates.cs に用意されています。それぞれの Enter と Exit は何が起きたかをログに出力し(Walk: enter、Sneak: exit...)、Tick はプレイヤーの Move() を呼び出します。それらを実行するマシンを書きましょう。

  • StateMachine.cs に、通常のクラス StateMachine を書きます。このクラスには、マシンだけが設定できる public な Current プロパティ、現在の状態の Exit を実行してから新しい状態の Enter を実行する ChangeState(IState next) メソッド、そして現在の状態の Tick を実行する Tick() メソッドを定義します。
  • プレイヤーは毎フレーム自身の状態を確認するため、すでに現在の状態になっている状態を指定して ChangeState を呼び出した場合は何もしません。Exit も Enter も実行しません。
  • Player.cs に、machine という名前の StateMachine フィールドを追加します。Start でマシンと両方の状態(それぞれプレイヤーを受け取ります)を作成し、歩行を開始します。Update では、Spaceキーを押している間はしゃがむ状態に切り替え、そうでなければ歩行状態に切り替えてから、マシンの Tick を呼び出します。

Play を押し、歩き、Spaceキーを押したまま歩き続けてから、Check を押してください。

自分で試してみよう

// StateMachine: Current、ChangeState、Tick
quiz icon腕試し

このレッスンには短いクイズがあります。レッスンを始めて解答し、進捗を記録しましょう。

Unityにおけるゲームアーキテクチャのすべてのレッスン