[UE5] Behavior Tree Basics: A Patrolling Enemy That Spots the Player and Gives Chase

Created: 2025-12-12Last updated: 2026-09-06

Build an AI where a patrolling enemy chases the player on sight and returns to patrol when it loses them. Diagrams cover Selector and Sequence, the Blackboard, and Task running/success/failure, through to Observer Aborts for switching behavior mid-action.

An enemy walks around a room and comes after the player when it spots them. Hide behind a wall and it stops chasing and starts walking again. Building an enemy like this requires thinking about "when do we switch to which behavior," on top of the movement itself.

A Behavior Tree is a system for building that choice of behavior as a tree. You express a policy such as "chase if the target is visible, otherwise patrol" through branch conditions and ordering.

In other engines: neither Unity nor Godot has a standard feature equivalent to this (you cover it with assets or your own code). The fact that it is built into the engine is an advantage when building AI in UE.

In this article we first get patrol working, then add spotting and chasing the player. At the end we display "Attack" when the enemy gets close and confirm the behavior actually switched.

An image of an enemy AI's policy organized as a tree of conditions and behaviors

What You'll Learn

  • How AI Controller, Behavior Tree, and Blackboard divide the work
  • How to read a tree using Selector and Sequence
  • The procedure of getting patrol working first, then adding the chase branch
  • How Observer Aborts switches behavior mid-action

What You'll Build

  • An enemy that picks a nearby destination, walks to it, and waits 2 seconds
  • It aborts patrol and gives chase when it spots the player, logging an attack when it gets close
  • It aborts the chase and returns to patrol when it loses sight

This is a single-player example using UE5's Third Person template. Attack animations and damage can be added once this AI's decision-making works.

Sponsored

Three roles that drive the AI

A Behavior Tree alone does not move the enemy on screen. You combine something that controls it, something that chooses behavior, and somewhere to remember decision material.

How AI Controller, Behavior Tree, Blackboard, and the enemy's body divide the work
PartIts role here
AI ControllerControls the enemy's body and starts the Behavior Tree
Behavior TreeLooks at conditions and picks patrol, chase, and so on
BlackboardStores "who to chase" and "where to walk"

The controlled body is called a Pawn. The Character we use here is a kind of Pawn with movement built in. Thinking of it as "the AI Controller is the driver, the Character is the body" makes the roles easy to separate.

The Blackboard is like a shared note the AI reads. The logic that spots a target writes "who to chase," and the chase logic reads it and moves. The spotting logic no longer has to send individual instructions to patrol, chase, and everything else.

Selector and Sequence: how to read the tree

You follow the tree from the Root at the top. Children under the same parent are tried from the left. The first thing to learn is the two kinds that decide how a child's result is handled.

Selector finishes where it succeeds, Sequence finishes where it fails
KindWhen a child succeedsWhen a child fails
SelectorSucceeds and finishes thereTries the next child. Fails if all fail
SequenceMoves to the next child. Succeeds if all succeedFails and finishes there

A Selector expresses "which behavior to choose." Put "chase the player" on the left and "patrol" on the right, and as long as the chase condition holds, that one is picked first.

A Sequence expresses "what steps the chosen behavior goes through." For patrol that is "pick a destination → move there → wait a moment." If the movement fails, it does not advance to the wait; it ends this sequence as a failure.

"Running" is neither success nor failure

A part responsible for a single behavior, such as movement, is called a Task. While the enemy walks toward its destination, the movement Task is Running (In Progress). Simply issuing the move order is not success, and it does not advance to the next Task until it arrives.

Move To stays running until arrival, then succeeds and moves on to Wait

The same is true of a Selector. The chase on the left being in progress does not mean the patrol on the right also starts. Waiting for one Task's result, and only advancing once success or failure is decided, is the basic behavior of this tree. Switching behavior mid-action comes later.

Task, Decorator, and Service

The parts of a tree include not only ones that act but ones that check conditions.

