読者です 読者をやめる 読者になる 読者になる

GameProgrammar's Night

ゲームプログラム系の覚え書き

UnrealEngine4で2Dゲームを作ろう! その15 BehaviorTreeのDecorator/Task作ってみた

という感じで、BehaviorTree(以下BT)で敵AIを作ってみた時にわかったことを書きます。

BT全体

f:id:katze_7514:20160103170558j:plain

BT全体は上図の通りで、移動して攻撃したらちょっと待つを繰り返します。

Decorator/IsEnableAI

 BTは、外からPauseしたりStopしたりする機能がないので、代わりに根元で実行を止めるDecoratorを付けました。
 中身は、対応するControllerの状態を調べてBTを実行する状態かをチェックしています。

Decorator実装

 Decoratorの実装は、「PerformConditionCheckAI」をオーバーライドし、boolをリターンします。
f:id:katze_7514:20160103174211j:plain
 AIがついていない「PerformConditionCheck」もあり、どっちも使えるのですが、AI付きの方はBTを実行しているController/Pawnを引数として取れるのでAI付きの方が使いやすいと思います。

Task/SimpleMoveTo,Attack

SimpleMoveTo

 NavMeshがリビルドエラーを吐き使えなかったので、MoveToを自前実装したのがSimpleMoveToです。中身は単純にPlayerPawnに近づいて一定距離になったら止まるというだけです。
 このリビルドエラーは、AnswerHubにも投稿されていますが完全な解決には至ってないようです。

 移動中は処理を継続し、PlayerPawnの一定距離内に来たらFinishExecuteを読んでTaskを終了します。
 また、処理を途中で打ち切るための仕込みもいれてあります。BlackBoardにAbortフラグが立っているかをチェックして、立っていたらFinishAbortします。この辺りについては後述します。

Attack

 攻撃アニメを再生して再生終わりを待つTaskです。アニメ再生終わりは、Controllerの方で検出してBlackBoardにフラグを書き込んでいます。Taskの中で直接再生終了をイベントをbindしても良いと思います。
 ダメージのやりとりはコリジョンイベントの方で行っています。

Task実装

 Taskは2つのイベントを実装します。

f:id:katze_7514:20160103191119j:plain
f:id:katze_7514:20160103191122j:plain

 ExecuteはActorのBeginPlayに相当するのもので、Taskが実行開始時に呼ばれます。BeginPlayと違うのは、Taskが実行開始する度に呼ばれることです。
 つまり、今回の例ですと、SimpleMoveTo→Attack→Wait と実行され、最初に戻り再びSimpleMoveToが実行される時にもまたExecuteが実行されます。

 Tickは、Task内でFinish系ノードが呼ばれるまで毎フレーム呼ばれます。

Taskの実行中断

※ DecoratorのObserveAbortsという項目を使うことで途中中断ができたみたいです。Decoratorの値が変化した時に接続されているノードを中断するかを選択することができます。

 今回、BT(というかTask)の実行を中断する必要があったのは、Playerの攻撃でノックバックしたり、HPが0になったら死亡エフェクトを表示したりする必要があるからでした。
 先にも書きました通り、BT自体に動作を止める手段が用意されてないため、実行中のTask以外の動作をさせるには一端Taskを止める必要があります。

 BTのデバッグ表示を見ると以下のようになっていたので、
f:id:katze_7514:20160103192338j:plain

 SequenceのIsEnableAIも毎フレーム実行されるのかと勝手に思っていたのですが、そんなことはなく、上図の場合はSimpleMoveToのTickだけが呼ばれている状態になります。
 Decoratorは実行"開始"条件判定を行うだけで、一度判定が通り先に進むとDecoratorは実行されなくなります。実行"継続"条件としては使用できません。
 よって、Taskの実行を中断させるには、根元にIsEnableAIを仕込むだけは足りないということになり、Task内に中断する仕組みを導入する必要があります。

 TaskのTick内で中断フラグをチェックする機構をいれておきます。
f:id:katze_7514:20160103194309j:plain
 IsAbordはBlackBoardに用意したAbordフラグを見にいっています。BlackBoardはBT内からでも外からでも操作できますので、どこからでもTaskの実行を中断できます。