実はちょうど一年くらい前に公開した、ステートマシンを実装したサンプルプロジェクトを配布しているのですが、改めてそのプロジェクトの解説を聞いてみたいという方がいましたので、公開後一年を経過しておりますが改めて解説したいと思います。
プロジェクトは以下のURLにあります。
ちなみに既にUE4.11には対応済みです。ダウンロード後にZipファイルを解凍すればあとはuprojectファイルを開くだけですぐに中を見ることができます。
コンポーネントベースのステートマシン
UE4には標準で利用可能なステートマシンのシステムはありません。アニメーションにはありますが、それ以外のシステムには応用することができません。
実はUE3の時代にはUnrealScriptにステートマシンの仕組みが実装されていましたが、ブループリントには同様の仕組みはありません。ブループリントにも同様のステートマシンの仕組みが欲しいところですが、それは今のところ実装される可能性がなさそうなので、自前で実装してみました。
この仕組みはコンポーネントをベースにして、あくまでも汎用的に利用できるようにしています。利用するにはまずコンポーネントを理解しておく必要があります。
まずこのステートマシンシステムには必ず"StateMachineComponent"をブループリントのアクターに追加する必要があります。"StateMachineComponent"はステートマシンシステム全体を管理するマネージャーのようなものです。それとは別に"StateComponent"を継承したブループリントコンポーネントに追加します。
これでアクター上で利用可能となりました。
ステートの追加と起動
コンポーネントを追加した後に、ステートを追加する必要があります。更にその後に最初に起動させるステートを指定します。
ステートはイベントグラフ上で"Add State"ノードを使用して追加します。"Remove State"ノードを使えば追加したステートを削除することも可能です。"Launch State"でどのステートで起動させるかを指定すれば、その後にステートが起動します。
ステートコンポーネントについて
各ステートは"StateComponent"を継承してクラスを作成すれば独自に作成可能です。"StateComponent"はブループリントインターフェースにより、3つのイベントが定義されています。
"Event On State Begin"、"Event On State Tick"、"Event On State End"の3つです。
これらはアクターに標準で用意されている、"Event BeginPlay"、"Event Tick"、"Event EndPlay"と同様ですが、このイベントは"StateComponent"内部で呼び出されますので、それぞれのステート毎に個別のロジックを実装可能です。
次はステートの切り替えです。
ステートの切り替えには"Transition State"ノードを使用します。そこで"StateName"にステート名を入力します。これは作成したコンポーネント名をそのまま入力すればOKです。ここでステート名を間違えるとログが表示され、何も起きません。
ステートを切り替えると、まずは現在のステートの"Event On End"が呼び出されます。その直後に遷移ステートの"Event On Begin"が呼び出されて、その後は毎フレーム"Event On Tick"が呼び出されるようになります。あとはロジックを自由に実装してステートマシンを利用するだけです。
使用する際の工夫
最後にいくつかコンポーネントを利用する際に工夫していることを解説したいと思います。
コンポーネントとタイムラインの相互利用
通常はコンポーネント内部ではタイムラインノードを利用することができません。このサンプルではコンポーネントを追加するアクター側でタイムラインノードを作成し、ステート内部に移動用に変数を作成しておき、その結果を直接渡すことによって外部からタイムラインノードを利用できるように工夫しています。
ここでイベントが定義されていますが、これはステート内部で宣言したイベントディスパッチャー経由のイベントです。Add Stateの段階でイベントバインドをしています。