Task acts, Decorator gates entry to a branch, and Service repeats a check while the branch runs
PartRoleExample
TaskPerforms a behaviorMove To to move, Wait to wait
DecoratorChecks whether a branch or Task may runLet it through if "there is a target"
ServiceRepeatedly checks while the branch it is attached to runsMeasure the distance to the target at an interval

Splitting it as Decorator is condition, Task is behavior makes the flow of judgment visible when you read the tree. That said, a Task may also check its target just before running and return failure if it is invalid.

A Service stops once you leave its branch. If the check is needed during every behavior, attach it to the parent that bundles both branches. Spotting and losing sight here use AI Perception notifications, covered later, so there is no need to write your own Service.

Prepare the enemy and somewhere to walk

Create the enemy's body and its controller

Open the Third Person template and create an "AI" folder to work in.

  1. Duplicate "BP_ThirdPersonCharacter" and name it "BP_Enemy." You get to reuse the enemy's appearance and walk animation.
  2. Open BP_Enemy and delete the input handling nodes in the EventGraph. The player you duplicated from stays as it is.
  3. Create a new "Blueprint Class," search "All Classes" for "AIController," and select it. Name it "BP_EnemyAIController."
  4. In BP_Enemy's "Class Defaults," set the control settings in the table below. The two Character Movement entries are set by selecting that component under "Components."
SettingValue
AI Controller ClassBP_EnemyAIController
Auto Possess AIPlaced in World or Spawned
Auto Possess PlayerDisabled
Use Controller Rotation YawOff
Character Movement → Orient Rotation to MovementOn
Character Movement → Max Walk Speed300

Possessing is a Controller taking over control of a Pawn. The Auto Possess AI setting attaches an AI Controller both to enemies placed in the level and to ones spawned later. The rotation settings make the enemy face the direction it walks. UE's default unit is centimeters, so Max Walk Speed 300 is 3 m/s.

Build a map the AI can walk on

Place one enemy on a flat part of the level, add a "Nav Mesh Bounds Volume," and cover the whole floor the enemy and player walk on. Press P and confirm the green area appears on the floor.

This NavMesh is the AI's "map of where it can walk." Even if it looks like a floor, Move To cannot walk there without a map. If it does not turn green, check the NavMesh article first.

On a floor with a NavMesh, a path around obstacles can be found

Create the Blackboard and Behavior Tree

Right-click in the content browser and create a "Blackboard" and a "Behavior Tree" from "Artificial Intelligence." Name them "BB_Enemy" and "BT_Enemy."

Open BB_Enemy and create the following two entries with "New Key." A Key is the name of an entry you store.

Key nameType and settingWhat it stores
TargetActorObject, Base Class = ActorThe target being chased
PatrolLocationVectorThe next place to walk

An Object holds a reference pointing at "that specific thing in the level." It is not a field for a name string. A Vector is three values X, Y, and Z, representing a location here.

Open BT_Enemy, set "Blackboard Asset" to BB_Enemy, and save. Now the tree can select both Keys.

Sponsored

Get patrol working first

Create a Task that picks a destination

From BT_Enemy's "New Task," choose "BTTask_BlueprintBase" and name it "BTT_FindPatrolLocation." In the Task, create a variable "PatrolKey" of type Blackboard Key Selector and turn on "Instance Editable."

Blackboard Key Selector is the type for choosing "which Key to write to." Enabling Instance Editable lets you specify "PatrolLocation" from the details of the Task placed in the tree.

Add "Event Receive Execute AI" to the Task's EventGraph. That event is the signal "start this Task." "Controlled Pawn" hands you the enemy body being controlled.

First, pick the coordinate to write with these connections.

  1. Controlled Pawn → Get Actor Location's "Target." This gets the enemy's current position.
  2. Current position → Get Random Reachable Point in Radius's "Origin." Set "Radius" to 1000 (a 10 m radius).
  3. Add a "Select Vector" and connect Random Location to "A," the enemy's current position to "B," and the search's Return Value to "Pick A."
