Unity ステートマシンベースのプロセス制御

 ゲームを作るときはプロセス制御を行うことが多く、プロセス制御には動作決定木やステートマシンなど、さまざまな手法があります。本質的な違いは大きくなく、各実行ロジックを一つ一つノード化し、条件に応じてあるノードが実行されたり、あるノードに切り替わったりするだけである。今日はステートマシンに基づいてゲームプロセスを制御する方法を共有したいと思います。

1 単純なステートマシンのケース

  まず、誰もがステート マシンのプロセス制御の基本を理解できるように、ユース ケースを分解しましょう。まず、いくつかの状態ノードを構築し、それらを状態マシンに置きます。次のように疑似コードを記述します。

ステート マシンを作成します: FiniteStateMachine _fsm = new  FiniteStateMachine()

プロセスの状態を制御するすべての論理ノードをステート マシンに追加します。

_fsm.AddNode( new  NodeInit());

_fsm.AddNode( new  NodeLogin());

_fsm.AddNode( new  NodeTown());

初期化論理ノードNodeInitは初期化ロジック制御に使用され、NodeLoginはログインシーンのロジック制御に使用され、NodeTownノードはゲーム戦闘シーンのロジック制御に使用されます。

各ステート マシン ノードには、いくつかの統一された固定入口があります。これらの入口がどのように設計されるかは、業界に関連しています。たとえば、ゲーム業界では、ステート マシン ノード インターフェイスの設計は一般に次のとおりです:

名前: ステート マシン ノードの名前。

OnEnter: ステート マシンがこのステート ノードに入ったときに実行され、通常は初期化に使用されます。

OnExit: ステート マシンがこのステート ノードを開くときに実行されます。通常、一部のリソースはユーザーが終了すると破棄され、解放されます。

OnUpdate: ステート マシン ノードの更新はフレームごとに呼び出され、各フレームで処理される多くのトランザクションを OnUpdate に配置できます。

OnFixedUpdate: 各FixedUpdateはステートマシンのOnFixedUpdate関数を呼び出します。固定回数の反復を持つ一部の更新をこのインターフェイスに配置できます。

OnHandleMessage(object msg): このインターフェイスは、ステート マシン ノードに対してイベント メッセージがトリガーされたときに呼び出され、ステート マシン ノードがイベント メッセージを処理するための制御エントリとして機能します。

各ステート マシン ノードは IFsmNode に対応するインターフェイスを実装し、統合管理のためにステート マシン内に配置されます。この場合、ゲームの開始時にまず NodeInit ステータス ノードを実行して、ゲームの初期化を完了します。

public  void  StartGame()

{

_fsm.Run(nameof(NodeInit));

}

まず NodeInit ノード処理のロジックを見てみましょう. NodeInit は OnEnter に初期化関連のロジックのみを実装しており、他のインターフェイスにはロジック処理はありません。コードは以下のように表示されます

void  IFsmNode.OnEnter()

{

AudioPlayerSetting.InitAudioSetting();

//コルーチンを使用して初期化します

MotionEngine.StartCoroutine(Init());

}

プライベート IEnumerator Init()

{

// UIRootをロードする

var  uiRoot = WindowManager.Instance.CreateUIRoot<CanvasRoot>( "UIPanel/UIRoot" );

yield 戻り uiRoot;

//常駐パネルをロードします

yield  return  GameObjectPoolManager.Instance.CreatePool( "UIPanel/UILoading" , true );

//ログインプロセスに入る

FsmManager.Instance.Change(nameof(NodeLogin));

}

上記のコードに示すように、ステート マシンが NodeInit ノード ステートを実行すると、初期化中に OnEnter インターフェイスが呼び出されます。NodeInit の OnEnter インターフェイスでは、初期化のために Init 関数が呼び出されます。まず、UIRoot が作成され、次に、リソース ロード インターフェイスが表示されます。出てきて、リソースのロードが完了したら、ログイン論理ノード シーンに入ります。ここで、ステート マシンが元の NodeInit から NodeLogin ステート マシン ノードに切り替わることに注意してください。NodeLogin ノードに入ると、OnEnter インターフェースが実行されます。次に、ログイン ノードの論理処理を次のように見てみましょう。

