Let's Enjoy Unreal Engine

Unreal Engineを使って遊んでみましょう

UE4 コンポーネントベースのステートマシンについて

実はちょうど一年くらい前に公開した、ステートマシンを実装したサンプルプロジェクトを配布しているのですが、改めてそのプロジェクトの解説を聞いてみたいという方がいましたので、公開後一年を経過しておりますが改めて解説したいと思います。

プロジェクトは以下のURLにあります。

github.com

ちなみに既にUE4.11には対応済みです。ダウンロード後にZipファイルを解凍すればあとはuprojectファイルを開くだけですぐに中を見ることができます。

コンポーネントベースのステートマシン

UE4には標準で利用可能なステートマシンのシステムはありません。アニメーションにはありますが、それ以外のシステムには応用することができません。

実はUE3の時代にはUnrealScriptにステートマシンの仕組みが実装されていましたが、ブループリントには同様の仕組みはありません。ブループリントにも同様のステートマシンの仕組みが欲しいところですが、それは今のところ実装される可能性がなさそうなので、自前で実装してみました。

この仕組みはコンポーネントをベースにして、あくまでも汎用的に利用できるようにしています。利用するにはまずコンポーネントを理解しておく必要があります。

まずこのステートマシンシステムには必ず"StateMachineComponent"をブループリントのアクターに追加する必要があります。"StateMachineComponent"はステートマシンシステム全体を管理するマネージャーのようなものです。それとは別に"StateComponent"を継承したブループリントコンポーネントに追加します。

f:id:alwei:20160430084944p:plain

これでアクター上で利用可能となりました。

ステートの追加と起動

コンポーネントを追加した後に、ステートを追加する必要があります。更にその後に最初に起動させるステートを指定します。

f:id:alwei:20160430092323p:plain

ステートはイベントグラフ上で"Add State"ノードを使用して追加します。"Remove State"ノードを使えば追加したステートを削除することも可能です。"Launch State"でどのステートで起動させるかを指定すれば、その後にステートが起動します。

ステートコンポーネントについて

各ステートは"StateComponent"を継承してクラスを作成すれば独自に作成可能です。"StateComponent"はブループリントインターフェースにより、3つのイベントが定義されています。

f:id:alwei:20160430100637p:plain

"Event On State Begin"、"Event On State Tick"、"Event On State End"の3つです。

これらはアクターに標準で用意されている、"Event BeginPlay"、"Event Tick"、"Event EndPlay"と同様ですが、このイベントは"StateComponent"内部で呼び出されますので、それぞれのステート毎に個別のロジックを実装可能です。

次はステートの切り替えです。

f:id:alwei:20160430103651p:plain

ステートの切り替えには"Transition State"ノードを使用します。そこで"StateName"にステート名を入力します。これは作成したコンポーネント名をそのまま入力すればOKです。ここでステート名を間違えるとログが表示され、何も起きません。

ステートを切り替えると、まずは現在のステートの"Event On End"が呼び出されます。その直後に遷移ステートの"Event On Begin"が呼び出されて、その後は毎フレーム"Event On Tick"が呼び出されるようになります。あとはロジックを自由に実装してステートマシンを利用するだけです。

使用する際の工夫

最後にいくつかコンポーネントを利用する際に工夫していることを解説したいと思います。

コンポーネントとタイムラインの相互利用

通常はコンポーネント内部ではタイムラインノードを利用することができません。このサンプルではコンポーネントを追加するアクター側でタイムラインノードを作成し、ステート内部に移動用に変数を作成しておき、その結果を直接渡すことによって外部からタイムラインノードを利用できるように工夫しています。

f:id:alwei:20160430111347p:plain

ここでイベントが定義されていますが、これはステート内部で宣言したイベントディスパッチャー経由のイベントです。Add Stateの段階でイベントバインドをしています。

コンポーネント内でアクターの情報を参照する方法

コンポーネント内では直接追加されているアクター側の情報を参照できるわけではありませんが、"Get Owner"ノードを使えば親アクターの情報を参照することが可能です。

f:id:alwei:20160430114152p:plain

親アクターのクラスを直接参照する場合にはキャストやインターフェースを活用する必要があります。これでコンポーネントからアクターの情報を参照することができるので、自由にアクター側を操作することが可能となり、よりコンポーネントの汎用性が増すことになります。

アクター側から強制的にステートを変更する

本来ステートはコンポーネント内部から切り替えを行いますが、アクター側からStateMachineComponentの"SwitchState"ノードを利用することで、コンポーネント内部を無視して強制的にステート変更が可能です。

f:id:alwei:20160430114731p:plain

このような使い方は本来のステートの流れを無視してしまうので、あまり推奨できるわけではありませんが、場合によっては必要になることもあります。ケースバイケースで使うことが可能です。

コンポーネントの活用方法

ここまでコンポーネントベースのステートマシンの解説をしてきました。ブループリントコンポーネントはとても便利な機能ですが、まだまだ活用されている例が少ない気がします。

ブループリントインターフェースと合わせて活用すれば更に応用範囲は広がります。少しでもこの解説が何かの活用になればと思います。