Behavior Designerの更新処理の制御とTaskの処理タイミングについてまとめました。
Unity2018.3.9
はじめに
Behavior Designerは初期設定では更新タイミングはUnityのUpdateに従い、
同じTaskの繰り返しは同フレームで行われなかったりします。
厳密にAIを制御するにはこのあたりの処理フローを理解・制御しないといけません。
そのためこの記事では更新処理の制御とTaskの処理タイミングについてまとめます。
更新処理はBehavior Managerが行う
Behavior Treeをランタイムで実行すると、Behavior Managerというオブジェクトが自動的に作られるのがわかります。
これはすべてのBehavior Treeの更新処理を行うオブジェクトで、
InspectorにはBehavior Managerというコンポーネントがアタッチされていることがわかります。
更新処理を制御する
Behavior Managerによる更新処理を制御するには、まずシーンにBehavior ManagerのアタッチされたGameObjectを配置します。
これでBehavior Treeの更新にこのBehavior Managerが使用されるようになります。
更新処理を一定間隔で行いたい場合、Behavior ManagerのUpdate IntervalをSpecify Secondsに設定します。
そしてSecondsフィールドに更新間隔の秒数を指定します。
また、手動で更新を行う場合にはBehavior ManagerのUpdate IntervalをManualにします。
その上でスクリプトからBehaviorManager.Tick()を呼ぶことで更新します。
using BehaviorDesigner.Runtime; using UnityEngine; public class BehaviorManagerController : MonoBehaviour { [SerializeField] private BehaviorManager _manager; [SerializeField] private bool _isActive = true; private void Update() { if (!_isActive) { return; } // BehaviorManagerを更新する _manager.Tick(); } }
Tickの引数にBehavior Treeを与えれば特定のBehavior Treeだけを更新することもできます。
BehaviorManager manager; BehaviorTree tree; manager.Tick(tree);
1フレーム内で処理するTaskを制御する
初期設定では、Taskが成功/失敗すると同フレーム内で次のTaskを処理します。
つまり下記のようなツリーの場合、同じフレームですべてのTaskが処理されます。
もしあるTaskの処理が完了した時にそれ以降のTaskの処理を次のフレームに回したければ、
TaskのInspectorのInstantのチェックを外します。
またこれとは別に、「同フレーム内で同じTaskを処理せず次のフレームに回す」というルールがあります。
どういうことかというと、例えば次のようなBehavior Treeを考えます。
100回ログ出力を繰り返すだけのTreeです。
これを実行すると同じフレーム内で同じLog Taskを実行しようとしたときに
次のフレームに処理が先送りされるため、Treeが完了するまでに100フレーム掛かることになります。
同フレームで処理するTaskの数を制御する
さて前節のように次のフレームに処理を先送りにしたくない場合、
Behavior ManagerのTask Execution Typeというフィールドを使います。
これをNo Duplicates(初期値)に設定すると、前節の通りの挙動となります。
Task Execution TypeをCountにしてMax Execution Countを設定すると、
その数だけ次フレームの先送りが無効になり、同フレームで処理されるようになります。