News Activity Product Learning red Event Contact
Devblog top img

開発ブログ

2018-09-09

Behavior TreeのDecoratorのObserver Abortsについて

writer : yuto

 以前Observer Abortsを使う機会があったのですが,それに関する詳しい日本語の記事が見当たらず困ったことがありました(2017/07/07現在).ここでは,そのObserver Abortsの仕様を検証してみます。

 

 

説明

 

 

 Observer AbortsとはDecoratorのプロパティの一つです.日本語では「オブザーバーを中止」と表示されるものです.簡単に説明すると,条件が変わったとき今実行しているタスクをどのように中断するかを決めるものです。

公式ドキュメントではプロパティ説明欄にObserver Abortsの説明が書いてあります。

https://docs.unrealengine.com/latest/JPN/Engine/AI/BehaviorTrees/NodeReference/Decora
tors/index.html#blackboard

 

 通常,タスクはそのタスクが終了するまで,つまりFinish Executeが呼ばれるまでは別のタスクに切り替わることはありませんが,ある条件が変わったとき現在実行しているタスクに割り込んで別のタスクに切り替えたいということは多々あります(例えば,探索タスクを実行中の敵がプレイヤーを発見したとき,即座に戦闘タスクに切り替えたいなど)。
Observer Abortsではこのようなときに割り込みを発生させるためのものです。

 

 

 

 

準備

 

 

 

 検証に使用したアセット一覧です。

以下詳細です。

 

TestEnemy (BlueprintClass)
 AIControllerを作成したAIC_TestEnemyに設定するだけです。 ここではMeshとAnimationも設定していますが,全く必要ありません。

 

 

 

AIC_TestEnemy (AIController)
 Begin PlayからRun Behavior Treeを呼び出します。BTAssetには作成したBT_TestEnemyを設定します。

 

 

 

 

BBD_TestEnemy (BlackboardData)
 Bool変数のTestFlagを作成します。Self Actorは自動生成されたものなので作る必要はありません。

 

 

 

 

BT_TestEnemy (BehaviorTree)
 以下のようなツリーを作成します。Test Flagがtrueの場合、BTTask_HighPriorityが実行され、TestFlagがfalseの場合、BTTask_LowPriorityが実行されます。それぞれのTaskは後述します。

 

 

 

 

BTTask_HighPriority
 実行が開始されると、「High Priority Start」を出力して1秒待ち、TestFlagをfalseにしてから「Changed」1秒待ち、「High Priority End」を出力して終了します。

 

 

 

 

Task_LowPriority
実行が開始されると,「Low Priority Start」を出力して1秒待ち,TestFlagをtrueにしてから「Changed」を出力して1秒待ち,「Low Priority End」を出力して終了します。

 

 

 

作成したTestEnemyをレベルに配置して完了です。

 

 

 

 

 

検証

 

 

 

 

検証内容
 このBehavior Treeは、DecoratorでTestFlagの値を監視しており、それぞれのタスクでTestFlagをtrueまたはfalseにしています。例えば、TestFlagがtrueであったとき、HighPriorityに設定されているDecoratorはTestFlagがtrueのときのみ通過するようフィルタをかけていますが、その後実行されるHighPriorityではそのTestFlagをfalseに書き換えています。
 このようなBehaviorTreeを作成した場合、Observer Abortsの値によってどのように結果が変わるのかを検証してみます。

検証1.HighPriority->None、LowPriority->Noneの場合
 Noneは特に何もしない、つまりタスクは最後まで実行され、終了してからDecoratorの判定が入ります。要するにデフォルトのままです。

【出力結果】
 出力を見てもらうと分かる通り、どちらもStart、Changed、Endがすべて実行されます。

アウトプットログは以下の通りです。Low Priorityから開始しているのはTestFlagの初期値を設定していない(=false)であるためです。

 

 

検証2.HighPriority->None、LowPriority->Selfの場合
 次はLowPriorityのDecoratorだけSelfに設定してみます。SelfはそのDecoratorより下のツリーが実行中の時に条件が変わるとそのツリーの実行を停止します。
Selfに設定したDecoratorを選択すると。そのDecoratorによって中断されるノードが水色になります。

 

 

 

 

【出力結果】
 検証1では出力されていた「Low Priority End」がここでは現れていません。
Observer AbortsによりTestFlagの値がtrueになったのを検出してタスクの実行が中断されたのが分かります。

 

 

 

 

検証3.HighPriority->Lower Priority、LowPriority->Noneの場合
 Lower PriorityはそのDecoratorの条件が整ったときに、そのツリーより右側にあるツリーの実行を停止し、即座に自身のツリーを実行します。Lower Priorityに設定したDecoratorを選択すると、そのDecoratorによって中断されるノードが青色になります。

 

 

 

 

【出力結果】
 検証2と同じく、「Low Priority End」が出力されていません。 TestFlagがtrueに変更されたとき、即座に割り込みが発生していることが確認できます。

 

 

 

検証4.HighPriority->Both、LowPriority->Noneの場合
 BothはSelfとLower Priorityの両方を含みます。検証2・3と同じく、Selfで停止されるノードは水色、Lower Priorityで停止されるノードは青色になります。

 

 

 

【出力結果】
 「High Priority End」と「Low Priority End」両方とも出力されていません。BothのうちLower PriorityによってTestFlagがtrueになったときBTTask_LowPriorityが中断され、BothのうちのSelfによってTestFlagがfalseになったときBTTask_HighPriorityが中断されています。

 

 

 

 

 

まとめ

 

 

 

 以上がObserver Abortsの値None、Self、Lower Priority、Bothについての検証結果でした。 個人的にはSelfは自身のノードを中断する役割であるのに対し、Lower Priorityは自身のノードを開始する役割であることが少しややこしいですね。
ですが、これを知っていると複雑なタスクの制御が可能になります。 今まで知らなかった方はぜひ使ってみてください。