void  IFsmNode.OnEnter()

{

var  uiwindow = UITools.OpenWindow<UILogin>();

uiwindow.Completed += Uiwindow_Completed;

文字列 シーン名 = "シーン/ログイン" ;

SceneManager.Instance.ChangeMainScene(sceneName, null );

}

図に示すように、ログイン UI インターフェイスを表示し、同時にシーンをログイン シーンに切り替えます。これにより、ステート マシン制御ロジックがログイン シーンに切り替わります。

次に、ユーザー名とパスワードを入力し、[ゲームの実行] ボタンをクリックして、ゲームの実行ボタンがどのように処理されるかを確認します。

プライベート void  OnClickLogin()

{

//ログインイベントを送信

var  message =新しい LoginEvent.ConnectServer

{

アカウント = _account.text,

パスワード = _password.text

};

EventManager.Instance.SendMessage(メッセージ);

}

ステート マシン ノードのイベント処理関数を呼び出すことができるように、ログイン イベント メッセージをステート マシンのノードに送信します。

プライベート void  OnHandleEvent(IEventMessage msg)

{

if (メッセージ LoginEvent.ConnectServer)

{

FsmManager.Instance.Change(nameof(NodeTown));

}

}

イベント処理関数で、ステート マシンを呼び出して、実行する NodeTown ステート マシン ノードに切り替えます。最後に、NodeTown ゲームの戦闘シーンでのノード処理を見てみましょう。OnEnter インターフェイスは次のように初期化されます。

void  IFsmNode.OnEnter()

{

string  sceneName = "シーン/タウン" ;

SceneManager.Instance.ChangeMainScene(sceneName, OnSceneLoad);

UITools.OpenWindow<UILoading>(シーン名);

UITools.OpenWindow<UIMain>();

AudioManager.Instance.PlayMusic( "オーディオ/音楽/街" , true );

}

ゲームの戦闘シーンに切り替わり、戦闘のメインUIが表示されゲームのBGMが再生されます。他のインターフェイスを見てみましょう。OnUpdateゲーム ワールドの変更を繰り返し、OnExit はゲーム ワールドを削除してリソースを解放します。コードは次のとおりです:

void  IFsmNode.OnUpdate()

{

if  (_initWorld)

_gameWorld.Update();

}

void  IFsmNode.OnFixedUpdate()

{

}

void  IFsmNode.OnExit()

{

_gameWorld.Destroy();

UITools.CloseWindow<UIMain>();

}

写真が示すように:

このケースの分析を通じて、ゲーム ステート マシンの設計を決定しました。これは次のように要約されます。

ステップ 1: いくつかのゲーム ステート ノードを設計し、ノードにいくつかの特定の論理処理インターフェイスを実装します。

ステップ 2:ゲームステート ノードをゲーム ステート マシンに追加します。

ステップ 3: ステート マシンの「スイッチ ノード」インターフェイスを作成します。ノードに入る前に、最初に前のノードの OnExit インターフェイスを呼び出し、次に新しいノードの OnEnter インターフェイスを呼び出します。ゲームのニーズに応じて、各更新、FixedUpdate、反復ステート マシン ノードの OnUpdate インターフェイスと OnFixedUpdate インターフェイス。

