[UE5] Building Enemy AI with Behavior Trees: Patrol, Detect, Chase, Attack

Created: 2025-12-12Last updated: 2026-07-19

Behavior Trees let you build enemy AI without drowning in Branch nodes. This article diagrams the difference between Selector and Sequence, the role of the Blackboard, and when to use Decorators versus Services, with a hands-on build of a patrol-detect-chase-attack enemy from scratch.

Everyone building enemy AI walks the same path. You write "chase the player when you see them" with a Branch, add "attack when in range," then add "return to patrolling when you lose them." Before long you have a giant graph of nested branches.

A Behavior Tree is a system for writing that decision-making as a tree. "Which action takes priority" is expressed vertically, and "in what order" horizontally, so the AI's plan reads as a diagram. This article covers the core difference between Selector and Sequence, then walks through building a patrol β†’ detect β†’ chase β†’ attack enemy from scratch.

Illustration contrasting a graph full of branches with a cleanly organized tree

What You'll Learn

  • AI runs on a set of three (AI Controller, Behavior Tree, Blackboard)
  • Selector = priority (any one) / Sequence = procedure (all of them)
  • Task = action, Decorator = condition, Service = periodic monitoring
  • Handing detection to AI Perception gets you sight and sound for free
  • Hands-on: building a patrol β†’ detect β†’ chase β†’ attack enemy

Sponsored

The Three Parts That Drive AI

A Behavior Tree doesn't run on its own. The standard setup combines these three.

Diagram of the role split: the AI Controller is the brain, the Behavior Tree is the plan of action, and the Blackboard is memory
PartRoleIn a word
AI ControllerDrives the Pawn. Starts the BTThe one inside
Behavior TreeThe tree that decides "what next"The plan of action
BlackboardWhere the AI stores values it remembersMemory (a notepad)

