Menu
CoddyTech

ステートマシン

CoddyのUnityジャーニー「Unityのゲームアーキテクチャ」セクションの一部。レッスン 37/64。

Beaconの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

チャレンジ

中級

プレイヤーの準備状態をステートマシンで実行します。

  1. StateMachine.csで、public class StateMachineを記述し、public IState Current { get; private set; }と、状態を更新するTick()を追加します。
  2. ChangeState(IState next)では、現在の状態と同じ場合は何もしません。それ以外の場合は、Exitを呼び出し、Currentを設定してからEnterを呼び出します。
  3. Playerでは、Startでmachine、walk、sneakを作成して歩行状態にします。Updateでは、Spaceキーを押している間はしゃがみ、そうでなければ歩行してから、状態を更新します。

「プレイ」を押してSpaceキーを押し続けると、Sneak: enterと表示されます。その後、「確認」を押します。

自分で試してみよう

// StateMachine: Current、ChangeState、Tick

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

自分で練習してみよう: Unityプレイグラウンド