Behavior Treeの概要
Unreal Engineでゲーム開発を進める中で、「敵AIの動きが単調で面白くない」「複雑な状況判断をさせようとするとBlueprintがスパゲッティコードになってしまう」といった課題に直面していませんか?
特に、プレイヤーの発見、追跡、攻撃、そして見失った際の巡回といった、複数の行動を状況に応じて切り替えるAIを実装しようとすると、従来のステートマシン(State Machine)では管理が非常に煩雑になりがちです。
本記事では、このような複雑なAIの意思決定を、視覚的かつ階層的に 設計できるUnreal Engineの強力なAIツール、Behavior Tree(ビヘイビアツリー) について、その基本概念から、初心者でもすぐに実践できる具体的な実装手順までを、豊富なBlueprint例とともに徹底的に解説します。
Behavior Treeとは
Behavior Treeは、AIが「次に何をすべきか」を決定するための階層的な意思決定構造です。ツリーのルートから始まり、ノードを辿りながら、AIの行動を上から順に、あるいは条件に応じて実行していきます。
主要な構成要素
Behavior Treeを理解する上で、以下の3つの主要な要素は欠かせません。
| 要素名 | 役割 | 詳細 |
|---|---|---|
| Behavior Tree (BT) | 意思決定の構造 | AIの行動ロジック全体を定義するツリー構造。 |
| Blackboard (BB) | AIのメモリ/データ | AIが共有するデータ(ターゲットの位置、HP、現在の状態など )を格納する場所。BTのノードはBBの情報を参照・更新して動作を決定します。 |
| AI Controller | AIの制御役 | BTとBBを所有し、Pawn(キャラクター)を操作するコントローラー。 |
ノードの種類
Behavior Treeは、主に以下の4種類のノードで構成されます。
- コンポジットノード (Composite Nodes): 子ノードの実行順序を制御します。
- Sequence (シーケンス): 子ノードを左から順に実行し、すべて成功した場合に成功を返します。途中で失敗した場合は、その時点で失敗を返します。
- Selector (セレクター): 子ノードを左から順に実行し、いずれか一つが成功した場合に成功を返します。すべて失敗した場合に失敗を返します。
- タスクノード (Task Nodes): AIに具体的な行動(移動、攻撃、待機など)を実行させるノードです。通常、カスタムのBlueprintまたはC++で作成します。
- デコレーターノード (Decorator Nodes): 子ノードの実行可否を判断する条件ノードです。Blackboardの値やAIの状態をチェックします。
- サービスノード (Service Nodes): 一定間隔で実行され、Blackboardの値を更新したり、周囲の状況を監視したりするノードです。
敵AIの実装例
ここでは、最も一般的な敵AIの動作である「プレイヤーの索敵(パトロール)」「 発見後の追跡」「一定距離での攻撃」をBehavior Treeで実装する手順を解説します。
AI ControllerとBlackboardの設定
まず、AIを制御するための基本設定を行います。
- AI Controllerの作成:
AIControllerクラスを継承したBlueprintを作成し、敵PawnのデフォルトAIコントローラーに設定します。 - Blackboardの作成: コンテンツブラウザで右クリックし、
Artificial Intelligence->Blackboardを選択してBlackboardアセットを作成します。 - Blackboard Keyの追加: 作成したBlackboardを開き、以下のKeyを追加します。
TargetActor(Object型): プレイヤーなど、AIが追跡・攻撃するターゲット。IsTargetDetected(Boolean型): ターゲットを発見したかどうか。PatrolLocation(Vector型): 巡回目標地点。
- Behavior Treeの作成:
Artificial Intelligence->Behavior Treeを選択してBTアセットを作成します。BTアセットを開き、詳細パネルのBlackboard Asset にBlackboardアセットを設定します。AI ControllerではRun Behavior TreeノードでこのBTアセットを指定するだけで、Blackboardは自動的に関連付けられます。
💡 Blackboardの設定場所
BlackboardはBTアセット側で設定するのが一般的です。AI Controller側ではBTアセットのみを指定し、Blackboardを別途指定する必要はありません。
Behavior Treeの設計
AIの意思決定は、以下のロジックで構成します。
AIのロジック:
- Selector: ターゲットを発見しているか?
- YESの場合 (Sequence): ターゲットを追跡し、攻撃する。
- NOの場合 (Sequence): 巡回(パトロール)する。
索敵(Serviceノード)の実装
AIがプレイヤーを発見したかどうかを定期的にチェックするロジックをServiceノードで実装します。
- Serviceノードの作成:
BTService_BlueprintBaseを継承したBlueprint(例:BTS_CheckForTarget)を作成します。 - ロジックの実装:
Receive Tick AIイベントで、Sphere TraceやGet Actors in Rangeなどを使用してプレイヤーを索敵します。 - Blackboardの更新: プレイヤーを発見した場合、Blackboardの
TargetActorにプレイヤーを設定し、IsTargetDetectedをTrueに設定します。見失った場合はFalseに戻します。 - BTへの配置: Behavior Treeのルート直下のSelectorノードに、このServiceノードをアタッチします。
💡 より効率的な索敵:AIPerceptionコンポーネント
Serviceノードでの定期的な索敵(Tickベース)は簡単ですが、パフォーマンスの観点からはAIPerceptionComponent の使用が推奨されます。AIPerceptionは** イベント駆動型** であり、
OnTargetPerceptionUpdatedイベントを使ってターゲットを検知したときだけBlackboardを更新できます。多数のAIが存在する大規模なゲームでは、この方法の方が効率的です。
追跡と攻撃(Taskノード)の実装
- 追跡Task: 標準の
Move Toタスクノードを使用します。このノードのBlackboard Keyに、Blackboardで作成したTargetActorを指定します。 - 攻撃Task:
BTTask_BlueprintBaseを継承したBlueprint(例:BTT_AttackTarget)を作成します。Receive Execute AIイベントで、攻撃アニメーションの再生やダメージ処理を行い、Finish ExecuteノードでSuccessを返します。
💡 ベストプラクティス:条件判断はDecoratorで分離
上記の攻撃Taskでは「攻撃可能距離内かどうか」をTask内でチェックすることも可能ですが、Decoratorノード で距離チェックを分離する方が推奨されます。例えば
BTDecorator_IsAtLocationやカスタムDecoratorを使い、攻撃可能距離内のときだけ攻撃Taskが実行されるようにします。これにより、Taskは純粋に「攻撃する」という行動のみに専念でき、条件と行動が明確に分離されます。
巡回(Taskノード)の実装
- 巡回地点設定Task: カスタムTask(例:
BTT_FindPatrolLocation)を作成し、ランダムな巡回地点を計算してBlackboardのPatrolLocationKeyに設定します。 - 巡回移動Task: 標準の
Move Toタスクノードを使用し、Blackboard KeyにPatrolLocationを指定します。
ベストプラクティス
Behavior Treeは強力ですが、設計を誤るとすぐに複雑化します。以下のベストプラクティスを意識して設計しましょう。
BlackBoardの設計を最優先する
Behavior Treeの真の力は、Blackboardによるデータ駆動型の意思決定にあります。
- データの一元管理: AIの状態(攻撃中、巡回中など)や重要な情報(ターゲット、HP、弾薬数)はすべてBlackboardに格納し、ノード間で直接データをやり取りしないようにします。
- Keyの命名規則: Keyには明確な命名規則(例:
Target_Player,State_Patrolling)を設け、どのノードがどのKeyを参照・更新しているかを分かりやすくします。
ノードの役割を明確にする
- Taskノードは「行動」のみ: Taskノード内では、移動や攻撃といった具体的な行動 のみを実行し、条件判断 はDecoratorに任せます。
- Decoratorノードは「条件」のみ: DecoratorはBlackboardの値をチェックする純粋な条件判断 に徹し、Blackboardの値を変更するなどの副作用を持たせないようにします。
よくある間違い
| よくある間違い | 解決策(ベストプラクティス) |
|---|---|
無限ループ: TaskノードがFailureを返し続け、Selectorノードがすぐに次の子ノードに移ってしまう。 | Taskノード内でWaitやDelayを適切に使用し、実行頻度を調整する。または、Finish ExecuteでSuccessを返す条件を明確にする。 |
| 頻繁すぎるService: Serviceノードの実行間隔(Interval)が短すぎるため、パフォーマンスが低下する。 | 索敵など、頻繁なチェックが 必要な処理でも、最低0.2秒~0.5秒程度のIntervalを設定する。また、必要な時だけServiceを実行するようDecoratorで制御する。 |
| Blackboard Keyの誤用: 異なる意味を持つデータに同じKeyを使い回してしまう。 | Keyは用途ごとに明確に分け、特にVectorやObject型は、TargetLocationとPatrolLocationのように区別して使用する。 |
Behavior Tree活用のポイント
Behavior Treeは、Unreal Engineで複雑な敵AIを実装するための最も強力で推奨される手法です。
- 階層的な設計: 複雑な意思決定をSequenceやSelectorで階層的に整理できます。
- データ駆動: Blackboardを中心にデータを管理することで、ノード間の依存関係を減らし、再利用性を高めます。
- 視覚的なデバッグ: エディタ上でAIの実行パスをリアルタイムで確認できるため、デバッグが容易です。
本記事で紹介した基本概念と実装手順を参考に、あなたのゲームに深みを与える、賢く、そして手強い敵AIを設計してみてください。
💡 より高度なAIへ:EQS(Environment Query System)
Behavior Treeは意思決定の構造を提供しますが、「どこに移動するか」「どのターゲットを選ぶか」といった環境に基づいた選択 にはEQS(Environment Query System) が効果的です。EQSは、周囲の環境をスキャ ンし、最適な位置やターゲットをスコアリングして選択できます。BTとEQSを組み合わせることで、より賢く状況適応的なAIを実現できます。