ビヘイビアツリー(BT)完全ガイド:設計・実装・デコレータ・ブラックボードからゲームAI・ロボティクスへの応用
ビヘイビアツリー(Behavior Tree)とは
ビヘイビアツリー(以下 BT)は、エージェント(ゲーム内 NPC、ロボット、シミュレーションエンティティなど)の振る舞いを階層的に記述・実行するための制御架構です。ツリー構造により「条件判定」「アクション実行」「制御ロジック(合成・装飾)」を分離して表現でき、再利用性・可読性・拡張性に優れるため、ゲームAIやロボット制御で広く採用されています。
起源と背景(簡潔に)
BT の発想は、行動ベース制御(behavior-based control)や階層的な意思決定アプローチ(例:サブサンプション・アーキテクチャ、階層的タスクネットワーク)に由来します。ゲーム分野で広く注目されたのは 2000年代に入ってからで、以降ロボティクス分野でも理論的な定義や解析が進み、学術図書やライブラリ(BehaviorTree.CPP、py_trees 等)が生まれています(詳細は参考文献参照)。
基本概念と実行モデル
- ノードの種類
- ルート(Root): 実行の起点。定期的に「ティック(tick)」を受け取りツリー全体を進める。
- コンポジット(Composite): 子ノードをまとめて制御するノード。代表的なものに Sequence(直列実行)、Selector/Fallback(選択)、Parallel(並列)などがある。
- デコレータ(Decorator): 子ノードの前後で条件チェックや結果変換を行うノード(Inverter、Repeater、Timeout、UntilSuccess 等)。
- リーフ(Leaf): 実際の条件評価(Condition)や動作(Action)を実行する末端ノード。
- ステータス
ノードは実行結果として主に三つのステータスを返す:Success(成功)、Failure(失敗)、Running(実行中)。(実装によっては Error/Idle 等の追加がある。)
- ティック(tick)駆動
BT はフレームごと、または専用の周期でルートからティックが伝播します。各ノードはティックを受け取るたびにそのロジックを評価し、ステータスを返します。Running を返すノードは次回のティックでも継続的に実行される(あるいはメモリ化された子を再開する)挙動を持ちます。
主要コンポジットノードの振る舞い
- Sequence(直列)
子ノードを左から順に実行し、子のいずれかが Failure を返した時点で Sequence は Failure を返す。すべての子が Success を返せば Success。途中の子が Running を返すと Sequence は Running を返し、(メモリ有無に応じて)次回はその子から再開する。
- Selector / Fallback(選択)
子ノードを左から順に評価し、ある子が Success を返したら Selector は Success を返す。すべての子が Failure の場合に Failure を返す。Running は継続を意味する。
- Parallel(並列)
複数の子を同時に(論理的に)実行する。成功/失敗判定は「何個の子が成功したら成功とみなすか」等のポリシーで決まる。並列実行は状態共有や競合に注意が必要。
デコレータ(Decorator)の役割とよく使われる例
- Inverter: 子の成功/失敗を反転する(Running はそのまま)。
- Repeater / Loop: 子を指定回数繰り返す、または条件が満たされるまで繰り返す。
- Limiter: 実行回数や時間を制限する。
- Timeout: 子の実行が一定時間を超えたら Failure 等で打ち切る。
- Decorator がプレフィックス的(前処理)・ポストフィックス的(後処理)両方の役割を持ち、前提条件や副作用の制御に使われる。
ブラックボード(Blackboard)とデータ共有
BT では多くの場合「ブラックボード」という共有メモリを用いてノード間で状態やセンサー情報、ターゲット位置などをやり取りします。ブラックボードを明確に設計することで、ノードの再利用性が高まり、デバッグもしやすくなります。ただし共有データアクセスの競合やスコープ(グローバル・ローカル)設計には注意が必要です。
メモリ化と非メモリ化(Memory vs Non-memory)
Selector や Sequence に対して「メモリあり(memory)」実装を導入することがよくあります。メモリありだと、前回 Running だった子から次回再開するため、途中から処理をやり直さずに済みます。一方メモリなしだと毎ティック先頭から評価するため、リアクティブ性を高く保てます。用途に合わせて使い分けます。
BT と有限状態機械(FSM)との比較
- 可読性・階層性: BT は階層構造で行動を組み立てるため、複雑度が増しても FSM より管理しやすい。
- 再利用性: リーフやサブツリーを別ツリーで再利用しやすい。
- リアクティブ性: ティックごとに最新の条件で評価されるため、環境変化に対して迅速に反応できる。
- 一方で、単純な状態遷移や厳密な順序制御を行う場合は FSM のほうが直感的なこともある。
設計パターンとベストプラクティス
- 小さなリーフを作る:1つのアクションは単一責務にする(移動のみ、攻撃のみ、待機のみ等)。
- 条件は軽量に:条件ノードは副作用を持たない純粋なチェックにする。副作用が必要ならデコレータで制御。
- ブラックボードを利用して状態を共有:明確なキー名とスコープ設計を行う。
- ノードに意味ある名前を付け、可視化ツールで動作を確認する(実行中のステータス表示はデバッグで必須)。
- 深いネストは避ける:深すぎるツリーは理解しにくくなる。サブツリーに切り出して整理する。
- 並列ノードは副作用の管理が重要:複数ノードがブラックボードの同一データを書き換えないようにする。
よくあるアンチパターン(注意点)
- 大きすぎるリーフ:複雑な処理をリーフに詰め込みすぎると BT の利点を損なう。
- ブラックボードにすべてのロジックを押し付ける:データは共有しても、ロジックはノードで適切に分離する。
- 頻繁に全ツリー再評価してパフォーマンスを落とす:高頻度ティックや重い条件処理は最適化する。
- デバッグ情報がない:可視化・ロギングがないと振る舞いの原因究明が困難。
実装例(簡易)
以下は典型的な敵キャラクターの簡単な BT 構造例です(擬似表記)。
Root
└─ Selector
├─ Sequence (ChaseAndAttack)
│ ├─ Condition: CanSeePlayer?
│ ├─ Action: MoveToPlayer (Running)
│ └─ Action: AttackPlayer
└─ Sequence (Patrol)
├─ Action: MoveToNextWaypoint (Running)
└─ Action: Wait
このツリーでは、敵はプレイヤーを視認できれば追跡と攻撃を行い、視認できなければ巡回を続けます。MoveToPlayer/MoveToNextWaypoint はティックごとに Running を返すタイプのリーフで、到達や中断に応じて Success/Failure を返します。
実運用での考慮点(パフォーマンス・スケジューリング)
- ティック頻度:全エージェントを毎フレームティックするのは重いため、更新間隔を分散させる(フレームごと/数フレームおき等)。
- 条件評価のコスト:視線判定など重いセンサー処理は間欠的に評価するか、簡易フラグで前処理する。
- 並列実行:マルチスレッドで BT の一部を並列化する場合、ブラックボードの同期と競合回避が重要。
代表的なライブラリ・ツール
- Unreal Engine Behavior Tree(Epic Games): ゲーム業界で広く使われる実装。エディタで可視化・デバッグ可能。
Unreal Engine ドキュメント - BehaviorTree.CPP: C++ 実装のライブラリで、組込みやロボティクスで利用される。
BehaviorTree.CPP 公式サイト / ドキュメント - py_trees: Python 実装。教育・プロトタイピング、ROS 環境などで利用される。
py_trees ドキュメント - Unity アセット(Behavior Designer、NodeCanvas など): Unity 開発向けのビジュアル BT ツール。
Behavior Designer(Opsive)
研究・拡張領域
- 確率的セレクタ(Probabilistic Selector): 選択にランダム性を導入して行動バリエーションを出す。
- 学習と自動生成: 遺伝的アルゴリズムや強化学習で BT を自動生成・最適化する研究。
- 形式手法による検証: BT の振る舞いを形式的に解析・安全性検証する取り組み(ロボティクスで重要)。
- プランナーとの統合: タスクプランニング(HTN やシンボリックプランナ)と BT を組み合わせ、計画生成と実行を分担するアーキテクチャ。
まとめ(実装の勧め)
ビヘイビアツリーは、複雑なエージェント行動を階層的に整理し、再利用しやすく、可視化・デバッグもしやすいアーキテクチャです。ゲーム開発やロボティクスでの実績が豊富で、既存のライブラリやエンジン組み込みのツールが多数あります。実装時はブラックボード設計、ティック頻度、並列実行時の競合、そしてノードの単純化(単一責務)を意識すると成功しやすいでしょう。
参考文献
- M. Colledanchise, P. Ögren, "Behavior Trees in Robotics and AI: An Introduction" (Springer, 2018)
- BehaviorTree.CPP 公式サイト(ドキュメント) - behaviortree.dev
- py_trees ドキュメント(Python 実装)
- Unreal Engine ドキュメント: Behavior Trees
- Behavior Designer(Opsive) — Unity 用ビヘイビアツリーツール
- ビヘイビアツリーや行動ベース制御に関する学術論文群(IEEE / Springer / arXiv 等)(検索用)


