State Tree(5.5) まとめ

# はじめに
この記事は [Unreal Engine (UE) Advent Calendar 2024](https://qiita.com/advent-calendar/2024/ue) シリーズ 3 の 23 日目の記事です。

~~本当はPhysicsAsset関連で一つ記事を書いていたのですが間に合わなかったので~~

今回は5.5でStateTreeの機能がアップデートされていますので、各種機能の説明をさっくり記事にしようと思います。

基本的な機能や以前のバージョンに関する説明は、既に色んな方が記事で紹介されていますので、そちらをご参照いただければと思います。

私の方でも、以前のStateTreeについて下の記事で少し触れています。

https://qiita.com/BONTAN/items/8d78605c9d2b3d1fabde

# 環境

UE 5.5.0
Windows 11

# **StateTreeとは**
StateTreeとは、様々な場面でロジックをBehaviorTreeやStateMachineの様に管理できる「**階層型ステートマシン**」です。

BehaviorTreeの代わりに思考を管理する用途に使用することもできれば、BehaviorTree側で呼び出しのTaskも用意されているため、併用も可能です。

また、AI用途の他、

- [**Motion Design**](https://www.youtube.com/watch?v=bRVnkTG2wFk)(旧: [Avalanche](https://dev.epicgames.com/community/learning/tutorials/3VRe/unreal-engine-5-s-new-motion-graphic-tools-will-blow-your-mind-project-avalanche?locale=ja-jp))
- [MassEntity](https://dev.epicgames.com/documentation/ja-jp/unreal-engine/overview-of-mass-entity-in-unreal-engine)
- [GameplayInteractions](https://portal.productboard.com/epicgames/1-unreal-engine-public-roadmap/c/1467-gameplay-interactions-plugin-experimental?&utm_medium=social&utm_source=starter_share)
- CameraDirector
- AnimNext

など複数の機能でもStateTreeは使用されており、更なる今後のアップデートが期待できます

また、最近公開されたUnreal Fes シアトルでも実際のプロジェクトで運用した例について

説明されている動画がアップされているので、興味がある方は合わせてご確認頂ければと思います。
https://dev.epicgames.com/community/learning/talks-and-demos/pL76/unreal-engine-surviving-state-tree-a-real-case-study-with-dinosaurs-unreal-fest-2024

# 準備
使用する際は、下記プラグインを有効化して下さい
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276335/3d564cf7-837e-d83f-ada5-17fa66482138.png)

# State
### Selection Behavior
5.5ではSelection Behaviorがいくつか追加されています。
Selection Behaviorとは、Stateの選択の仕方を設定する項目です。

![image 1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276335/5355c638-8d96-7e15-3515-0e37b5c7dc9b.png)


- **None**
    - Transitionの遷移先候補に指定できません
    - 通常の遷移の対象にもなりません
- **Try Enter State**
    - 子Stateが設定されていても、まずこのStateが選択されます
    - 子Stateに遷移したい場合は別途Transitionを指定する必要があります
- **Try Select Children In Order**
    - 最初に遷移可能な子Stateを選択しようとします
    - 子Stateが存在しない場合は、このStateが選択されます
- **Try Select Children At Random(New!)**
    - 設定されている子StateからランダムなStateが選択されます
    - 子Stateが存在しない場合は、このStateが選択されます
- **Try Select Children With Highest Utility(New!)**
    - State選択の際、Utility Scoreが最も高い子Stateを選択します
    - 同点の場合は上から順番に選択されます
- **Try Select Children At Random Weighted By Utility(New!)**
    - State選択の際、子Stateをランダムに1つ選択します
    - 各子Stateが選択される確率は、そのStateのUtility Scoreが使用されます
- **Try Follow Transitions**
    - Stateに遷移する時、代わりにTransitionをトリガーして有効なStateに遷移します

### Selection Utility

上記Utility Scoreでとして使用されるパラメーターを定義する機能です。
Stateのスコアを設定することで、Stateの選択優先順位をつけることができます。
![image 2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276335/ebf4b1b0-6594-b8e7-1cd1-827ac3625d8a.png)

使い方はWeightの数値を任意に設定、必要に応じて右上の＋マークから、その数値に対して乗算する倍率値を計算する処理(Consider)を選択します。

**※現在この機能は実験的機能として定義されているため、使用の際は自己責任でお願い致します。**

```cpp
/**
 * This feature is experimental and the API is expected to change. 
 * Base struct for all utility considerations.
 */
```

デフォルトでは以下の機能が用意されています
![image 3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276335/c78b488b-cd9d-a4e8-f47f-c61e298c2c45.png)


- **Constant**
    
    定数(0~1)が設定可能です
    ![image 4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276335/cf998c73-d34d-5f96-4bfe-59dc127d7da6.png)
    
- **Enum Input**
    
    Inputで指定したEnum型ごとにEnumValueScorePairs値を設定できます。
    ![image 5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276335/3f8d782e-6706-6935-fc2d-59a45771d2de.png)
    
- **Float Input**
    
    Inputに入力する値を指定し、InputRangeで指定したMin～Max内での割合値(0.0~1.0)に変更されます。
    最終的にその割合値がCurveの横軸で参照された結果がWeightに乗算されます。
    ※カーブには好きな値を設定できますが、最終的にはWeightに乗算するためClampされるため注意して下さい。
    ![image 6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276335/0f49f9bd-87da-76ac-83cd-5579fd700719.png)
    

また、このConsiderはC++なら`FStateTreeConsiderationCommonBase`、
BPなら`StateTreeConsiderationBlueprintBase`を継承して独自でスコアを設定する処理を作成することも可能です。
![image 7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276335/2ef055d4-e699-0d69-89ed-46495ddf5acf.png)

ちなみに複数のConsiderをConditionの様に組み合わせることは可能ですが、
ここで複雑なことを行うよりは自分で定義する方が見た目上分かりやすくてミスも起こりにくい気がします。
![image 8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276335/977b83e9-8a5c-8523-bca8-99b41a133f9f.png)

詳細な処理については`FStateTreeExecutionContext::EvaluateUtility`関数で行われているので興味がある方は是非。

## まとめ

Selection UtilityはまさにStateTreeを敵の思考として利用する場合に、
Utility Systemとして使えるので、今後の正式運用に期待が高まります。

※UtilitySytemについては下記動画がとても分かりやすいのでオススメです
[**SQEXにおける UNREAL ENGINE 4 を用いた人工知能技術の開発事例**](https://www.youtube.com/watch?v=BV2GTGbSjq8)

# Task
### Run Parallel Tree

現在のツリーに子Stateの選択と処理を継続させながら、現在のStateで別のState Treeを実行するタスク。

StateのLinked AssetやSub Treeよりも効率は悪いが、複数のツリーを並行して実行できるという利点があります。

また、通常のタスクと同様に、並列して処理しているStateTreeの結果に応じて、Taskの成功、失敗が実行されます。

![image 9.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276335/5c6945c7-ee27-b411-52f5-36136ca10d7d.png)

- **State Tree Override Tag**
    - 設定されている場合、StateTreeに設定されているStateTreeではなく、タグごとに設定されているStateTreeを参照します
    - StateTreeComponentを利用している場合はComponent側のLinked State Tree Overridesで設定が可能です
        ![image 10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/276335/421f2b49-4332-15e1-525b-6ef1e8e3bfbe.png)

- **Event Handling Priority**
    - 並列で動作するStateTree内でイベントを処理する際の優先順位です
        - **`Normal`** : StateTree内のStateの順序が処理順序を決定します
        - **`Low`** : MainのStateTreeが最初に遷移を処理するようにします
        - **`High`** : 並列で呼ばれているStateTree側が最初にイベントを処理する機会を得ます
    - 複数のタスクが同じ優先順位を持つ場合は、Stateの順序が処理順序を決定します
- **State Tree**
    - デフォルトで使用するStateTreeアセットです

# その他
### Property Function

各種ConditionやTaskで使用するPropertyに対して、関数をバインドして取得させることができます。

今までの既存機能としてはEvaluaterが近いですが、こちらは処理されるタイミングがStateTreeの開始、終了、Tickタイミングでした。

Property FunctionはEnter StateやConditionの判定が呼ばれるタイミングに実行されるので利便性が高いです。

2024/12月時点ではC++側でのみ利用可能で、BP側にベースクラスが公開されていません

##### デフォルト機能

値の型に応じていくつか用意されていますので紹介します。

| 名前 | 対象の型 | 用途 |
| --- | --- | --- |
| Add | Int、Float | Left + Right の結果が取得できます |
| Subtract | Int、Float | Left - Right の結果が取得できます |
| Multiply | Int、Float | Left * Right の結果が取得できます |
| Divide | Int、Float | Left / Right の結果が取得できます |
| Invert | Int、Float | Inputの値の符号を反転させた結果が取得できます |
| Absolute | Int、Float | Inputの値の絶対値が取得できます |
| Make Interval | Float | Min, Maxどちらかの値を取得できます |
| And | bool | Left && Right の結果が取得できます |
| Or | bool | Left || Right の結果が取得できます |
| XOr | bool | Left ^ Right の結果が取得できます |
| Not | bool | ! Input の値が取得できます |

##### 自分で作る場合

- `FStateTreePropertyFunctionCommonBase`を継承したクラスを用意
- Taskなどと同様にInstanceDataを定義
- Executeを継承し行いたい処理を記載
- 結果を受け渡しするパラメーターに反映(下の例ではbResult)

```cpp
USTRUCT()
struct FMySTFunction_Test_InstanceData
{
	GENERATED_BODY()

	UPROPERTY(EditAnywhere, Category = Output)
	bool bResult = false;
};

USTRUCT()
struct FMySTFunction_Test : public FStateTreePropertyFunctionCommonBase
{
	GENERATED_BODY()

	using FInstanceData = FMySTFunction_Test_InstanceData;
	virtual const UStruct* GetInstanceDataType() const override { return FInstanceData::StaticStruct(); };
	

	/**
	 * Called right before evaluating bindings for the owning node.
	 * @param Context Reference to current execution context.
	 */
	virtual void Execute(FStateTreeExecutionContext& Context) const override;
};
```

詳細な処理について興味がある方は下記関数をご確認ください。`FStateTreeExecutionContext::EvaluatePropertyFunctionsOnActiveInstances`

### その他地味にはまったところ

今回のアップデートでInstanceDataに定義するパラメーターの指定子が非公開だとバインド対象として表示されなくなるようになっていました。
もし困っている方は指定子を公開に変更すると表示されるかと思います。

# 最後に
今回調べるにあたって、前回から更に新規プラグインでの利用が伺えたりと
StateTreeは今後の運用拡張が期待できます。もし触ったことがない人はこの機会に是非。