A comprehensive guide to creating intelligent, dynamic, and environment-aware AI agents.
By the end of this lesson, you will be able to:
We'll be working with three key components that work together:
Start with the Third Person template. This gives us a playable character and a simple environment to work in.
Duplicate the BP_ThirdPersonCharacter and rename it to BP_AI_Character. Place one in the level.
EQS is a plugin! Go to Edit > Plugins, search for "Environment Query System" and enable it. Restart the editor.
In the Content Browser, create a new folder called "AI". Inside, create the following assets:
AIC_Enemy.BT_Enemy.BB_Enemy.Step 1: Open BP_AI_Character, select the top-level component (Self), and in the Details panel, set AI Controller Class to your AIC_Enemy.
Step 2: Open AIC_Enemy. In its Event Graph, on Event On Possess, add the nodes: Run Behavior Tree. Select your BT_Enemy as the asset.
Open BB_Enemy. This is where we define our AI's memory. Let's add two keys:
TargetActor. In its details, set the Base Class to "Actor".TargetLocation.Open BT_Enemy. Make sure its Blackboard Asset is set to BB_Enemy in the Details panel.
BTs flow from the Root, down and left-to-right.
Drag from the Root and add a Selector node. A Selector tries each child from left to right and stops as soon as one succeeds. This is perfect for "either-or" logic (e.g., "Attack Player OR Patrol").
Drag from the Selector (on the right side) and add a Sequence node. A Sequence executes all its children from left to right and fails if any one of them fails. This is for step-by-step actions.
From the Sequence, add the following built-in tasks:
Move To. In its Details, set the Blackboard Key to our TargetLocation.Wait. Set duration to 2 seconds.Instead of creating custom Blueprint tasks or services for every spatial query, we will use Unreal's built-in, powerful **Environment Query System (EQS)**. This is the modern, data-driven way to have AI perceive and understand the world.
An EQS Query consists of:
First, we'll replace the custom `BTT_FindPatrolLocation` task with a reusable EQS query.
In your "AI" folder, right-click and choose Artificial Intelligence > Environment Query. Name it EQS_FindRandomPatrolPoint.
Open the new query. The root node is the Generator. Choose Points: On Circle. This will generate test points in a ring around the AI (the "Querier"). Set the Circle Radius to 1500 and Points on Circle to 16.
Right-click the Generator and add a Pathfinding test. This is crucial. It will automatically filter out any points the AI cannot navigate to, preventing it from getting stuck.
Use the EQS Testing Pawn in the editor toolbar to preview your query in the level. You should see a ring of green spheres representing valid patrol points.
Next, we'll replace the simple Sphere Overlap service with a more robust EQS query for finding the player.
Create another EQS asset and name it EQS_FindPlayer.
This time, for the Generator, choose Actors Of Class. This generator finds actors directly instead of points.
BP_ThirdPersonCharacter).Add two tests to the generator:
Now that we have our "senses" (EQS Queries), we can build our AI's "brain" (Behavior Tree) to use them. This approach is much cleaner and more powerful.
A Service is still the perfect tool to periodically run our perception query.
Open BT_Enemy. Right-click the main Selector node, choose Add Service > New Service, and name it BTS_CheckForPlayer.
In BTS_CheckForPlayer, override Receive Tick AI. Instead of doing overlaps, we will run our EQS query.
With our perception service running, the Behavior Tree can now react to the `TargetActor` key.
To the main `Selector`, add a `Sequence` node on the left. This will be our highest-priority behavior.
Blackboard decorator. Set it to observe `TargetActor` and check if it "Is Set". This branch will only run if the AI has a target.Move To task. In its details, set the `Blackboard Key` to `TargetActor`. The AI will now move directly towards the player it has found.Wait task (e.g., 1 second) to simulate an "attack" cooldown.To the main `Selector`, add another `Sequence` node to the right of the first one. This is the fallback behavior.
Run EQS Query task.
EQS_FindRandomPatrolPoint.TargetLocation. This task will run our query and store the best point in the Blackboard.Move To task that reads from the TargetLocation key.Wait task (e.g., 3 seconds) before finding a new patrol point.Now, let's combine everything and add the "Find Cover" logic for a more intelligent AI.
Create a new EQS query named EQS_FindCover:. This will find a point that is hidden from the player.
Points: On Circle:. Radius ~2000.BB_Enemy:, create a new key named PlayerActor_EQSContext: of type Actor. In the BTS_CheckForPlayer: service, set this key at the same time you set TargetActor:.Filter Only: and enable Invert. This will discard any points that CAN see the player.PlayerActor_EQSContext: higher. We don't want to hide right next to the player or too far away.We will now restructure our tree for the final, more intelligent logic: "If I see a player, run for cover. If I don't see a player, patrol."