Unreal Behavior Trees
Author NPC decision-making in UE5 with Behavior Trees driven by a Blackboard: structure the
tree with composites, gate branches with decorators, keep state current with services, and run
it from an AIController. Targets UE 5.8.
When to use
- Use when building enemy/NPC AI: creating a
BT_/BB_ asset pair, structuring
Selector/Sequence branches, adding decorators (conditions) and services (periodic updates),
writing custom BTTask/BTService nodes, or wiring an AIController to run the tree.
- Use when the project has Behavior Tree (
BT_) and Blackboard (BB_) assets and an
AAIController.
When not to use: the concept of AI (FSM vs BT vs steering, cross-engine) →
game-ai. Pure navigation/pathing math is engine navmesh (BT's MoveTo uses it). Simple
one-off logic may be cheaper as a small state machine than a full tree.
Core workflow
- Create the pair: a Blackboard (
BB_) holds typed keys (the AI's memory: TargetActor,
LastKnownLocation, bIsInvestigating); a Behavior Tree (BT_) references that Blackboard.
- Possess and run. An
AAIController possesses the pawn and calls RunBehaviorTree(BT),
which also initializes the referenced Blackboard.
- Structure with composites. Selector runs children left→right until one succeeds
(priority/fallback: "attack, else chase, else patrol"). Sequence runs children until one
fails (do-all: "move to cover → reload → peek"). Simple Parallel runs one main task
alongside a secondary.
- Gate branches with Decorators that read Blackboard keys (e.g. "Has Target?" guards the
combat branch). Set Observer Aborts so the tree re-evaluates when the key changes.
- Keep the Blackboard current with Services attached to a branch — they tick periodically
(e.g. update
TargetActor via a sight check) only while that branch is active.
- Do work in Tasks, which return
Succeeded, Failed, or InProgress (latent tasks like
MoveTo finish later).
- Verify with the Behavior Tree debugger during PIE — it highlights the running node and
shows live Blackboard values, so you see exactly which branch executes.
Patterns
1. AIController that runs the tree (C++)
void AEnemyAIController::OnPossess(APawn* InPawn)
{
Super::OnPossess(InPawn);
if (BehaviorTree) // UPROPERTY(EditAnywhere) TObjectPtr<UBehaviorTree>
RunBehaviorTree(BehaviorTree); // initializes & uses the Blackboard the BT references
}
2. A priority tree (node structure)
ROOT
└── Selector (try combat, else investigate, else patrol)
├── Sequence [Decorator: Blackboard 'TargetActor' Is Set, Observer Aborts: Both]
│ ├── Task: MoveTo (TargetActor) // latent: returns InProgress then Succeeded
│ └── Task: Attack
├── Sequence [Decorator: 'LastKnownLocation' Is Set]
│ ├── Task: MoveTo (LastKnownLocation)
│ └── Task: Wait (3s) + clear key
└── Task: Patrol (BTTask_FindPatrolPoint -> MoveTo)
Observer Aborts: Both makes the combat branch interrupt patrol the instant TargetActor is
set, and bail out when it's cleared — this is what makes the AI feel reactive.
3. Updating the Blackboard from code (e.g. on seeing the player)
void AEnemyAIController::SetTarget(AActor* Target)
{
if (UBlackboardComponent* BB = GetBlackboardComponent())
BB->SetValueAsObject(TEXT("TargetActor"), Target); // key name must match the BB asset
}
// Clear with BB->ClearValue(TEXT("TargetActor")); to drop back to a lower-priority branch.
Pitfalls
- AI never starts — the pawn isn't possessed (set the Pawn's Auto Possess AI to "Placed
in World or Spawned" and assign the AIController), or
RunBehaviorTree was never called.
MoveTo instantly fails — no NavMesh in the level (add a Nav Mesh Bounds Volume), or the
target is off the navmesh.
- Branch doesn't react to changes — the gating Decorator's Observer Aborts is set to
None; set it to Self/Lower Priority/Both so the tree re-evaluates when the key changes.
- A task hangs the tree — a custom task returned
InProgress and never calls
FinishLatentTask. Always complete latent tasks.
- Blackboard key typos —
SetValueAsObject("Taget", ...) silently does nothing; match the
key name and type exactly, or use a cached FBlackboardKeySelector.
- Sequence vs Selector confusion — Sequence = AND (stops on first failure); Selector = OR
(stops on first success). Swapping them inverts the behaviour.
References
- For a custom C++
UBTTaskNode (instant and latent ExecuteTask returning EBTNodeResult,
with a FBlackboardKeySelector), read references/custom-bttask.md.
- Primary docs: "Behavior Trees in Unreal Engine"
(
https://dev.epicgames.com/documentation/en-us/unreal-engine/behavior-trees-in-unreal-engine).
Related skills
game-ai — engine-agnostic AI design (FSM, BT, steering, pathfinding choices).
unreal-cpp-gameplay — the AIController and pawn classes in C++.
fps-shooter / tower-defense — genres that compose enemy AI.
1---
2name: unreal-behavior-trees
3description: >
4 Build NPC AI in Unreal Engine 5 with Behavior Trees and Blackboards: composites
5 (Selector/Sequence), tasks, decorators, services, and running the tree from an AIController.
6 Use when creating enemy/NPC AI, BT_/BB_ assets, custom BTTask or BTService nodes, or when
7 the user mentions Behavior Tree, Blackboard, AIController, BTTask, decorator, or service.
8---
9
10# Unreal Behavior Trees
11
12Author NPC decision-making in UE5 with Behavior Trees driven by a Blackboard: structure the
13tree with composites, gate branches with decorators, keep state current with services, and run
14it from an AIController. Targets **UE 5.8**.
15
16## When to use
17
18- Use when building enemy/NPC AI: creating a `BT_`/`BB_` asset pair, structuring
19 Selector/Sequence branches, adding decorators (conditions) and services (periodic updates),
20 writing custom `BTTask`/`BTService` nodes, or wiring an AIController to run the tree.
21- Use when the project has Behavior Tree (`BT_`) and Blackboard (`BB_`) assets and an
22 `AAIController`.
23
24**When *not* to use:** the *concept* of AI (FSM vs BT vs steering, cross-engine) →
25`game-ai`. Pure navigation/pathing math is engine navmesh (BT's `MoveTo` uses it). Simple
26one-off logic may be cheaper as a small state machine than a full tree.
27
28## Core workflow
29
301. **Create the pair:** a Blackboard (`BB_`) holds typed keys (the AI's memory: `TargetActor`,
31 `LastKnownLocation`, `bIsInvestigating`); a Behavior Tree (`BT_`) references that Blackboard.
322. **Possess and run.** An `AAIController` possesses the pawn and calls `RunBehaviorTree(BT)`,
33 which also initializes the referenced Blackboard.
343. **Structure with composites.** **Selector** runs children left→right until one *succeeds*
35 (priority/fallback: "attack, else chase, else patrol"). **Sequence** runs children until one
36 *fails* (do-all: "move to cover → reload → peek"). **Simple Parallel** runs one main task
37 alongside a secondary.
384. **Gate branches with Decorators** that read Blackboard keys (e.g. "Has Target?" guards the
39 combat branch). Set **Observer Aborts** so the tree re-evaluates when the key changes.
405. **Keep the Blackboard current with Services** attached to a branch — they tick periodically
41 (e.g. update `TargetActor` via a sight check) only while that branch is active.
426. **Do work in Tasks**, which return `Succeeded`, `Failed`, or `InProgress` (latent tasks like
43 `MoveTo` finish later).
447. **Verify** with the Behavior Tree debugger during PIE — it highlights the running node and
45 shows live Blackboard values, so you see exactly which branch executes.
46
47## Patterns
48
49### 1. AIController that runs the tree (C++)
50
51```cpp
52void AEnemyAIController::OnPossess(APawn* InPawn)
53{
54 Super::OnPossess(InPawn);
55 if (BehaviorTree) // UPROPERTY(EditAnywhere) TObjectPtr<UBehaviorTree>
56 RunBehaviorTree(BehaviorTree); // initializes & uses the Blackboard the BT references
57}
58```
59
60### 2. A priority tree (node structure)
61
62```text
63ROOT
64└── Selector (try combat, else investigate, else patrol)
65 ├── Sequence [Decorator: Blackboard 'TargetActor' Is Set, Observer Aborts: Both]
66 │ ├── Task: MoveTo (TargetActor) // latent: returns InProgress then Succeeded
67 │ └── Task: Attack
68 ├── Sequence [Decorator: 'LastKnownLocation' Is Set]
69 │ ├── Task: MoveTo (LastKnownLocation)
70 │ └── Task: Wait (3s) + clear key
71 └── Task: Patrol (BTTask_FindPatrolPoint -> MoveTo)
72```
73
74`Observer Aborts: Both` makes the combat branch interrupt patrol the instant `TargetActor` is
75set, and bail out when it's cleared — this is what makes the AI feel reactive.
76
77### 3. Updating the Blackboard from code (e.g. on seeing the player)
78
79```cpp
80void AEnemyAIController::SetTarget(AActor* Target)
81{
82 if (UBlackboardComponent* BB = GetBlackboardComponent())
83 BB->SetValueAsObject(TEXT("TargetActor"), Target); // key name must match the BB asset
84}
85// Clear with BB->ClearValue(TEXT("TargetActor")); to drop back to a lower-priority branch.
86```
87
88## Pitfalls
89
90- **AI never starts** — the pawn isn't possessed (set the Pawn's *Auto Possess AI* to "Placed
91 in World or Spawned" and assign the AIController), or `RunBehaviorTree` was never called.
92- **`MoveTo` instantly fails** — no NavMesh in the level (add a Nav Mesh Bounds Volume), or the
93 target is off the navmesh.
94- **Branch doesn't react to changes** — the gating Decorator's **Observer Aborts** is set to
95 None; set it to Self/Lower Priority/Both so the tree re-evaluates when the key changes.
96- **A task hangs the tree** — a custom task returned `InProgress` and never calls
97 `FinishLatentTask`. Always complete latent tasks.
98- **Blackboard key typos** — `SetValueAsObject("Taget", ...)` silently does nothing; match the
99 key name and type exactly, or use a cached `FBlackboardKeySelector`.
100- **Sequence vs Selector confusion** — Sequence = AND (stops on first failure); Selector = OR
101 (stops on first success). Swapping them inverts the behaviour.
102
103## References
104
105- For a **custom C++ `UBTTaskNode`** (instant and latent `ExecuteTask` returning `EBTNodeResult`,
106 with a `FBlackboardKeySelector`), read `references/custom-bttask.md`.
107- Primary docs: "Behavior Trees in Unreal Engine"
108 (`https://dev.epicgames.com/documentation/en-us/unreal-engine/behavior-trees-in-unreal-engine`).
109
110## Related skills
111
112- `game-ai` — engine-agnostic AI design (FSM, BT, steering, pathfinding choices).
113- `unreal-cpp-gameplay` — the AIController and pawn classes in C++.
114- `fps-shooter` / `tower-defense` — genres that compose enemy AI.