Choosing the found point on success and the current position on failure

Get Random Reachable Point in Radius looks for a walkable point nearby. Return Value true means one was found, false means none was. Select Vector picks A on true and B on false, so on failure the destination becomes the current position.

Next, write the chosen coordinate and finish the Task.

  1. Receive Execute AI's white exec line → Set Blackboard Value as Vector → Finish Execute.
  2. On Set Blackboard Value as Vector, connect a Get of PatrolKey to "Key" and the Select Vector's Return Value to "Value."
  3. Turn on "Success" on Finish Execute.
Writing the chosen coordinate into the PatrolKey entry and returning Task success with Finish Execute

Finish Execute is the node that reports back to the tree that the Task is done. Success here means "the destination was written," not that the enemy arrived. Movement is left to the following Move To.

Even when the search fails, moving to the current position and then entering the wait avoids immediately retrying the search over and over. Compile and save.

Build the patrol tree and start it

In BT_Enemy, drag from Root and add a Selector. Put a Sequence under it and set its "Node Name" to "Patrol." Arrange the Sequence's children from the left in this order.

BTT_FindPatrolLocation → Move To → Wait

NodeSettings
BTT_FindPatrolLocationPatrol Key = PatrolLocation
Move ToBlackboard Key = PatrolLocation, Acceptable Radius = 50
WaitWait Time = 2.0, Random Deviation = 0
The patrol Sequence runs pick destination, move, and wait 2 seconds in order

Move To's Acceptable Radius is "how close counts as arrived." Rather than matching the position exactly, it stops once it gets reasonably close.

Finally, add "Event On Possess" to BP_EnemyAIController's EventGraph and connect it to "Run Behavior Tree." "BTAsset" is BT_Enemy.

Starting BT_Enemy from the AI Controller's On Possess

On Possess is called when the controller takes over a Pawn. Starting the tree at that point means patrol begins with the enemy it controls already decided.

Compile, save, and Play. Success is the enemy walking, waiting 2 seconds on arrival, then walking to the next spot. There is no spotting logic yet, so it keeps patrolling even if you approach.

Remember the player on the Blackboard when spotted

With patrol working, add sight to the enemy. AI Perception is the system for receiving information such as what was seen or heard. We use sight only.

Remembering the target when line of sight is clear, and clearing it when a wall blocks it

Set the sight distance and angle

Add an "AI Perception" component to BP_EnemyAIController. Add one "AI Sight config" to "Senses Config" and set the following.

ItemValue and meaning
Sight Radius1500: the maximum distance for newly spotting a target
Lose Sight Radius1800: the distance at which a spotted target is lost
Peripheral Vision Half Angle60: 60 degrees each side of front, about 120 degrees total
Detection by Affiliation → Detect NeutralsOn: also targets those without team settings
Starts EnabledOn

Sight Radius 1500 is 15 m. Lose Sight Radius is not a setting for seeing through walls. Hide behind a wall that blocks line of sight and it loses you even within range. Make the test wall one that Blocks the "Visibility" channel.

On the player's BP_ThirdPersonCharacter, set the following.

  • Add "Player" to the Actor "Tags" in "Class Defaults." This is separate from Component Tags.
  • Add "AI Perception Stimuli Source," turn on "Auto Register as Source," and add "AISense_Sight" to "Register as Source for Senses."

Stimuli Source is the part that registers something as detectable. Adding the Player tag here lets you tell whether a detected Actor is the player. Do not put the Player tag on BP_Enemy.

Receive the target and the sight result from the notification

Create a function "ApplySightUpdate" in BP_EnemyAIController. It takes two inputs: "SeenActor" (Actor Object Reference) and "bSensed" (Boolean). A Boolean is a true/false value, representing whether the target is visible here.

