Menu
CoddyTech

状態遷移

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

状態がいつ変わるかを決めるのは誰でしょうか?所有者に決めさせると、switchの場合と同じように、すべてのルールがひとつのUpdateに戻ってしまいます。一般的な答えは、それぞれの状態が自分の抜け方を知っている、というものです。Tickの中で条件を確認し、マシンに次の状態を要求します。この爆弾はプレイヤーが近づくまで待ち、その後導火線に火をつけ、プレイヤーが走り去ると待機状態に戻ります:

public class Bomb : MonoBehaviour
{
    public Transform player;
    public StateMachine machine = new StateMachine();
    public IState idle;
    public IState fuse;

    void Start()
    {
        idle = new IdleState(this);
        fuse = new FuseState(this);
        machine.ChangeState(idle);
    }

    void Update() { machine.Tick(); }

    public bool PlayerNear()
    {
        return Vector3.Distance(transform.position, player.position) < 3f;
    }
}

public class IdleState : IState
{
    private Bomb bomb;
    public IdleState(Bomb bomb) { this.bomb = bomb; }

    public void Enter() { }
    public void Exit() { }

    public void Tick()
    {
        if (bomb.PlayerNear()) bomb.machine.ChangeState(bomb.fuse);
    }
}

public class FuseState : IState
{
    private Bomb bomb;
    private float timer;
    public FuseState(Bomb bomb) { this.bomb = bomb; }

    public void Enter() { timer = 2f; }
    public void Exit() { }

    public void Tick()
    {
        if (!bomb.PlayerNear())
        {
            bomb.machine.ChangeState(bomb.idle);
            return;
        }
        timer -= Time.deltaTime;
        if (timer <= 0f)
        {
            Debug.Log("Boom!");
            Object.Destroy(bomb.gameObject);
        }
    }
}

各状態はコンストラクターで爆弾を受け取り、それを通じてマシン、プレイヤーの確認処理、そしてほかの状態にアクセスします。爆弾はStartで各状態を一度ずつ作るため、状態がnewで別の状態を作ることはありません。コンストラクターで互いを作る2つの状態があると、スタックがあふれるまでループしてしまいます。爆弾のUpdateはマシンをTickするだけで、ルールはそれぞれが属する状態に置かれています。2秒間の導火線はFuseStateだけが扱います。

ChangeStateはFuseStateのExitとIdleStateのEnterをすぐに実行しますが、呼び出しの後もFuseStateのTickの残りの処理は実行されます。returnでそれを止めないと、すでに終了した状態の導火線がもう1フレーム燃えてしまいます。DestroyはObject.Destroyと書きます。MonoBehaviourはUnityのObjectクラスからこれを継承しますが、通常のクラスではクラス名を指定する必要があります。

challenge icon

チャレンジ

中級

ハエトリグサは、近づいてきた人にかみつきます。Flytrap.cs の準備はできています。ステートマシンと3つの状態(公開フィールドの open、snap、chew)を作成し、Openから開始して毎フレームステートマシンを更新します。また、PlayerInReach() は、プレイヤーが地面に沿って2未満の距離まで近づいているかどうかを返します。FlytrapStates.cs では、各 Enter(色、タイマー、Chomp! のログ)がすでに記述されています。各状態の Tick に遷移を記述してください。

  • Open:プレイヤーが射程内に入ったら、ハエトリグサがかみつきます。
  • Snap は0.5秒続きます。その後、プレイヤーがまだ射程内にいればハエトリグサはかみつき、逃げていれば再び開きます。
  • Chew は、誰が近くにいても3秒続き、その後ハエトリグサは再び開きます。

矢印キーで Player を動かします。Play を押してハエトリグサに近づき、次にかわしてみてから、Check を押してください。

自分で試してみよう

using UnityEngine;

public class OpenState : IState
{
    private Flytrap trap;

    public OpenState(Flytrap trap)
    {
        this.trap = trap;
    }

    public void Enter()
    {
        trap.Paint(new Color(0.3f, 0.8f, 0.2f));
    }

    public void Tick()
    {
        // プレイヤーが届く範囲に入ったら閉じる
    }

    public void Exit()
    {
    }
}

public class SnapState : IState
{
    private Flytrap trap;
    private float timer;

    public SnapState(Flytrap trap)
    {
        this.trap = trap;
    }

    public void Enter()
    {
        timer = 0f;
        trap.Paint(new Color(1f, 0.55f, 0.1f));
    }

    public void Tick()
    {
        // 0.5 秒後:プレイヤーがまだ届く範囲にいれば噛み、いなければ再び開く
    }

    public void Exit()
    {
    }
}

public class ChewState : IState
{
    private Flytrap trap;
    private float timer;

    public ChewState(Flytrap trap)
    {
        this.trap = trap;
    }

    public void Enter()
    {
        timer = 3f;
        trap.Paint(new Color(0.5f, 0.05f, 0.1f));
        Debug.Log("Chomp!");
    }

    public void Tick()
    {
        // 3 秒後:再び開く
    }

    public void Exit()
    {
    }
}
quiz icon腕試し

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

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