0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ステートマシンの使い方

Last updated at Posted at 2024-02-11

この記事について

この記事は、現在チーム開発を行っているチームメンバー向けに書いた内容となっていますので予めご了承ください。

作成するスクリプト

3つのスクリプトを作成して下さい。
スクリプト名は担当箇所+末尾が名詞単体もしくはerである事。

・管理クラス  (Manager,Controllerなど)
・登録クラス  (Register)
・ステートクラス(Move,Rotationなど ※今回は2つ作ります

// 管理クラス
public class HamsterController : MonoBehaviour
{
    private void Start()
    {
    
    }

    private void Update()
    {
    
    }
}

// 登録クラス
public class HamsterComponentRegister : MonoBehavior
{
    private void Start()
    {
    
    }

    private void Update()
    {
    
    }
}

// ステートクラスはStateを継承します
public class HamsterIdler : State
{
    // overrideを使うとStateクラスのメソッドを利用できます
    public override void OnEnter()
    {

    }

    public override void OnExit()
    {

    }

    public override void OnUpdate()
    {

    }
}

public class HamsterMover : State
{
    // 略
}

管理クラス

・管理クラスにStateMachineBaseの変数を追加します。

public class HamsterController : MonoBehaviour
{
    // Stateを継承したベースクラス
    private StateMachineBase<State> stateMachineBase;
    
    // 略
}

・ロケーターからベースクラスを取得して初期化を行います

public class HamsterController : MonoBehaviour
{
    // 略

    private void Start()
    {
        // ロケーターからベースクラスを取得する
        stateMachineBase = Locator<StateMachineBase<State>>.GetInstance();
        InitStateMachineBase();
    }

    // 略
    
    // StateMahcineBaseを初期化する
    private void InitStateMachineBase()
    {
        // LocatorからIdleスクリプトを取得する
        var idle = Locator<Idle>.GetInstance();

        // ハムスターをidleステートに初期化する
        stateMachineBase.InitState(idle);
    }
}

これでステートマシンの初期化をする事が出来ました。
IdlerクラスのOnEnterメソッドにDebug.Logを書いて実行すると開始時にDebug.Logが呼ばれている事が分かると思います。

・StateMachineBaseのUpdateメソッドを追加します

public class HamsterController : MonoBehaviour
{
    // 略
    
    private void Update()
    {
        // StateMachineBaseのOnUpdateを実行する
        stateMachineBase.OnUpdate();
    }

    // 略
}

これでステートのUpdateを行えるようになりました。
最初に、stateMachineBase.InitState(HamsterIdler);でIdlerステートに初期化をしているので、
現在はIdlerクラスのOnUpdate処理が実行され続けています。

・ここまでの内容を実装した管理クラス

public class HamsterController : MonoBehaviour
{
    // Stateを継承したベースクラス
    private StateMachineBase<State> stateMachineBase;

    private void Start()
    {
        // ロケーターからベースクラスを取得する
        stateMachineBase = Locator<StateMachineBase<State>>.GetInstance();
        InitStateMachineBase();
    }

    private void Update()
    {
        // ステートのUpdateを実行する
        // 最初にidleステートに初期化したので、idleのUpdateが実行される
        stateMachineBase.OnUpdate();
    }

    // ステートマシンを初期化する
    private void InitStateMachineBase()
    {
        // LocatorからIdleスクリプトを取得する
        var idle = Locator<Idle>.GetInstance();

        // ハムスターをidleステートに初期化する
        stateMachineBase.InitState(idle);
    }
}

登録クラス

登録クラスではUnityコンポーネントを取得したり、ステートクラスに必要なスクリプトの取得を行います。

using StateMachine;
using UnityEngine;
using Utility;

public class HamsterComponentRegister : MonoBehavior
{
    private StateMachineBase<State> stateMachineBase = new StateMachineBase<State>();
    private Idle idle = new Idle();
    private Move move = new Move();
    
    private void Awake()
    {
        // ロケーターにスクリプトを登録する
        // ロケーターの引き数には(登録したい物, 登録番号)を設定する事が出来ます
        // 1番はプレイヤー、2番はエネミーと登録する場所を分けて管理出来ます
        // どの番号を使うかは各自話し合ってください
        
        // Locatorに登録する
        Locator<StateMachineBase<State>>.Register(stateMachineBase);
        Locator<Idle>.Register(idle);
        Locator<Move>.Register(move);
    }
}

ステートクラス

コードの内容を追加して下さい。

using StateMachine;
using UnityEngine;

// ステートクラスはStateを継承します
public class Idle : State
{
    private StateMachineBase<State> stateMachineBase;
    private Move move;
    private bool isInit = false;
    
    public override void Init()
    {
        if (!isInit)
        {
            stateMachineBase = Locator<StateMachineBase<State>>.GetInstance();
            move = Locator<Move>.GetInstance();
            AddTransition();
            isInit = true;
        }
    }


    public override void OnEnter()
    {
        Init();
        Debug.Log("立ち止まった");
    }

    public override void OnExit()
    {
        Debug.Log("立ち止まるのをやめた");
    }

    public override void OnUpdate()
    {
    
    }

    private void AddTransition()
    {
        stateMachineBase.AddTransition(this, move);
    }
}

・ベース変数の遷移メソッドを実行する

// ステートクラスはStateを継承します
public class HamsterIdle : State
{
    // 略
    
    public override void OnUpdate()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            stateMachineBase.TransitionTo(this, move);
        }
    }

    // 略
}

Moverクラスにはこれの反対条件を追加してステートの動きを確認してください。
問題なくステートが切り替わればこれで全ての実装は終了となります。

複数のステートを実装したい時

複数のステートを同時に行い時もあると思います。アクションゲームで例えると移動しながらジャンプするなどのステート+ステートを同時に行いたい時です。

そのような時はステートクラスと行いたい処理のクラスに分けてステートクラスで実装すると解決出来ます。

public class PlayerStateMove : State
{
    // Stateを継承したベースクラス
    private StateMachineBase<State> stateMachineBase;
    
    // 移動だけを行うクラス
    private State playerMove;

    // 回転だけを行うクラス
    private State playerRotation;
    
    private bool isInit = false;
  
    public override void OnEnter()
    {
        Init();
    }

    public override void OnExit()
    {

    }

    public override void OnUpdate()
    {
        playerMove.OnUpdate();
        playerRotation.OnUpdate();
    }

    public override void Init()
    {
        if(!isInit)
        {
            // ロケーターからスクリプトを取得する
            stateMachineBase = Locator<StateMachineBase<State>>.GetInstance();
            playerMove = Locator<PlayerMover>.GetInstance();
            playerRotation = Locator<PlayerRotation>.GetInstance();
            
            // コンポーネントの初期化処理を行う
            // やる事はこのクラスと同じです
            playerMove.Init();
            playerRotation.Init();
            isInit = true;
        }
    }
}

このように実装する事で、PlayerStateMoveでは移動と回転処理を実行するという内容になりました。複数行いたいステートがある時はこのようにまとめるステートクラスを作ると解決出来ます。

0
2
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?