The enemy that chases you works. Next you want it to flee to cover when shot. Reconfiguring "hiding coordinates" by hand every time you move a rock is a chore, though.
EQS (Environment Query System) is a mechanism that compares nearby candidates by condition and picks a location fitting the current situation. Combining "not visible to the player", "walkable from here", and "close to me" finds cover that adapts to the terrain.
What You'll Learn
- That EQS consists of "generate candidates, exclude them, and score them"
- How to build a Context deciding who you hide from
- Combining not visible, walkable, and close to choose cover
- Seeing why a spot was chosen in the Testing Pane
We confirm candidate points visually, then connect to logic moving a hit enemy to cover. Even without a gun, the N key deals damage so you can try it.
- Four stages: generate candidates, exclude, score, and choose
- How to build the Context deciding "who you are hidden from"
- Confirming settings one at a time by reading dot colors and numbers
- Integrating into a Behavior Tree, including when no cover is found
Separate what makes a spot "good"
Deciding "hidden and close" by score alone may let a fully exposed spot win on closeness. Separate the conditions that are essential for hiding from those you would merely like to satisfy.

| Stage | EQS element | What we do here |
|---|---|---|
| Generate candidates | Generator | Create a grid of points around the enemy |
| Exclude by condition | Test's Filter | Drop visible points and points you cannot walk to |
| Compare the rest | Test's Score | Score points closer to the enemy higher |
| Pick one | Run Mode | Make the highest-scoring candidate the destination |
A Filter decides whether a candidate may remain, and a Score sets the priority among those that do. One Test can do both, but separating the roles at first makes settings easier to follow.
A query bundles up "what conditions to search by". Every execution examines the surroundings at that moment. EQS choosing alone does not move the enemy; passing the result to Move To is what makes it move.
Thinking of Behavior Tree as "what to do", AI Perception as "what was seen or heard", and EQS as "which candidate to choose" ties them together.
Display candidate points first
The foundation for the exercise is BP_Enemy, BP_EnemyAIController, BB_Enemy, and BT_Enemy from the Behavior Tree article. Get patrolling and chasing working with the enemy walking on the NavMesh.
For the test level, place a wide floor and two Cube walls taller than the enemy. Leave room to go around each end and ensure the NavMesh connects in front of and behind them.
1. Create a Grid
Search for Environment Query Editor in "Edit → Plugins". Enable it if it is off and restart.
Right-click in the Content Browser and create "Artificial Intelligence → Environment Query". Name it EQ_HideSpot . Once open, drag from Root and add Points: Grid .
| Item | Setting |
|---|---|
| Generate Around | EnvQueryContext_Querier |
| Grid Half Size | 800 |
| Space Between | 150 |
| Projection Data's Trace Mode | Navigation |
The Querier is whoever is running the query. Run by the enemy it is the enemy; run by the Testing Pawn we place later it is that Pawn.
Grid Half Size is the reach from the center to the edge and Space Between is the spacing between points. The standard unit is cm, so this searches 8 m around at roughly 1.5 m intervals.
Projection aligns the created points to positions on the NavMesh. That does not guarantee you can walk to a point on a separate platform, though. Whether a path connects is checked separately later.

2. Score by closeness alone
Right-click the Grid and add "Add Test → Distance".
| Item | Setting |
|---|---|
| Test Purpose | Score Only |
| Distance To | EnvQueryContext_Querier |
| Test Mode | Distance 2D |
| Scoring Equation | Linear |
| Scoring Factor | -1.0 |
Distance compares the distance from the reference to each candidate. We use planar distance here, and Scoring Factor -1 prioritizes closer points .
Next create a Blueprint Class and choose EQSTestingPawn under "All Classes". Name it BP_EQSTester and place it on the level's floor.
Select that Pawn and configure the Details like this.
| Item | Setting |
|---|---|
| Query Template | EQ_HideSpot |
| Querying Mode | All Matching |
| Draw Labels | On |
| Draw Failed Items | On |
This is a Pawn that tries the query in place of the actual enemy and displays candidate points . Use Nav Agent dimensions that match the real enemy too.
Save and move the Pawn a little, and candidates and scores update relative to its position. At this stage, success is closer points scoring better. Changing to +1 prioritizes distant ones , so compare once and return to -1.

