UE5.1で追加された「State Machine Function Library」を使ってみる 

# はじめに

UE5.1から、「State Machine Function Library」という機能が追加されました。
これにより、アニメーションBP内のステートマシンの状態をBPやC++から制御できます。

現時点では、詳しいドキュメントは見つかりませんでしたが、
リリースノートや5.1アップデート内容のスライドで存在を確認することができます。

> Added a new State Machine Function Library that allows you to query the active state, as well as dynamically transition between states.

https://docs.unrealengine.com/5.1/ja/unreal-engine-5.1-release-notes/

> State Machine Function Library - State Machine Update -

https://www.docswell.com/s/EpicGamesJapan/ZY3PDK-UE_CEDECKYUSHU2022_UE5Animation#p132

# 環境
UE5.1.1
Rider2023.1


# 使い方

※5.1.1におけるThirdPersonSampleの「ABP_Manny」の構成を例に説明します。
　アニメーションやBP構成に一部相違がある点はご了承ください。

## ステートマシンに関数を定義する

任意のステートマシンを選択し「OnUpdate」からバインディングする関数を作成します。
今回は、ABP_Mannyの「Main States」に作成しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/376911/a38ab74c-4f6c-adb5-3b52-85f2a9a577b6.png)

作成した関数内に、以下のようなノードを組みます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/376911/d539bb81-d39c-f3b7-372a-4920325970eb.jpeg" width=50%>


ざっくりとした内容の説明です。

* ABPにリクエスト用の変数「TargetState」を追加します。
* 引数「Node」を「Convert to Animation State Machine」で型を変換します。
* 変換した型から「SetState」を使用してステートを変更します。
    * ブレンド時間やブレンドタイプを指定することもできます。
* リクエスト用の変数をクリアします。

OnUpdateにバインドされた関数は、毎フレーム呼び出されるため、
リクエストがある場合にのみ「SetState」が処理されるように制御しています。
リクエスト用の変数は使いやすいように拡張することをお勧めします。

## 呼ばれる側のステートマシンの準備

ABP_Mannyの「Main States」から、赤枠の部分を追加しました。
追加した「Slip」ステートは、どこからも遷移が無い事がわかると思います。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/376911/81c758c5-e41b-bd05-49a7-fcd2589dfb54.png)


## ステート遷移をリクエストする

レベル上に適当なTriggerBoxを追加します。
![banana_trigger.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/376911/3dd32a8f-527b-1f91-3369-1c5687875c52.jpeg)

レベルブループリントで、TriggerBoxがプレイヤーが接触したときに
ABPのリクエスト用変数「TargeState」へ「Slip」を代入し、遷移をリクエストするようにします。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/376911/641434e5-139e-4997-0d2d-1f4d765ad6c2.jpeg" width=50%>


# 結果

![banana_slip.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/376911/b8c19ab3-8ad6-5715-d271-8f150ea85e89.gif)
いい感じに滑りました。

ABPの遷移は以下のようになっています。
「Slip」ステートに強制的に遷移していることがわかります。
![banana_slip_abp.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/376911/8075b20d-3e76-5ca0-f349-f8af52655f64.gif)

今回はわかりやすくする為、「Slip」ステートに遷移しましたが、
「Jump」や「Land」など、同じステートマシン内のステートなら自由に遷移することができます。

# 使いどころについての考察

※実際に運用した経験は無いため、あくまで想像です。

プログラム（BP/C++）から遷移を行う利点はいくつか考えられます。

* 優先度の制御
ステートの遷移優先度は、トランジションルールのプロパティのみに存在し、動的に変更することができません。
プログラムから遷移する場合、優先度は自由に変更することが可能となります。
* 遷移条件の分離
遷移条件は、ゲーム仕様に関わることが多いため、アニメーションBPと分離することで、
柔軟な追加や修正が行えるようになる可能性があります。
* ネットワークゲーム上でのステート同期
マルチプレイヤーのステートを同期する場合、強制的に遷移させたいケースがあるかもしれません。
* デバッグのしやすさ
明示的な遷移呼び出しを行うことによって、遷移タイミングが明確になり、デバッグのしやすさに繋がります。

とまあ、いくつか書きましたが、
「ここはプログラムから制御したいよ」って所で使っていけば良いのかなと思います。

また、「ステートエイリアス」でも遷移条件をシンプルに書けるようになっているので
まずはそちらを試してみるのも良いかもしれません。

https://docs.unrealengine.com/5.1/ja/state-machines-in-unreal-engine/#%E3%82%B9%E3%83%86%E3%83%BC%E3%82%BF%E3%82%B9%E3%82%A8%E3%82%A4%E3%83%AA%E3%82%A2%E3%82%B9

# 注意点

* 別のステートマシン内のステート名を指定しても遷移はできない
    * ステートマシン内のステートにのみ遷移できます。
    * また、関数バインドやリクエスト用変数は、ステートマシンごとに用意する必要があります。
        * ある程度共通化はできそうですが。
* SetStateは、同じステートに再度遷移することはできない
    * 現時点では、強制遷移などのオプションは存在しないようです。
* C++から直接SetStateを呼び出すことは難しそう
    * AnimNodeの評価時の処理に依存しているため、アクセスが容易ではありません。
    * ただし、独自のAnimInstanceにリクエスト用の変数（FNameなど）を用意し、
バインドした関数内で参照することで、リクエストは可能だと思います。

# まとめ

まだ出たばかりの機能ですが
「State Machine Function Library」を使うことで、
柔軟なアニメーションBPの設計が可能になる可能性があります。

すべてをプログラムからの遷移にしてしまうと、
SlotによるMontage再生と変わらないことになってしまうため（本末転倒^^;）
ステートマシンとプログラム制御のバランスが重要だと思います。

「こんな感じで運用してるよ」など、教えていただけると幸いです。