gamedev-skills/unreal-behavior-trees
> (Selector/Sequence), tasks, decorators, services, and running the tree from an AIController. Use when creating enemy/NPC AI, BT_/BB_ assets, custom BTTask or BTService nodes, or when the user mentions Behavior Tree, Blackboard, AIController, BTTask, decorator, or service.
npx skills add https://github.com/gamedev-skills/awesome-gamedev-agent-skills --skill 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.4+.
BT_/BB_ asset pair, structuringSelector/Sequence branches, adding decorators (conditions) and services (periodic updates),
writing custom BTTask/BTService nodes, or wiring an AIController to run the tree.
BT_) and Blackboard (BB_) assets and anAAIController.
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.
BB_) holds typed keys (the AI's memory: TargetActor,LastKnownLocation, bIsInvestigating); a Behavior Tree (BT_) references that Blackboard.
AAIController possesses the pawn and calls RunBehaviorTree(BT),which also initializes the referenced Blackboard.
(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.
combat branch). Set Observer Aborts so the tree re-evaluates when the key changes.
(e.g. update TargetActor via a sight check) only while that branch is active.
Succeeded, Failed, or InProgress (latent tasks likeMoveTo finish later).
shows live Blackboard values, so you see exactly which branch executes.
void AEnemyAIController::OnPossess(APawn* InPawn)
{
Super::OnPossess(InPawn);
if (BehaviorTree) // UPROPERTY(EditAnywhere) TObjectPtr<UBehaviorTree>
RunBehaviorTree(BehaviorTree); // initializes & uses the Blackboard the BT references
}
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.
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.
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 thetarget is off the navmesh.
None; set it to Self/Lower Priority/Both so the tree re-evaluates when the key changes.
InProgress and never callsFinishLatentTask. Always complete latent tasks.
SetValueAsObject("Taget", ...) silently does nothing; match thekey name and type exactly, or use a cached FBlackboardKeySelector.
(stops on first success). Swapping them inverts the behaviour.
UBTTaskNode (instant and latent ExecuteTask returning EBTNodeResult,with a FBlackboardKeySelector), read references/custom-bttask.md.
(https://dev.epicgames.com/documentation/en-us/unreal-engine/behavior-trees-in-unreal-engine).
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.Take gamedev-skills/unreal-behavior-trees from the repository into ~/.claude/skills for personal
use, or into .claude/skills inside a project.
The agent identifies a skill by the name field in its header. Two skills with the
same name cannot sit side by side — one of them will be ignored.