In the display, remaining candidates are scored from red to green , with greener being better. Blue means excluded by a test. Do not read blue shades as score levels. Confirm the Draw Labels numbers alongside the colors.
Decide who you hide from
With close spots selectable, next we add "not visible to the player". That requires a Context — the target or position used as a reference for comparison .
Here, candidate generation and distance scoring use "myself" as the reference and visibility uses "the player".

Build a Context returning the player
A "Player" Context is not provided out of the box. We build a Blueprint that hands over your player.
So it works in the editor too, place exactly one BP_ThirdPersonCharacter in the level for the player. If one is already there, use it. Set that placed Actor's "Auto Possess Player" to Player 0 so you control that body on Play. Confirm in the Outliner during Play that there is one player of this Class.
BP_Enemy is a separate Class made by duplicating the player Blueprint, so it is not included in the search below. If you use an enemy made as a child Class, replace this with a Class that retrieves only the player.
- Choose EnvQueryContext_BlueprintBase under a Blueprint Class's "All Classes". Name it EQC_PlayerContext .
- Open Provide Actors Set from "Override" in "My Blueprint".
- Wire the white exec line from the entry into Get All Actors Of Class and from there into the Return Node.
- Set Actor Class to BP_ThirdPersonCharacter .
- Connect "Out Actors" into the Return Node's "Resulting Actors Set", then compile and save.

An Actors Set is the list of Actors used as references. We place only one here, so a single player is returned. That Actor exists before Play too, so the Testing Pawn can use the same Context.
Returning Get Player Character is another approach, but it is normally used during Play. Searching for a player not yet spawned in the editor cannot hand over a reference. We use a placed Actor here so visualization can be tried first.
Combine not visible, walkable, and close
1. Trace keeps the far side of a wall
Add a Trace test to EQ_HideSpot's Grid.
| Item | Setting |
|---|---|
| Test Purpose | Filter Only |
| Context | EQC_PlayerContext |
| Bool Match | On |
| Trace Mode | Geometry by Channel |
| Trace Channel | Visibility |
| Trace Shape | Line |
| Trace from Context | On |
| Item Height Offset | 90 |
| Context Height Offset | 0 |
Trace draws a line between the player and each candidate and checks whether something blocks it. Bool Match on here means "keep points where the line is blocked". Off keeps points with an unobstructed line of sight.

Drawing the line right along the floor can judge a small step as cover. Item Height Offset 90 raises the candidate side's endpoints 90 cm off the floor. The player side uses the Actor's position as is. For our Third Person Character, the reference is around the body's center rather than its feet.
The walls need Collision and must Block "Visibility". To confirm how Trace works, the Line Trace article is a useful reference.
This is a simple cover check for whether a single line at a specified height is blocked . It does not guarantee the head or whole body is fully hidden. Starting with tall walls makes the results easier to judge.
2. Pathfinding keeps points with a connected path
Add a Pathfinding test to the Grid.
| Item | Setting |
|---|---|
| Test Purpose | Filter Only |
| Test Mode | Path Exist |
| Context | EnvQueryContext_Querier |
| Path from Context | On |
| Bool Match | On |
| Skip Unreachable | On |
Path Exist confirms that a route to the point exists. Even with candidates on another NavMesh island, it drops them when there is no way across.

Leave the Distance you added first with Distance To as Querier and Scoring Factor at -1. Do not change it to "close to the player".
The query now divides roles like this. EQS adjusts test execution order, so do not read the on-screen order like Blueprint exec lines.
| Element | Role |
|---|---|
| Grid | Creates candidates around itself |
| Trace: Filter Only | Keeps points where the player's line is blocked |
| Pathfinding: Filter Only | Keeps points it can walk to |
| Distance: Score Only | Scores the closest remaining points highest |
3. Confirm by moving the walls
Put BP_EQSTester in front of a wall and the player on the other side, specify the Query Template, and look at the results. Close points that are in plain sight being excluded while blocked, reachable points remain means the conditions work as intended.

