【Unreal Engine】Behavior Treeで敵AIを作る:巡回・発見・追跡・攻撃

作成: 2025-12-12最終更新: 2026-07-19

敵AIをBranchだらけにせず作るのがBehavior Tree。SelectorとSequenceの違い、Blackboardの役割、Decorator/Serviceの使い分けを図解し、巡回→発見→追跡→攻撃の敵AIをゼロから組む実践つき。

敵AIを作りはじめると、多くの人が同じ道をたどります。「プレイヤーが見えたら追いかける」を Branch で書き、「攻撃範囲に入ったら攻撃」を足し、「見失ったら巡回に戻る」を足す。気づけば 分岐が入れ子になった巨大なグラフ ができあがっています。

Behavior Tree は、この意思決定を 木の形 で書くための仕組みです。「どの行動を優先するか」を上下の階層で、「どの順番でやるか」を左右の並びで表すので、 AIの方針が図として読めます 。この記事では、中核となるSelectorとSequenceの違いから、 巡回→発見→追跡→攻撃 の敵AIをゼロから組む手順までを解説します。

分岐だらけのグラフと、すっきり整理されたツリーを対比したイメージ

この記事でわかること

  • AIは3点セットで動く( AI Controller・Behavior Tree・Blackboard
  • Selector=優先順位(どれか1つ)/Sequence=手順(全部やる)
  • Task=行動、Decorator=条件、Service=定期的な監視
  • 索敵は AI Perception に任せると、視界や音まで扱える
  • 実践:巡回→発見→追跡→攻撃の敵AIを組む

Sponsored

AIを動かす3点セット

Behavior Treeは単体では動きません。標準的な構成では、次の3つを組み合わせます。

AI Controllerが脳、Behavior Treeが行動計画、Blackboardが記憶という役割分担の図
部品役割ひとことで言うと
AI ControllerPawnを操作する。BTを起動する中の人
Behavior Tree「次に何をするか」を決める木行動の計画表
BlackboardAIが覚えておく値を置く場所記憶(メモ帳)

とくに Blackboard が重要です。「いま誰を追っているか」「どこへ向かうか」といった ノード間で共有したい判断材料 をここに置きます(Task自身はPawnの関数を呼んだり移動したりもするので、Blackboardだけで動くわけではありません)。

なぜ共有の置き場所を作るのか。ノード同士が直接データをやり取りする作りにすると、ノードを1つ差し替えるたびに周囲も直すことになるからです。 全員が同じメモ帳を見る ことで、ノードの追加や入れ替えが安全になります。

SelectorとSequence:木の読み方

Behavior Treeを読めるようになるかどうかは、この2つの違いを理解できるかで決まります。

Selectorは成功したところで止まり、Sequenceは失敗したところで止まる、という対比図

どちらも 子を左から順に試す のは同じです。違うのは いつ止まるか です。

動き意味するものたとえるなら
Selector成功したら、そこで止まる(1つでも成功すれば成功)優先順位「上から順に試して、できたやつを採用」
Sequence失敗したら、そこで止まる(全部成功して成功)手順「1つでもコケたら中断」

具体例で考えてみましょう。敵AIのルートに Selector を置き、子を左から「攻撃する」「追いかける」「巡回する」と並べたとします。

  • 攻撃できる状況なら → 攻撃して終わり(右の子は試さない)
  • 攻撃できないが追える → 追いかけて終わり
  • どちらも無理 → 巡回する

これが 優先順位 です。左にあるほど優先度が高い、と読めます。

一方、「追いかける」の中身は Sequence になります。「ターゲットへ移動する」→「向きを合わせる」といった 順番にやるべき手順 だからです。途中で失敗したら、その先はやる意味がありません。

覚え方: Selector は「または」、Sequence は「かつ」 に近い動きです(厳密な論理演算ではなく、 結果がどう伝わるか を掴むための近似だと考えてください)。どれか1つでいいのか、全部必要なのかで選びます。

Task・Decorator・Service

木を組み立てる部品は3種類あり、 役割を混ぜないこと が読みやすさを保つコツです。

Taskは行動、Decoratorは条件のゲート、Serviceは定期的な見張り、という役割の図
種類役割見た目
Task行動する (葉の部分)紫っぽいノードMove ToWait、攻撃
Decorator通していいか判断する (ゲート)ノードの上に付く帯「ターゲットがいるなら通す」
Serviceその枝がアクティブな間、定期的に調べるノードの下に付く帯距離を測ってBlackboardへ書く

原則として 、次のように分けると読みやすくなります(エンジン上の制約ではなく、設計の目安です)。

  • Taskは行動を担当: 「攻撃範囲内かどうか」の判定はDecoratorに任せる。ただし、Taskが実行時に前提を確認して失敗を返すのは正常な使い方です
  • Decoratorは判断を担当: 条件を見るだけにして、Blackboardの値を書き換えない。副作用があると、なぜ通ったのか追えなくなります

Serviceで1つ注意したいのは、 取り付けた枝が実行されている間だけ動く ことです。AI全体を常時監視したいなら、ルート近くの枝に付ける必要があります。

この線引きをしておくと、木を眺めるだけで 「どういう条件のとき、何をするAIなのか」 が読み取れるようになります。

索敵はAI Perceptionに任せる

「プレイヤーを見つけたか」の判定を、Serviceの中で毎回距離を測って実装することもできます。ただ、本格的に作るなら AI Perception Component のほうが向いています。

Serviceが自分から周囲を調べに行くのに対し、AI Perceptionは見えた瞬間に知らせてくる、という対比図
Service方式AI Perception方式
仕組み一定間隔で 自分から調べる知覚状態が変わったら 通知が来る
扱えるもの自分で書いた判定だけ視界(角度・距離)、音、ダメージ
障害物自分でトレースを書く必要あり視線判定を 標準で持っている
手軽さすぐ書ける設定項目が多い

AI Perceptionを使うと、 「壁の向こうのプレイヤーは見えない」「背後は見えない」 といった当たり前の挙動を、設定中心で組めます(壁で遮られるかどうかは、その壁のCollision設定が視線判定に反応する前提です)。自前で書くと地味に大変な部分です。

この記事の実践ではAI Perceptionを使います。Serviceは「ターゲットとの距離を測ってBlackboardに書く」といった 補助的な監視 に使うのが向いています。視覚だけでなく聴覚を足したり、見失ったあとの動きまで詰めたいなら AI Perceptionで敵に見つけさせる を参照してください。

Sponsored

実践:巡回する敵に、プレイヤーを見つけさせる

ステルスゲームの見張り、ホラーゲームの徘徊する敵、アクションRPGのフィールドモンスター——「普段は巡回し、見つけたら追ってきて、近づいたら攻撃する」はAIの基本形です。これをゼロから組みます。

再現用の準備: 次を用意します。作成は右クリック → Artificial Intelligence から選べます。

種類名前設定
CharacterBP_EnemyAI Controller ClassBP_EnemyAIControllerAuto Possess AIPlaced in World or Spawned
AIControllerBP_EnemyAIControllerAIPerception Component を追加
BlackboardBB_EnemyKeyを2つ(下表)
Behavior TreeBT_EnemyBlackboard AssetBB_Enemy を指定
レベルNav Mesh Bounds Volume床を覆うサイズに。 P を押して緑になることを確認
プレイヤーBP_ThirdPersonCharacterActor Tag に Player を追加(感知対象の判別に使う)

Auto Possess AI を忘れると、レベルに置いた敵にAI Controllerが付かず、何も動きません。

Blackboardのキーは2つです。

Key名用途
TargetActorObject(Base Class: Actor)追いかける相手
PatrolLocationVector次に向かう巡回地点

ステップ1:AI Perceptionを設定する。 BP_EnemyAIControllerAIPerception を選び、Senses ConfigAI Sight config を追加します。

項目
Sight Radius1500.0
Lose Sight Radius1800.0(Sight Radiusより大きく)
Peripheral Vision Half Angle60.0前方から左右に各60度(視野は約120度)
Detection by Affiliation → Detect Neutralsチェック

Detect Neutrals にチェックを入れるのがポイントです。Teamを設定していないActorは中立として扱われるため、これだけで検証できます。

ステップ2:感知したのが「本当にプレイヤーか」を確かめる。 ここが最も間違えやすい箇所です。AI Perceptionは 感知したActorを何でも渡してくる ので、そのまま TargetActor に入れると、他の敵やNPCまで追いかけはじめます。

OnTargetPerceptionUpdatedからTagを確認し、TargetActorを設定またはクリアするノードグラフ
Event On Target Perception Updated(AIPerception)
  → Actor Has Tag(Target: Actor, Tag: "Player")
  → Branch
      False → (何もしない)                                  ← プレイヤー以外は無視
      True  → Branch(Condition: Stimulus の Successfully Sensed)
          True  → Get Blackboard → Set Value as Object
                    (Key Name: TargetActor, Object Value: Actor)      ← 見つけた
          False → Branch(Condition: Actor == Get Blackboard Value as Actor(TargetActor))
              True → Get Blackboard → Clear Value(Key Name: TargetActor) ← 追っていた相手を見失った

2つの確認が入っていることに注目してください。

  • Tagでプレイヤーかを判定: これがないと、味方NPCを見た瞬間に追跡が始まります
  • 見失ったのが「いま追っている相手か」を確認: 無条件で Clear Value すると、 無関係なActorを見失っただけでターゲットが消えます

Set Value as ObjectClear ValueTarget ピンには、 Get Blackboard(AI Controllerの関数)の戻り値 をつなぎます。ここが空だと何も書き込まれません。

ステップ3:Behavior Treeを起動する。 Event On Possess で木を動かします。

Event On Possess(BP_EnemyAIController)
  → Run Behavior Tree(BTAsset: BT_Enemy)

BeginPlay ではなく On Possess を使うのが確実です。操作するPawnが確定した時点で開始できるためで、公式の手順もこの形になっています。

ステップ4:木を組む。 BT_Enemy を開き、次の形に組み立てます。 左が優先 です。

ルートSelectorの下に、左が追跡Sequence、右が巡回Sequenceと並んだBehavior Treeの図
Root
└─ Selector                              ← どちらか1つでいい
   ├─ Sequence 「戦う」                   ← 左なので優先
   │   ⚑ Decorator: Blackboard(TargetActor is Set / Observer aborts: Both)
   │   ├─ Task: Move To(Blackboard Key: TargetActor, Acceptable Radius: 200)
   │   ├─ Task: BTT_Attack
   │   └─ Task: Wait(Wait Time: 1.0)      ← 攻撃の間隔。これが無いと高速で連打される
   └─ Sequence 「巡回する」                ← ターゲットがいないときだけ来る
       ├─ Task: BTT_FindPatrolLocation
       ├─ Task: Move To(Blackboard Key: PatrolLocation)
       └─ Task: Wait(Wait Time: 2.0)

3つ、押さえるべき設定があります。

  • Decoratorの Observer abortsBoth: これで 巡回中にプレイヤーを見つけた瞬間、巡回を中断して追跡へ切り替わりますNone のままだと巡回が終わるまで反応しません
  • 戦う枝にも Wait を入れる: Taskが即座に成功を返し続けると、木が高速で回り続けて攻撃が連打されます
  • Move ToAcceptable Radius: ここが小さすぎると、目標に到達できず延々と歩き続けます

ステップ5:巡回地点を決めるTaskを作る。 BTTask_BlueprintBase を継承して BTT_FindPatrolLocation を作ります。

書き込み先のキーは、 Blackboard Key Selector 型の変数 で受け取るのが標準的な作りです。こうしておくと、Behavior Tree上でTaskを選んだときに詳細パネルからキーを指定でき、同じTaskを別のキーで使い回せます。

Get Random Reachable Point in Radiusで地点を求め、BlackboardのPatrolLocationへ書き、Finish Executeで成功を返すノードグラフ
変数: PatrolKey(Blackboard Key Selector型・Instance Editable)

Event Receive Execute AI(Controlled Pawn)
  → Get Random Reachable Point in Radius(Origin: Controlled Pawn の位置, Radius: 1000.0)
  → Branch(Condition: 戻り値の成否)
      True  → Set Blackboard Value as Vector(Key: PatrolKey, Value: 求めた地点)
            → Finish Execute(Success: true)
      False → Finish Execute(Success: false)

Behavior Tree上でこのTaskを選び、詳細パネルの Patrol KeyPatrolLocation を割り当てます。

BTT_Attack も同様に作り、攻撃処理の後で Finish Execute(Success: true) を返します。中身は最初 Print String だけで構いません。

ステップ6:レベルに置いて動かす。 BP_Enemy をレベルにドラッグして配置し、Playします。

敵は範囲内をランダムに歩き回り、視界に入った瞬間にこちらへ向かってきて、近づくと攻撃のログが1秒おきに出る。物陰に隠れると巡回に戻る 。これが見えれば成功です。

うまくいかないときは、 Behavior Treeを開いたままPlayする と、いま実行中のノードが光ります。値は Blackboardパネル で確認でき、敵が複数いる場合はエディタ上部の Debug Object で対象を選びます。

  • 1歩も動かない → Nav Mesh Bounds Volume(P で確認)、Auto Possess AIAI Controller Class
  • 巡回はするが追ってこない → Blackboardパネルで TargetActor を確認。空ならAI Perception側か、Tagの綴り
  • 他の敵を追いかける → Tag判定が抜けています
  • 追いはじめると巡回に戻らないClear Value の条件を確認
  • 攻撃ログが高速で流れる → 戦う枝の Wait が抜けています
  • 1つのノードで固まる → そのTaskで Finish Execute を呼び忘れています

ポイントは2つです。

  • 優先順位はSelectorの「左から」で表す: 条件分岐を書き足すのではなく、 枝の並び順 で優先度を表現します。「気絶したら何もしない」を最優先にしたければ、いちばん左に足すだけです
  • 感知したActorは必ず絞る: AI Perceptionは見えたものを何でも渡してきます。Tagやクラスで 狙う相手かどうかを1回確かめる ようにします。これを省くと、敵同士で追いかけ合う奇妙なAIになります

もっと賢く「どこへ逃げるか」「どの敵を狙うか」を選ばせたくなったら EQS(Environment Query System) が次の一歩です。移動そのものが不安定なら NavMeshの設定 を先に確認してください。

Sponsored

おまけ:先に知っておくと良いこと

Behavior Treeのデバッグは、エディタを開いたままPlayするのが基本です。 実行中のノードがハイライトされ、Blackboardの現在値も Blackboardパネル で見られます。「なぜこの行動をしているのか」が視覚的に分かるのは、BTの大きな利点です。 Print String を仕込む前に、まず木を眺めてください

Serviceの実行間隔は既定のままにしない。 ServiceはIntervalを設定できますが、既定値のまま多数のAIに付けると効いてきます。距離チェック程度なら 0.3〜0.5秒 で十分です。Random Deviation を少し入れておくと、全AIの処理が同じフレームに集中するのを避けられます。

Taskが Success を返し続けると、木が高速で回り続けます。 巡回のSequenceに Wait を入れているのはこのためです。「AIが何もしていないのに重い」ときは、どこかの枝が超高速でループしていないか疑ってください。

AIの「状態」をBlackboardのEnumで持つと整理しやすくなります。 巡回中・警戒中・戦闘中といった大きな区分をEnum型のKeyで持ち、各枝のDecoratorでそれを見る形にすると、木の構造が読みやすくなります。ステートマシン的な考え方をBTに持ち込むイメージです。

StateTreeという選択肢もあります。 UE5世代では、状態と遷移をそのまま図にする StateTree が公式サンプルでの採用を増やしています。Behavior Treeは今も現役で、情報量も圧倒的に多いので、この記事の内容が無駄になることはありません。ただ 新しくAIを組むときは、状態がはっきりしているならStateTree、優先度の駆け引きが命ならBehavior Tree 、と見比べてから決めると納得して進めます(→ StateTree入門)。


まとめ

Behavior Treeは、覚える要素は多いものの、押さえるべき骨格はシンプルです。

要素役割判断基準
Selectorどれか1つ成功すればいい優先順位 を表したいとき
Sequence全部成功する必要がある手順 を表したいとき
Task行動する「〜する」と言えるもの
Decorator通すか判断する「〜なら」と言えるもの
Service定期的に調べる「ずっと見ておきたい」もの
Blackboard記憶を置くノード間で共有したい値

そして設計の指針が1つ。 条件はDecorator、行動はTask、記憶はBlackboard 。この3つを混ぜないだけで、AIは後から拡張できる形に保てます。

あなたのゲームの敵は、プレイヤーを見失ったあと、どう振る舞ってほしいですか?