Simple Patrol, Chase, Attack, and AI Debugging¶
A first Behavior Tree enemy should be boring on purpose: patrol when nothing is known, chase when there is a target, attack in range, search briefly when the target is lost, and debug each layer before guessing.
At a glance
Use this for: the first complete enemy loop after sensing and basic Move To already work - Main pieces: AIController, Blackboard keys, Behavior Tree branches, Move To tasks, perception, timers/search memory, attack tasks, and AI debugging tools - Beginner rule: prove pawn, controller, NavMesh, perception, Blackboard, tree branch, and task result in that order - Official docs: Behavior Tree Quick Start Guide, AI Debugging, and Using the Gameplay Debugger
The one-minute version¶
- Build the enemy as a small state loop: patrol, chase, search, attack.
- The AIController starts the Behavior Tree and updates Blackboard keys from perception.
- The Blackboard stores facts:
TargetActor,LastKnownLocation,PatrolLocation,HasLineOfSight,InAttackRange, and maybeSearchExpiresAt. - The Behavior Tree chooses branches. It should not hide sensing, movement setup, and combat implementation in one giant custom task.
- Patrol chooses a valid destination and moves there. Chase moves toward the target. Search moves to the last known location. Attack calls a pawn/combat function when in range.
- Debug AI in layers: pawn possession, NavMesh, perception event, Blackboard values, active Behavior Tree branch, Move To result, then attack function.
- The AI Debugger opens with apostrophe (
'); default categories show NavMesh, general AI, Behavior Tree, EQS, and Perception information.
The target shape¶
A first useful Behavior Tree can be this simple:
Root
-> Selector AI Root
-> Sequence Attack
Decorator: TargetActor is set
Decorator: InAttackRange == true
Observer Aborts = Both on the range/target condition as needed
Task: AttackTarget
-> Sequence Chase
Decorator: TargetActor is set
Observer Aborts = Both
Service: UpdateCombatFacts
Move To TargetActor
-> Sequence Search
Decorator: LastKnownLocation is set
Decorator: TargetActor is not set
Move To LastKnownLocation
Wait 1.0
Task: ClearSearchLocation
-> Sequence Patrol
Task or Service: ChoosePatrolLocation
Move To PatrolLocation
Wait 1.5 with random deviation
That is enough to teach the real loop. Add strafing, cover, team rules, Environmental Query System (EQS), complex cooldowns, and multiple attack types after the branch structure is visible and debuggable.
Blackboard keys¶
Use clear key names. A first enemy might have:
| Key | Type | Written by | Read by |
|---|---|---|---|
TargetActor |
Object, base Actor or Pawn | AI Perception / Pawn Sensing / damage wake-up | Attack and chase decorators, Move To |
LastKnownLocation |
Vector | Perception update, chase service | Search Move To |
PatrolLocation |
Vector | patrol task/service | Patrol Move To |
HasLineOfSight |
Bool | perception or line-of-sight service | chase/search decorators |
InAttackRange |
Bool | service or attack-range check | attack decorator |
AttackRange |
Float | controller setup or enemy defaults | service/task checks |
HomeLocation |
Vector | controller On Possess |
return-home or search fallback |
Do not make the Behavior Tree guess facts from scratch in every task. Put changing facts into the Blackboard and watch them while debugging.
AIController setup¶
The controller starts the tree and owns the main sensing-to-Blackboard bridge:
BP_EnemyAIController
On Possess(NewPawn)
-> Run Behavior Tree BT_Enemy
-> Branch Return Value
true:
Get Blackboard Component
Set HomeLocation = NewPawn location
Set AttackRange from enemy defaults
false:
Print "BT_Enemy failed to start"
For AI Perception:
On Target Perception Updated(Actor, Stimulus)
-> filter actor is player/valid target
-> Break AI Stimulus
-> if Successfully Sensed:
Blackboard.TargetActor = Actor
Blackboard.HasLineOfSight = true
Blackboard.LastKnownLocation = Actor location
clear forget/search timer
else:
Blackboard.HasLineOfSight = false
Blackboard.LastKnownLocation = Stimulus Location
start short forget timer
When the forget timer fires:
ForgetTarget
-> if HasLineOfSight is false:
Clear TargetActor
That leaves LastKnownLocation available for search while target memory is
being cleared deliberately.
Patrol¶
Patrol needs a valid destination before the Move To task runs.
Random patrol:
BTT_ChoosePatrolLocation
-> Event Receive Execute AI
-> Get Controlled Pawn
-> Get Actor Location
-> Get Random Reachable Point in Radius
-> Branch Return Value
true:
Set Blackboard PatrolLocation = RandomLocation
Finish Execute true
false:
Set Blackboard PatrolLocation = CurrentLocation
Finish Execute true
Patrol path:
Enemy pawn has PatrolPoints array or PatrolPath actor reference
-> BTT_ChooseNextPatrolPoint chooses next index
-> Set Blackboard PatrolLocation = point location
-> Finish Execute true
Then the tree:
Sequence Patrol
-> BTT_ChoosePatrolLocation
-> Move To PatrolLocation
-> Wait
If patrol never moves, debug PatrolLocation, then debug NavMesh. A valid
vector in the Blackboard does not guarantee a reachable path.
Chase¶
Chase should not be "call Move To from perception every time sight updates." Let perception set the target key and let the tree run the chase branch.
Sequence Chase
Decorator: TargetActor Is Set
Observer Aborts = Both
Service: UpdateCombatFacts
Move To TargetActor
The service can update:
DistanceToTarget
InAttackRange
LastKnownLocation while target is visible/valid
The Move To task should use TargetActor and a reasonable acceptable radius.
If the goal is a moving player, enable goal tracking/blackboard observation
when your Move To settings support it.
If chase keeps restarting or twitching, check whether multiple systems are
issuing movement requests: AI Move To from perception, Behavior Tree Move To,
and pawn code can fight each other. Pick one owner for movement while the tree
is active.
Search¶
Search is what happens after the AI loses target certainty but still knows a place to investigate.
Simple search branch:
Sequence Search
Decorator: LastKnownLocation Is Set
Decorator: TargetActor Is Not Set
Move To LastKnownLocation
Wait 1.0
Task: Clear LastKnownLocation
That creates a readable behavior:
see player -> chase
lose sight -> remember last known location
forget target after short timer
move to last known location
wait/search briefly
clear search location
fall back to patrol
Do not clear every key at the first lost-sight event unless you want the AI to forget instantly. The usual beginner mistake is one of two extremes: never clear the target, or clear all memory immediately and never search.
Attack¶
Attack should be a task that asks the pawn/combat component to act.
Tree branch:
Sequence Attack
Decorator: TargetActor Is Set
Decorator: InAttackRange == true
Observer Aborts = Both or Self depending on layout
Task: AttackTarget
Task shape:
BTT_AttackTarget
-> Event Receive Execute AI
-> Get Controlled Pawn
-> Get Blackboard TargetActor
-> Is Valid both
false: Finish Execute false
-> call pawn function TryMeleeAttack(TargetActor)
-> Finish Execute with returned success
The pawn or combat component owns details:
- cooldown checks;
- montage playback;
- damage window;
- weapon trace;
- hit effects;
- health/damage application.
The task should not directly edit every combat sub-object unless this is a throwaway prototype. Calling one named function gives you a clean debug point: "did the Behavior Tree request an attack, and did the pawn accept it?"
Avoid flicker between chase and attack¶
If the AI switches rapidly between chase and attack, the range rule may be too tight:
Attack starts at <= 150
Chase resumes at > 150
Capsules, movement, and path following can push the distance around the exact threshold. Use a small buffer:
Enter attack at <= 150
Leave attack at >= 190
Or use cooldown/decorator rules so the AI does not evaluate the attack branch every tiny distance change.
This is not a Behavior Tree failure. It is a state-threshold design problem.
Debug in layers¶
When the enemy is broken, do not start by rewriting the tree. Prove each layer.
- Pawn exists and is possessed.
Print or debug
Get Controlleron the enemy pawn. It should be your AIController, notNoneand not a PlayerController. - NavMesh is usable. Press P in the editor viewport or use AI Debugger NavMesh view. Confirm green navigation under the enemy and the goal.
- Perception fires.
Print from
On See PawnorOn Target Perception Updated, including actor name andSuccessfully Sensed. - Blackboard keys change.
Watch
TargetActor,LastKnownLocation,HasLineOfSight, andInAttackRangein the Behavior Tree debugger. - Behavior Tree is running. Use AI Debugger general AI/Behavior Tree categories to confirm the tree class and active task/branch.
- Branch decorators pass or fail for a reason. Check the exact key names and types each decorator reads.
- Move To result makes sense. If movement fails, return to NavMesh, valid target, acceptable radius, pawn movement component, and competing movement requests.
- Attack function accepts the request.
Put a breakpoint or print inside
TryMeleeAttack, not only in the task.
This order matters because each layer depends on the previous one.
AI Debugger¶
During Play In Editor, press apostrophe (') to open the AI Debugger. The
default categories are useful for this exact workflow:
| Key | What to inspect |
|---|---|
| Numpad 0 | NavMesh data. |
| Numpad 1 | General AI information: controller, pawn, path following, active behavior/task. |
| Numpad 2 | Behavior Tree branch plus Blackboard key values. |
| Numpad 3 | Environmental Query System data, if you use EQS. |
| Numpad 4 | AI Perception information such as sight/hearing stimuli. |
The Behavior Tree view is especially useful because it shows two truths at once: which branch is active and which Blackboard values the tree sees. If the key value is wrong there, the tree is reacting to bad data. If the key value is right but the branch is wrong, inspect decorators and priority order.
Behavior Tree breakpoints¶
Behavior Tree assets can use breakpoints much like normal Blueprints. Use them when the debugger display tells you "this branch/task is suspicious" and you need to stop at the exact node.
Useful breakpoints:
- custom task
Event Receive Execute AI; - custom task abort event;
- service activation/tick;
- the pawn function called by an attack task;
- perception event in the AIController.
Pick the live AI instance you are debugging. Watching the wrong enemy is just as misleading in AI as it is in any other Blueprint.
Common failure patterns¶
| Symptom | Likely first place to check |
|---|---|
| Enemy never moves | Possession, AIController class, NavMesh, Move To key, movement component. |
| Enemy never sees player | Perception component, sight config, stimuli source/affiliation, line of sight, sensing interval. |
| Blackboard target is always empty | Perception event did not set the key, set wrong key name/type, or used wrong controller instance. |
| Chase branch never activates | Branch priority, TargetActor decorator, observer aborts, Blackboard value. |
| Enemy sees player but waits before chasing | Missing Lower Priority/Both abort on chase condition, or current lower-priority task must finish. |
| Enemy never returns to patrol | Target key or line-of-sight key never clears, search branch never clears last known location. |
| Enemy attacks from too far away | Attack range key/decorator is wrong, acceptable radius is too large, or distance is measured from origins. |
| Enemy does not attack in range | InAttackRange service/key is stale, attack branch is lower priority than chase, or attack task fails. |
| Tree is stuck on custom task | Task never calls Finish Execute, or latent work never reports completion. |
| Works for one enemy only | Hard cast, missing component, wrong Blackboard/key defaults, or per-instance settings differ. |
Every row has a concrete next probe. Use prints, breakpoints, and the AI Debugger to find the first false assumption.
What this pattern does not do¶
- It does not make perception, NavMesh, or possession work automatically.
- It does not require EQS, StateTree, team attitudes, or custom senses.
- It does not make attack montage timing or damage authoritative by itself.
- It does not solve multiplayer replication. AI decisions and damage should usually be server-owned in multiplayer.
- It does not replace pawn/combat functions with Behavior Tree tasks.
- It does not guarantee good game feel. Ranges, speeds, cooldowns, and aborts still need tuning.
Lookalikes - which one do I want?¶
| Tool | Use when | Watch out |
|---|---|---|
| Patrol branch | AI should move through random or authored points when idle. | Needs valid reachable locations. |
| Chase branch | AI has a target actor and should close distance. | Do not also spam AI Move To from perception. |
| Search branch | AI lost target but has a last known location. | Clear search memory deliberately when done. |
| Attack branch | Target is valid and in range. | Task should call pawn/combat behavior, not own every attack detail. |
| AI Debugger | You need live NavMesh, AI, Behavior Tree, Blackboard, and perception evidence. | It observes; it does not fix setup. |
| Blueprint breakpoints | You need to pause a task/service/controller event. | Must target the live instance that is running. |
| Print String | You need quick proof a path ran and what value it saw. | Remove or key noisy prints. |
| Visual Logger / EQS debugger | You are debugging environment query choices or recorded AI decisions. | More advanced than the first patrol/chase loop. |
Rule of thumb: build the smallest readable enemy loop first, then debug the layer that owns the fact you distrust.
Going deeper¶
- Behavior Trees and Blackboards for Blueprint Beginners - the AIController/tree/Blackboard/pawn ownership split.
- Run Behavior Tree, AIController Setup, and Blackboard Keys - starting the tree and setting initial keys.
- Move To Task, Decorators, Services, and Observer Aborts - the branch mechanics used by this pattern.
- AI Move To & the NavMesh - movement and NavMesh setup failures.
- Seeing the player: Pawn Sensing & AI Perception - perception setup and target forgetting.
- Breakpoints and watch values - stopping on the live task/controller instance.
- Print String and the Output Log - quick runtime evidence.
- Animation Montages / Play Montage - one-shot attack animation playback.
- Event AnyDamage / Apply Damage - applying authoritative damage from an attack.
- Replication basics - server-owned AI decisions in multiplayer.
- Official docs: Behavior Tree Quick Start Guide, AI Debugging, and Using the Gameplay Debugger.
- Engine source (requires engine access - we do not reproduce it here):
Behavior Tree execution and debugging support in
Engine/Source/Runtime/AIModule/Private/BehaviorTree/BehaviorTreeComponent.cpp; Move To task behavior inEngine/Source/Runtime/AIModule/Private/BehaviorTree/Tasks/BTTask_MoveTo.cpp; AI perception components underEngine/Source/Runtime/AIModule/Private/Perception/; path following inEngine/Source/Runtime/AIModule/Private/Navigation/PathFollowingComponent.cpp; Gameplay Debugger runtime code underEngine/Source/Runtime/GameplayDebugger/.