The diagram's scores illustrate closer candidates scoring higher. Actual numbers vary with the candidate layout.
Next move the player to the wall's side and nudge the Testing Pawn to recalculate. Watch whether points that hid you a moment ago get excluded. After moving a wall, also wait for the NavMesh to update.
If display gets heavy while editing a large query, temporarily clear the Testing Pawn's Query Template. Before widening the range, try coarser candidate spacing.
Hands-On: move to cover when hit
We now have "where to hide". Next we build "search when hit, move, and wait three seconds" into the Behavior Tree. When there is no cover or the move fails, it waits three seconds where it stands and returns to normal behavior.

1. Add two Keys to the Blackboard
Open BB_Enemy and add these.
| Key | Type | Purpose |
|---|---|---|
| NeedsCover | Bool | The cue to start hiding. Default false |
| HideLocation | Vector | The destination chosen by EQS |
A Blackboard is shared memory the Behavior Tree reads. NeedsCover is "does it need to hide" and HideLocation is "where to hide", kept separate. A Vector is the X, Y, Z trio representing a position.
2. Turn a hit into the cue
Confirm "Can Be Damaged" is on in BP_Enemy and add Event AnyDamage .
- Connect Get Controller's output into Get Blackboard 's Target.
- Connect Get Blackboard's Return Value into Set Value as Bool 's Target.
- Set Set Value as Bool's Key Name to
NeedsCoverand Bool Value to true. - Wire the white exec line from Event AnyDamage into Set Value as Bool.

Event AnyDamage fires when damage arrives through Apply Damage or similar. Here we record the hiding cue separately from HP-reducing logic. If you already have this event, add this update to the existing logic.
3. Build a Task that clears the cue at the end
From BT_Enemy's "New Task", create BTT_EndCover with BTTask_BlueprintBase as the parent.
Add a variable FlagKey of type Blackboard Key Selector and turn on Instance Editable. That variable lets you choose "which Key to operate on" where the Task is placed.
Wire the white exec line Receive Execute AI → Set Blackboard Value as Bool → Finish Execute . Specify FlagKey for the Set's Key and false for Value, with Finish Execute's Success on.

Set BB Bool in the diagram is shorthand for Set Blackboard Value as Bool. That returns NeedsCover to false after hiding finishes. Finish Execute is the node telling the tree "this Task is done".
4. Put the hiding branch leftmost
Add a new Sequence "Hide" to BT_Enemy's top-level Selector. We want it prioritized over chasing and patrolling, so place it left of the existing branches.
Add a Blackboard Decorator to "Hide".
| Item | Setting |
|---|---|
| Blackboard Key | NeedsCover |
| Key Query | Is Set |
| Notify Observer | On Result Change |
| Observer Aborts | Lower Priority |
For a Bool, Is Set checks whether it is true here. Lower Priority means NeedsCover turning true interrupts chasing or patrolling running to the right and enters the hiding branch.
Place these three as "Hide"'s children, from the left.
- A Sequence "Move to cover"
- Wait: Wait Time 3.0, Random Deviation 0
- BTT_EndCover: FlagKey NeedsCover
Then place Run EQS Query and Move To as siblings, left to right under "Move to cover". It is not a structure with Move To hanging under Run EQS Query.

Run EQS Query uses these settings.
| Item | Setting |
|---|---|
| Query Template | EQ_HideSpot |
| Run Mode | Single Best Item |
| Blackboard Key | HideLocation |
| Update BBOn Fail | On, where it is displayed |
Single Best Item picks the highest-scoring remaining candidate. Set Move To's Blackboard Key to HideLocation too, with Acceptable Radius at 30 to start, Reach Test Includes Agent Radius and Goal Radius off, and Allow Partial Path off. Those settings get it near the chosen point.
Finally, add a Force Success Decorator to the inner Sequence "Move to cover".
If EQS finds no candidates, that Sequence fails and never reaches Move To. Force Success returns success to the outside, including when the move fails, so the following Wait and BTT_EndCover still run. It is not a judgment that hiding succeeded but a setting for proceeding to cleanup.