The Blackboard matters most. It holds the decision-making data you want shared between nodes, like "who am I chasing right now" and "where am I headed." (Tasks also call Pawn functions and move things directly, so the Blackboard isn't the only mechanism at work.)

Why create a shared place at all? Because if nodes pass data directly to each other, swapping one node means fixing its neighbors too. Having everyone look at the same notepad makes adding and replacing nodes safe.

Selector and Sequence: How to Read the Tree

Whether you can read a Behavior Tree comes down to whether you understand these two.

Comparison diagram showing that a Selector stops where something succeeds while a Sequence stops where something fails

Both try their children left to right. What differs is when they stop.

BehaviorWhat it meansThink of it as
SelectorStops on success (succeeds if any one child succeeds)Priority"Try top to bottom and take the first one that works"
SequenceStops on failure (succeeds only if all children succeed)Procedure"Abort if any single step trips"

Let's think through an example. Put a Selector at the root of an enemy AI, with children ordered left to right as "attack," "chase," and "patrol."

  • Able to attack β†’ attack and stop (the children to the right are never tried)
  • Can't attack but can chase β†’ chase and stop
  • Neither works β†’ patrol

That's priority. Further left reads as higher priority.

Meanwhile, the inside of "chase" is a Sequence, because "move to the target" β†’ "face them" is a procedure to run in order. If a step fails partway, there's no point doing the rest.

A way to remember it: Selector is close to "or," and Sequence is close to "and" (not as a strict logical operation, but as an approximation for grasping how results propagate). Pick based on whether any one will do or you need all of them.

Task, Decorator, and Service

There are three kinds of building blocks, and not mixing their roles is the trick to keeping things readable.

Diagram of the roles: Task is an action, Decorator is a conditional gate, and Service is a periodic watcher
KindRoleAppearanceExamples
TaskActs (the leaves)Purple-ish nodeMove To, Wait, attack
DecoratorDecides whether to let flow through (a gate)Band attached above a node"Let through if there's a target"
ServiceChecks periodically while that branch is activeBand attached below a nodeMeasure distance and write it to the Blackboard

As a rule, splitting things like this keeps them readable (this is a design guideline, not an engine constraint).

  • Tasks handle actions: leave "am I in attack range" to a Decorator. That said, a Task checking its preconditions at runtime and returning failure is a perfectly normal usage
  • Decorators handle decisions: keep them to reading conditions and don't have them rewrite Blackboard values. Side effects make it impossible to trace why something passed through

One thing to watch with Services: they only run while the branch they're attached to is executing. If you want to monitor the whole AI at all times, you need to attach it to a branch near the root.

Draw these lines and just looking at the tree tells you "under what conditions does this AI do what."

Let AI Perception Handle Detection

You can implement "did I spot the player" by measuring distance inside a Service every tick. But for anything serious, the AI Perception Component is a better fit.

Comparison diagram of a Service going out to check its surroundings versus AI Perception notifying you the instant something is seen
Service approachAI Perception approach
How it worksPolls on your own at a fixed intervalNotifies you when perception state changes
What it handlesOnly the checks you writeSight (angle, distance), sound, damage
ObstaclesYou have to write traces yourselfLine-of-sight checks are built in
EaseQuick to writeMany settings to configure

With AI Perception, obvious behaviors like "can't see the player through a wall" and "can't see behind you" come mostly from settings (whether a wall blocks sight assumes that wall's collision settings respond to the line-of-sight trace). That's a surprisingly annoying thing to write yourself.

The hands-on section uses AI Perception. Services are better suited to supplementary monitoring like "measure the distance to the target and write it to the Blackboard." To add hearing on top of sight, or to nail down what happens after losing the target, see Getting Enemies to Notice You with AI Perception.

Sponsored

Hands-On: Making a Patrolling Enemy Spot the Player

A guard in a stealth game, a wandering enemy in a horror game, a field monster in an action RPG. "Patrol normally, chase when you spot someone, attack when close" is the basic form of AI. Let's build it from scratch.

Setup to follow along: prepare the following. You can create these from right-click β†’ Artificial Intelligence.

TypeNameSettings
CharacterBP_EnemyAI Controller Class set to BP_EnemyAIController, Auto Possess AI set to Placed in World or Spawned
AIControllerBP_EnemyAIControllerAdd an AIPerception Component
BlackboardBB_EnemyTwo keys (table below)
Behavior TreeBT_EnemyBlackboard Asset set to BB_Enemy
LevelNav Mesh Bounds VolumeSized to cover the floor. Press P and confirm it turns green
PlayerBP_ThirdPersonCharacterAdd Player to Actor Tags (used to identify the perception target)

Forget Auto Possess AI and the enemy you placed in the level never gets an AI Controller, so nothing moves.

There are two Blackboard keys.

Key nameTypePurpose
TargetActorObject (Base Class: Actor)Who to chase
PatrolLocationVectorThe next patrol point to head to

Step 1: Configure AI Perception. Select AIPerception on BP_EnemyAIController and add AI Sight config to Senses Config.

SettingValue
Sight Radius1500.0
Lose Sight Radius1800.0 (larger than Sight Radius)
Peripheral Vision Half Angle60.0 = 60 degrees to each side of forward (about a 120-degree field of view)
Detection by Affiliation β†’ Detect NeutralsChecked

Checking Detect Neutrals is the key part. Actors without a Team are treated as neutral, so this alone is enough to test with.

Step 2: Confirm what you perceived is actually the player. This is the easiest place to get it wrong. AI Perception hands you any Actor it perceives, so dropping that straight into TargetActor makes the enemy start chasing other enemies and NPCs too.

Node graph checking the Tag from OnTargetPerceptionUpdated and either setting or clearing TargetActor
Event On Target Perception Updated (AIPerception)
  β†’ Actor Has Tag (Target: Actor, Tag: "Player")
  β†’ Branch
      False β†’ (do nothing)                                  ← ignore anything but the player
      True  β†’ Branch (Condition: Successfully Sensed on Stimulus)
          True  β†’ Get Blackboard β†’ Set Value as Object
                    (Key Name: TargetActor, Object Value: Actor)      ← spotted them
          False β†’ Branch (Condition: Actor == Get Blackboard Value as Actor (TargetActor))
              True β†’ Get Blackboard β†’ Clear Value (Key Name: TargetActor) ← lost the one we were chasing

Notice there are two checks in there.

  • Check the Tag to confirm it's the player: without it, chasing starts the instant a friendly NPC comes into view
  • Confirm the one you lost is the one you're currently chasing: an unconditional Clear Value means losing sight of some unrelated Actor wipes your target

Wire the return value of Get Blackboard (an AI Controller function) into the Target pins of Set Value as Object and Clear Value. Leave that empty and nothing is written.

Step 3: Start the Behavior Tree. Kick off the tree in Event On Possess.

Event On Possess (BP_EnemyAIController)
  β†’ Run Behavior Tree (BTAsset: BT_Enemy)

Using On Possess rather than BeginPlay is the reliable choice, because it starts once the Pawn being controlled is settled. The official workflow uses this form too.

Step 4: Build the tree. Open BT_Enemy and assemble it like this. Left means higher priority.

Behavior Tree diagram with a root Selector, a chase Sequence on the left, and a patrol Sequence on the right
Root
└─ Selector                              ← any one of these will do
   β”œβ”€ Sequence "Fight"                   ← on the left, so higher priority
   β”‚   βš‘ 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)      ← attack interval. Without it, attacks fire nonstop
   └─ Sequence "Patrol"                   ← only reached when there's no target
       β”œβ”€ Task: BTT_FindPatrolLocation
       β”œβ”€ Task: Move To (Blackboard Key: PatrolLocation)
       └─ Task: Wait (Wait Time: 2.0)

Three settings matter here.

  • Set the Decorator's Observer aborts to Both: this is what makes spotting the player mid-patrol abort the patrol and switch to chasing immediately. Leave it at None and nothing happens until the patrol finishes
  • Put a Wait in the fight branch too: if Tasks keep returning success instantly, the tree spins at full speed and attacks fire nonstop
  • Acceptable Radius on Move To: too small and the AI never reaches its goal, walking forever

Step 5: Build the Task that picks a patrol point. Derive BTT_FindPatrolLocation from BTTask_BlueprintBase.

The standard approach is receiving the destination key through a variable of type Blackboard Key Selector. That way you can pick the key from the details panel when you select the Task in the Behavior Tree, and reuse the same Task with a different key.

Node graph finding a point with Get Random Reachable Point in Radius, writing it to the Blackboard's PatrolLocation, and returning success with Finish Execute
Variable: PatrolKey (Blackboard Key Selector type, Instance Editable)

Event Receive Execute AI (Controlled Pawn)
  β†’ Get Random Reachable Point in Radius (Origin: Controlled Pawn's location, Radius: 1000.0)
  β†’ Branch (Condition: whether the return value succeeded)
      True  β†’ Set Blackboard Value as Vector (Key: PatrolKey, Value: the point found)
            β†’ Finish Execute (Success: true)
      False β†’ Finish Execute (Success: false)

Select this Task in the Behavior Tree and assign PatrolLocation to Patrol Key in the details panel.

Build BTT_Attack the same way, returning Finish Execute (Success: true) after the attack logic. A Print String is fine as the entire contents at first.

Step 6: Place it in the level and run it. Drag BP_Enemy into the level and hit Play.

The enemy wanders randomly within its radius, turns toward you the instant you enter its view, and once close, prints an attack log once per second. Hide behind cover and it returns to patrolling. If you see that, it works.

When it doesn't, keep the Behavior Tree open while you Play and the currently executing node lights up. You can check values in the Blackboard panel, and with multiple enemies you pick the target from Debug Object at the top of the editor.

  • Doesn't move at all β†’ Nav Mesh Bounds Volume (check with P), Auto Possess AI, AI Controller Class
  • Patrols but never chases β†’ check TargetActor in the Blackboard panel. If it's empty, the problem is on the AI Perception side or the Tag spelling
  • Chases other enemies β†’ the Tag check is missing
  • Never returns to patrolling once it starts chasing β†’ check the condition on Clear Value
  • Attack logs stream past at high speed β†’ the Wait in the fight branch is missing
  • Freezes on one node β†’ that Task never calls Finish Execute

There are two key points.

  • Express priority through the Selector's left-to-right order: instead of adding conditional branches, express priority with the order of the branches. To make "do nothing when stunned" the top priority, you just add it as the leftmost branch
  • Always filter the Actors you perceive: AI Perception hands you anything it sees. Confirm once, via Tag or class, that it's a target you care about. Skip that and you get the strange AI where enemies chase each other

When you want smarter choices about "where to flee" or "which enemy to target," EQS (Environment Query System) is the next step. If movement itself is unstable, check NavMesh settings first.

Sponsored

Bonus: Good to Know for Later

The default way to debug a Behavior Tree is to Play with the editor open. The executing node is highlighted, and you can see current Blackboard values in the Blackboard panel. Seeing visually "why is it doing this" is one of BT's biggest advantages. Look at the tree before you start planting Print String calls.

Don't leave Service intervals at their defaults. Services let you set an Interval, and leaving it at the default across many AIs adds up. For something like a distance check, 0.3 to 0.5 seconds is plenty. Adding a bit of Random Deviation avoids every AI's work landing on the same frame.

A Task that keeps returning Success makes the tree spin at full speed. That's why the patrol Sequence has a Wait. When "the AI isn't doing anything but it's heavy," suspect a branch looping at extreme speed somewhere.

Holding the AI's "state" as an Enum on the Blackboard keeps things organized. Keep the broad categories, like patrolling, alerted, and in combat, as an Enum key, and have each branch's Decorator read it. The tree structure gets much easier to read. Think of it as bringing state-machine thinking into a BT.

StateTree is another option. In the UE5 era, StateTree β€” which turns states and transitions directly into a diagram β€” is showing up more and more in official samples. Behavior Tree is still very much alive and has far more material available, so nothing in this article goes to waste. That said, when you build a new AI, it's worth comparing first: StateTree if the states are clearly defined, Behavior Tree if priority juggling is the heart of it (see Introduction to StateTree).


Summary

Behavior Trees have a lot of parts to learn, but the skeleton you need is simple.

ElementRoleWhen to use it
SelectorAny one succeeding is enoughWhen you want to express priority
SequenceAll must succeedWhen you want to express a procedure
TaskActsAnything you'd phrase as "do X"
DecoratorDecides whether to let throughAnything you'd phrase as "if X"
ServiceChecks periodicallyAnything you want to "keep an eye on"
BlackboardHolds memoryValues you want shared between nodes

And one design guideline: conditions in Decorators, actions in Tasks, memory in the Blackboard. Just keeping those three separate keeps your AI extensible later.

After your enemy loses sight of the player, how do you want it to behave?