From the "+" on "On Target Perception Updated" in the AI Perception component's details, add an event and call ApplySightUpdate.

  • The event's Actor → the function's SeenActor.
  • Stimulus → Break AIStimulus → Successfully Sensed → the function's bSensed.
Passing the notification's Actor and Successfully Sensed into ApplySightUpdate

A Stimulus is the data bundling this detection result. "Successfully Sensed" true is a spotted notification; false is a lost-sight notification. Since we configured sight only, hearing notifications will not be mixed in.

Record and clear the target

Inside ApplySightUpdate, first pass SeenActor to "Actor Has Tag"'s Target with "Tag" set to Player. Connect the result to a Branch's Condition. Connect the white exec line from the function entry into this Branch, and advance only the True case into a second Branch. Pass bSensed to that second Condition.

SeenActor and bSensed come from the output pins at the function entry. Actor Has Tag is a node that inspects a value, so no white exec line runs through it. Reading white lines as order of operations and colored lines as data such as targets and results makes the connections easier to follow.

Splitting on whether a target with the Player tag was seen or not

On the second Branch's true side, create "Set Value as Object" from the return of "Get Blackboard" (Target is Self). "Key Name" is TargetActor and "Object Value" is SeenActor.

On spotting, storing SeenActor into Get Blackboard's TargetActor

On the false side, confirm "is the target we lost the one we are currently chasing?" before clearing it.

  1. From Get Blackboard's return, create "Get Value as Object" with "Key Name" set to TargetActor.
  2. Connect that Return Value and SeenActor to the two inputs of "Equal (Object)." This node returns true if they point at the same instance.
  3. Place a third Branch and connect Equal (Object)'s result to its Condition. Connect the white exec line from the bSensed Branch's False output.
  4. From the third Branch's True, go to "Clear Value" with "Target" set to Get Blackboard's return and "Key Name" set to TargetActor. Leave the False side unconnected.
Clearing TargetActor only when the lost target is the one being chased

The Target for Get Value as Object, Set Value as Object, and Clear Value is the Blackboard Component you got from Get Blackboard. That is the part for reading and writing this AI's notes. It is not where you connect the enemy Character.

Clearing only when you lose the target you are chasing prevents another Actor's notification from wiping your chase target. Wire the store and clear logic inside the same ApplySightUpdate, onto the True and False sides of the bSensed Branch respectively.

Compile and save what you have. With BT_Enemy open during Play, success is TargetActor on the Blackboard becoming the player when spotted and returning to None when lost. None means "no referenced target is stored." The enemy's behavior can still be patrol only at this stage.

Sponsored

Add the chase branch and switch mid-action

Instead of an attack, make a Task that logs

Create a new Task and name it "BTT_Attack." Connect "Event Receive Execute AI" to "Print String" with "In String" set to "Attack." Then connect to "Finish Execute" and turn on "Success." Compile and save.

The attack Task prints Attack with Print String, then returns success and finishes

Now you can confirm on screen or in the Output Log when the tree chose the attack Task. We deal no damage here; we watch whether the decision-making works.

Put the chase steps to the left of patrol

Connect another Sequence to BT_Enemy's Selector. Set "Node Name" to "Chase and attack" and place it to the left of patrol. Its children are "Move To," "BTT_Attack," and "Wait," in that order.

A tree that prioritizes the chase on the left and runs the patrol on the right when the condition fails

Set the chase-side Move To as follows.

SettingValue
Blackboard KeyTargetActor
Acceptable Radius200
Reach Test Includes Agent RadiusOff
Reach Test Includes Goal RadiusOff
Track Moving GoalOn
Allow Partial PathOff

With both capsule radii excluded from the arrival test, it advances to the next Task once it is within about 2 m. Track Moving Goal updates the path to follow a moving target. Allow Partial Path permits "a path that only gets partway to the goal"; we leave it off here.

Set the post-attack Wait to "Wait Time" 1.0 and "Random Deviation" 0. While the target is nearby, it now waits about a second between attacks. If you add real damage logic, you also need checks on the target, distance, and facing at attack time.