2 ステートマシン制御に基づく具体的な実装と設計

  上記の分析により、ステート マシンについて非常に明確に理解できました。当然、ゲームのジャンプ コントロール ロジックを制御するステート マシンを設計するのは非常に簡単です。ゲーム内のステート マシン ベースの制御を「」に分割します。これは、 「プロジェクトとは無関係」「ゲーム プロジェクトに関連する」の 2 つの部分で設計および処理されます。まず、「プロジェクトに関係のない」ステート マシン部分の設計を見てみましょう: 2 つのコード: IFsmNode.cs と FiniteStateMachine.cs. IFsmNode.cs コードは、ステート マシン ノードのインターフェイスを定義します。上記のコードはゲーム開発用に提供されており、ステート マシン ノードの共通インターフェイスです。開発者が特定のビジネス ロジックを実装する場合、このインターフェイスを継承して実装するだけで済みます。

FiniteStateMachine.cs は主にステート マシン ノードの管理を実装しており、主なデータ メンバーとインターフェイスは次のとおりです。

private  readonly  List<IFsmNode> _nodes = new  List<IFsmNode>();すべてのステート マシン ノードを保存するデータ メンバーを定義します。

プライベート IFsmNode _curNode;

プライベート IFsmNode _preNode;

2 つのデータ メンバー curNode と prevNode を定義して、現在実行中のステータス ノードと以前のステータス ノードを保存します。

public  void  AddNode(IFsmNode node) は、新しい状態ノードを状態マシンに追加するインターフェイスを定義します。

public  void  Run( stringentryNode  )は、最初のステータス ノードを実行するためのインターフェイスとしてインターフェイスを定義します。

public  void  Transition( string  nodeName)は、現在の状態から新しいステート マシン ノードに切り替えるためのインターフェイスとしてインターフェイスを定義します。

Update に基づいて、現在実行されているステート マシン ノードの Update、FixedUpdate、および HandleMessage インターフェイスを呼び出します。

public  void  Update()

{

if  (_curNode != null )

_curNode.OnUpdate();

}

public  voidFixedUpdate  ()

{

if  (_curNode != null )

_curNode.OnFixedUpdate();

}

public  void  HandleMessage( object  msg)

{

if  (_curNode != null )

_curNode.OnHandleMessage(msg);

}

これにより、ステート マシン ノードの関連インターフェイスの呼び出しと実行が行われます。FiniteStateMachine と IFsmNode の 2 つのコードを記述した後、ステート マシンが設計されました。次のステップは、それを特定のゲーム プロジェクトで使用することです。つまり、使用に関連するコードです。実際は非常に簡単で、主なステップは 3 つあります

ステップ 1: ステート マシン オブジェクトを作成します。

ステップ 1: ステート マシンの論理ノードを追加したい場合は、IFsmNode を継承し、関連するインターフェイスを実装し、論理ノードをステート マシン オブジェクトに配置して一元管理するだけです。

ステップ 3: ビジネス ロジックに従って、実行中のステート マシンのノードを切り替えます。ロジック制御の目的を達成するため。

3: ステートマシンに基づいて特別なステート制御を拡張する

  ステート マシンの設計が完了したら、最も一般的な逐次実行ステート マシン ProcedureFsm など、ステート マシンに基づいて特別なステート制御を実行して、ロジック コードをより明確にし、保守しやすくすることもできます。つまり、1 つの状態ノードを実行した後、2 番目の状態ノードがすぐに実行されます。この方法では、ホット アップデートのシーケンシャル プロセス ステート マシンなどのシーケンシャル プロセスを実行するのに非常に便利です。 

   1: バージョンステータスノードを確認します。

   2: 増分ダウンロード情報比較ノード。

   3: リソース ノードを増分ダウンロードします。

   4: ダウンロードが完了したら、ゲームノードに入ります。

これらのステート マシン ノードを ProcedureFsm に追加すると、最初のノードから実行が開始され、後続の各ノードが順番に実行されます。

プロジェクト内のロジック制御としてステート マシンを使用するかどうかは、特定のニーズに基づいて分析できます。絶対的な善悪はなく、自分に合ったものを選べば良いのです。

おすすめ

転載: blog.csdn.net/Unity_RAIN/article/details/134176932