この記事について
この記事は、現在チーム開発を行っているチームメンバー向けに書いた内容となっていますので予めご了承ください。
作成するスクリプト
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では移動と回転処理を実行するという内容になりました。複数行いたいステートがある時はこのようにまとめるステートクラスを作ると解決出来ます。