Abort the current behavior when the condition changes

Right-click the "Chase and attack" Sequence and add "Add Decorator" → "Blackboard." Specify the following.

SettingValue
Blackboard KeyTargetActor
Key QueryIs Set
Notify ObserverOn Result Change
Observer AbortsBoth

Is Set is the condition that checks whether a chase target is stored. But adding a condition alone cannot stop a patrol that is already running.

That is what Observer Aborts (the setting that watches a condition and aborts) is for. Both includes the two directions of aborting we want here.

  • When a target is stored, abort the patrol on the right and switch to the chase on the left.
  • When the target is cleared, abort this chase branch and return to patrol.
Both aborts patrol on spotting and aborts the chase on losing sight, switching behavior

The flow is now "the spotting logic writes to the Blackboard → the condition changes → the running branch switches." The sight logic updates target information, and the behavior switch is left to the tree.

Run it and compare the tree against the values

Play with BT_Enemy open and select the placed enemy instance from the debug target at the top of the editor. Watching the highlighted running node and the Blackboard's current values, try the following in order.

ActionExpected result
Wait outside the enemy's visionIt repeats patrol Move To and Wait
Step into the enemy's front arcTargetActor becomes the player and it switches to chase
Stop nearby"Attack" appears at roughly 1-second intervals
Block the enemy's line with a wallTargetActor becomes None and it returns to patrol

Stopping Play and changing Observer Aborts to "None" to try again is also instructive. Step in front of the enemy while it is in the patrol Wait and you can see that the target information updates but the running wait is not interrupted. Set it back to Both when you are done.

Outside its vision the patrol is highlighted, and stepping in front highlights the chase while TargetActor on the Blackboard changes
ProblemWhere to look
The enemy doesn't move at allThe green NavMesh, AI Controller Class, Auto Possess AI, the On Possess startup
It stops after picking a patrol pointWhether the Task's Patrol Key is PatrolLocation, and whether Finish Execute was called
TargetActor stays NoneThe player's Actor Tag, Sight distance and angle, Detect Neutrals, Stimuli Source
The target is stored but patrol doesn't abortThe left-right branch order, the Decorator's Observer Aborts
It keeps chasing after losing sightWhether it reaches Clear Value, and whether that Target is the Blackboard
It spots you through wallsWhether the wall's Visibility is Block
Attack prints continuouslyWhether the post-attack Wait Time is 1.0

If you add more enemies, TargetActor goes into a separate Blackboard per enemy. When checking, also confirm the debug target is the enemy you intended.

If you want it to investigate the last known position after losing sight, or to react to sound, continue to the AI Perception article. To have it pick hiding spots, EQS is next; to see an approach built around states and transitions, StateTree is the other candidate.

Bonus: Good to Know Up Front

  • Order is priority: a Behavior Tree tries children from the left. Put "chase when spotted" to the left of "patrol." Even with the condition correct, reversed order will not behave as you expect
  • Line up the references first: if even one connection among AI Controller, Behavior Tree, and Blackboard is missing, nothing runs even though it looks assembled. Match the Blackboard Key's name and type with the Task and Decorator too
  • When it won't switch, look at Observer Aborts: aborting a chase immediately, or switching the instant you spot something — these "interrupt mid-action" behaviors are decided by the difference between Self, Lower Priority, and Both
  • Add one thing at a time: finish patrol first, watch it work, then add the chase branch. Building it all at once leaves you unable to tell what caused what

Summary

In a Behavior Tree, a Selector picks the behavior and a Sequence walks through its steps. A Decorator reads the decision material stored on the Blackboard, and Tasks handle movement and waiting.

What is especially worth confirming with this enemy is that "the player was spotted" and "stop patrolling and chase" are separate things. First, did the value change; second, did the branch switch. Checking in that order keeps causes traceable as behaviors multiply.

Further Reading

Unreal Engine Notes in this section98