That avoids repeating the query with no interval when there are no candidates. Even with a stale HideLocation, the failing path does not proceed to Move To.
5. Deal damage with the N key
Instead of a gun, attack one enemy in the level with the N key to test.
- Select BP_Enemy in the level and open the Level Blueprint.
- Right-click the graph and create a reference to that placed enemy.
- Wire the N event's Pressed into Apply Damage .
- Specify the enemy reference for Damaged Actor and
1for Base Damage. The other inputs can stay at their defaults for this check.

Compile and save the Blueprints and save the Behavior Tree too. Play, click the game screen, and press N where the enemy and player can see each other. If N is used for something else, change this test event to a free key.
| What to try | Result to watch |
|---|---|
| Deal damage with N | NeedsCover becomes true and the hiding branch runs |
| Cover exists | HideLocation updates and the enemy moves there |
| It could move | It waits three seconds on arrival and returns to chasing or patrolling |
| Remove the walls so no candidates remain | It skips Move To, waits three seconds in place, and returns |
| Move the walls and try again | The next query picks a new hiding spot |
This example does not extend the wait when hit mid-hide. While NeedsCover is already true, it continues that single sequence.
Once real projectiles call Apply Damage, the same hit logic replaces the N key.
How to look when it does not work
First check "can candidates be chosen" with the Testing Pawn, then "is that result being used" in the Behavior Tree.
| Symptom | Where to check |
|---|---|
| No candidate points appear | Query Template, the Grid's range, projection to Navigation, the NavMesh, the Testing Pawn's position |
| Adding Trace leaves nothing | Whether the Context returns Actors, whether one player is placed, whether the walls Block Visibility |
| Fully exposed spots remain | Bool Match, the Trace height, whether the line hits unintended floors or props |
| Distant points get chosen | Whether Distance To is Querier and Scoring Factor is -1 |
| The Preview succeeds but the enemy cannot move | The Testing Pawn's and enemy's dimensions, Path Exist, the runtime NavMesh, Move To's result |
| Taking damage does not switch branches | Can Be Damaged, the runtime Blackboard's NeedsCover, branch order, Observer Aborts |
| It does not move after hiding | The Wait time, BTT_EndCover's FlagKey, the Finish Execute connection |
During play, AI Debugging's EQS display also traces candidate scores and the chosen point. By default the apostrophe key opens AI Debugging and numpad 3 toggles the EQS display. If your layout or settings differ, check the project's Gameplay Debugger settings.
Note also that the Testing Pawn's results are what it found from that Pawn's position . When comparing distance from the enemy, place the Testing Pawn near the enemy too.
Bonus: extending it to your own game
Change what "close" means
Our Distance is straight-line distance. A spot just past a wall may require a long way around to reach.
To prioritize "the shorter walking distance", score with Pathfinding's Path Length . Grasp the mechanism with straight-line distance first and compare when actual movement looks unnatural.
Change how candidates are made and the conditions
The Grid searches the surroundings as an area. Points: Circle lines candidates up at a fixed distance from a center. Making the player the center gives a foundation for finding positions that maintain distance.

Both let you set who the center is. It is not fixed that "Grid is always yourself and Circle always the player".
To make direction a condition, the Dot test is available. It compares how aligned two directions are, useful for designs choosing a target's front or back.
Reselect when it becomes necessary
Our hiding spot is the position chosen by the query at the moment of the hit. If the player circles around while the enemy runs, that spot can become visible.
To extend to an enemy that stays hidden, add a mechanism reselecting when spotted or at a fixed interval. Before adding finer candidates, think about when you need to check again .
Simply heading toward a target only needs a normal Move To. That Move To also uses NavMesh paths, so it does not mean "you cannot avoid walls without EQS". EQS is for when you want to choose the destination itself from several candidates.
Summary
In EQS you generate candidates, exclude by essential conditions, and score and choose among the rest. Here we made "not visible" and "walkable" Filters and "close" a Score.
Moving walls or the player changes what gets chosen. Confirm those changes through dot colors and numbers first, then connect it to the enemy's movement once the query convinces you.