Skip to content
Enemy AI and EQS
Type a keyword to search

Enemy AI and EQS

Behavior Tree based modular AI architecture, perception system, Blackboard-driven decision making, and EQS environment queries

Updated2026-07-15·~16 min read

This chapter explains the three-layer decoupled architecture of the enemy AI system, covering perception, logic, and presentation. It then uses melee enemies as a complete case study, tracing the full flow from perception trigger to Behavior Tree decision-making and attack execution.

6.1 Enemy AI Architecture: Modular Decoupling Between Controller and Base Class

Section titled “6.1 Enemy AI Architecture: Modular Decoupling Between Controller and Base Class”

When building a dynamic and extensible AI system, separating logic from presentation is central to production-oriented development. This project uses Unreal Engine’s classic Controller - Pawn/Character architecture: the Controller owns decision-making, while the Pawn/Character carries state and executes presentation, decoupling enemy AI logic.

AI system folder structure overview

LayerAssetResponsibility
Core base classesBP_Enemy_Base / AIC_Enemy_BaseBaseline enemy framework
Logic layerBT_Enemy_Melee + 3 subtrees (Frozen / Investigating / Passive)Hierarchical decision management
Utility layerTasks (BTT) · Decorators (BTD) · EQSReusable Behavior Tree sub-behavior blocks

Overall architecture: decoupled perception / logic / presentation layers

LayerCarrierResponsibility
Perception layerAIC_Enemy_BaseMounts AI Perception for sight, hearing, and damage; starts the Behavior Tree; initializes the Blackboard
Logic layerBehavior Tree & BlackboardBlackboard stores memory such as AttackTarget and State; Behavior Tree decides behavior based on state variables
Presentation layerBP_Enemy_BaseStores attributes and resources, implements the BPI_EnemyAI interface, and executes action commands

6.2 Melee Enemy Example: Full AI Flow Implementation

Section titled “6.2 Melee Enemy Example: Full AI Flow Implementation”

Complete enemy AI data flow: perception stimulus → AIC_Enemy_Base (Perception) → update Blackboard (AttackTarget / State) → BT_Enemy_Melee (decision) → BTT/BTD (execution) → BP_Enemy_Melee (presentation)

6.2.1 Assets and Presentation Layer: Enemy Pawn Class and Resource Carrier (BP_Enemy_Base / Melee)

Section titled “6.2.1 Assets and Presentation Layer: Enemy Pawn Class and Resource Carrier (BP_Enemy_Base / Melee)”

In the decoupled AI architecture, the Pawn class, or character Blueprint, is the execution carrier for the AI. It does not make decisions. Instead, it acts as the carrier for resources and attributes, executes commands from the logic layer, and stores the resources and logic needed for presentation.

BP_Enemy_Base establishes the foundation for all enemies. It defines what an enemy is and which baseline shared capabilities enemies should have:

BP_Enemy_Base Components panel screenshot

  • Core components: GAS core, ensuring enemies share the same combat logic foundation as the player and use the same Attribute Set DataTable; UI and feedback, with WB_EnemyHealthBar presenting health in real time; and ComboGraphCollision for attack collision validation during combat.
  • Interfaces: implements the BPI_EnemyAI Blueprint Interface, declaring to the AI Controller that it can receive commands such as equipping weapons, setting movement speed, and activating ComboGraph. This enables low-coupling interface communication.
  • Variable configuration: reserves variables for PatrolRoute, referencing BP_PatrolRoute, and BehaviorTree, referencing the Behavior Tree asset. This allows each enemy instance placed in the level editor to configure its own patrol route and behavior logic.

BP_Enemy_Melee, as a child class of BP_Enemy_Base, is responsible for filling in melee-enemy-specific assets and visual presentation logic:

BP_Enemy_Melee initialization Blueprint logic

  • Initialization flow: in BeginPlay, it performs weapon attachment, binding BP_EnemyWeapon_DualSword to the hand Socket; sets up ComboGraphCollision; creates the health bar Widget; and calculates gameplay drop probabilities.
  • Visual presentation layer: adds a dynamic dissolve death effect, driven by a dynamic material instance DynamicEnemyDissolveMat; and random material selection on spawn through SetSwordMaterial, selecting from a preset material array. This adds low-cost visual variety and enriches presentation.

Enemy visual variation comparison

  • Combat state management: declares combat-state variables, including whether the enemy has entered combat for one-shot logic such as drawing weapons, and a special logic switch for Boss behavior.

6.2.2 Perception Layer: Perception-Driven External Information Acquisition (AIC_Enemy_Base)

Section titled “6.2.2 Perception Layer: Perception-Driven External Information Acquisition (AIC_Enemy_Base)”

AIC_Enemy_Base is the controller base class for all enemy AI. As the decision entry point of the AI system, it has two core responsibilities: environment perception and behavior startup.

AI Perception Component configuration:

AI Perception Component configuration panel in AIC_Enemy_Base

The controller mounts an AI Perception Component and configures three sense types to cover different combat scenarios:

  • AI Sight: detects players within the field of view. It configures perception radius, field-of-view angle, and memory duration after line of sight is lost. This is the main trigger for enemies to transition from Passive to Attacking.
  • AI Hearing: detects sound stimuli generated by the player, such as attack sounds or footsteps. If the enemy has not seen the player but hears a sound, it enters Investigating and moves toward the sound source.
  • AI Damage: detects damage events from the player. Even if the enemy is facing away, taking damage immediately reveals the threat source and switches the enemy into combat, ensuring that a sneak attack does not leave the enemy unresponsive.

Perception event handling — On Target Perception Updated:

When any perception channel detects a stimulus source, the system triggers the On Target Perception Updated callback. The callback performs the following logic:

On Target Perception Updated event callback Blueprint

  1. Sense type classification: uses the E_AISenses enum, including None, Sight, and Damage, to identify the trigger source and determine the subsequent state-transition strategy.

  2. Blackboard variable update: writes the perceived target Actor into the Blackboard variable AttackTarget, and updates PointOfInterest, the movement target for Investigating, based on the sense type.

  3. AI state transition: updates the E_AIStates state variable in the Blackboard according to the sense type:

    • Sight: sets the state directly to Attacking, causing the enemy to enter combat immediately.
    • Damage: sets the state to Attacking and assigns the damage source as AttackTarget.
    • Hearing: sets the state to Investigating, causing the enemy to move toward the sound source.
    • Perception lost (Unregister): when the target leaves perception range, the system decides based on context whether to enter Investigating, moving toward the last known location, or return to Passive.

Behavior Tree startup and Blackboard initialization:

In the On Possess event of AIC_Enemy_Base, which is the moment when the Controller takes over the Pawn, the following initialization flow runs:

  1. Reads the preconfigured BehaviorTree asset reference from BP_Enemy_Base, then calls Run Behavior Tree to start the Behavior Tree.
  2. Initializes key variables in BB_Enemy_Base, including State, initially Passive; AttackTarget, initially empty; DefendRadius, the ideal attack distance; and PatrolRoute, read from the Pawn’s configured patrol-route reference.

6.2.3 Decision Layer: Decision Hub and Runtime Memory (BT_Enemy_Melee & BB_Enemy_Base)

Section titled “6.2.3 Decision Layer: Decision Hub and Runtime Memory (BT_Enemy_Melee & BB_Enemy_Base)”

Blackboard BB_Enemy_Base — memory and shared data:

The Blackboard is the Behavior Tree’s short-term memory. It stores all key data the AI needs to read and write at runtime. Core Blackboard variables in this project include:

VariableTypePurpose
StateE_AIStates (Enum)Current AI state, driving top-level Behavior Tree branch selection
AttackTargetObject (Actor)Current locked attack target, usually the player
PointOfInterestVectorPoint of interest, used for investigation targets or EQS query results
DefendRadiusFloatIdeal attack distance, used to determine whether the enemy should approach the target
PatrolRouteObjectPatrol route reference linked to BP_PatrolRoute

E_AIStates enum: defines five enemy behavior states: Passive for patrol, Attacking for combat, BeingHit for hit stun, Investigating for searching, and Dead for death. This enum is the foundation of branch selection across the entire Behavior Tree.

BB_Enemy_Base Blackboard variable definition

Behavior Tree BT_Enemy_Melee — decision trunk:

BT_Enemy_Melee uses a classic priority architecture with a top-level Selector node. From left to right, or high to low priority, it is divided into four core branches. Each branch uses a Blackboard Decorator to check the value of the State variable and decide whether it should activate:

Root (Selector)
├── [1] BeingHit State ← State == BeingHit → SubTree_Frozen
├── [2] Combat State ← State == Attacking → combat logic sequence
├── [3] Investigating State ← State == Investigating → SubTree_Investigating
└── [4] Passive State ← State == Passive → SubTree_Passive

This priority design ensures that hit reaction has the highest response priority and interrupts all behavior. Combat logic comes next, investigation after that, and patrol is the lowest-priority default behavior.

BT_Enemy_Melee Behavior Tree overview

When the enemy is hit, GAS grants the Event.Character.BeingHit.Melee Tag through GE_HitReaction_Melee. The perception layer switches State to BeingHit, and the Behavior Tree immediately enters this branch.

SubTree_Frozen internal flow:

StepTaskPurpose
1BTT_RotateToPlayerForces the enemy to face the player at the hit moment, ensuring consistent hit direction.
2BTT_ClearFocusClears Focus to avoid unnatural head tracking during stun.
3BTT_SetMovementSpeed(Idle)Sets movement speed to 0 to prevent sliding during hit stun.
4WaitWaits for hit-stun recovery, matching the hit reaction animation duration.

After the wait finishes, State is set back to Attacking, forming the full loop: hit → stun → combat recovery.

SubTree_Frozen behavior subtree

This is the most complex branch in the entire Behavior Tree and is divided into three sub-stages:

Combat State branch detailed structure

Stage A — equipment check: BTD_IsEnemyHasSwords checks whether weapons are equipped. If not, BTT_FocusTargetBTT_EquipWeapon runs, drawing the weapons. This is triggered only the first time the enemy enters combat.

Stage B — attack execution (Sequence):

StepTaskPurpose
1BTT_SetMovementSpeed(Run)Runs toward the target.
2BTT_ClearFocusTemporarily clears Focus to avoid unnatural locked movement while running.
3BTT_MoveToIdealRangeMoves to the ideal attack distance defined by DefendRadius.
4BTT_FocusTargetLocks onto the player again.
5BTT_ActiveComboGraphActivates CG_Enemy_Combo through the BPI_EnemyAI interface.

CG_Enemy_Combo combo asset

Stage C — tactical movement (Strafe Selector):

ConditionBehavior
Outside ideal rangeClearFocus → SetSpeed(Run) → MoveToIdealRange, approaching again
Within ideal rangeFocusTarget → SetSpeed(Walk) → EQS_Strafe query → Move to PointOfInterest, strafing around the player

The enemy enters this state when AI Hearing detects a sound but the enemy has not seen the player.

  1. Move to PointOfInterest — moves to the world-space sound source.
  2. Wait — waits in place after arrival, simulating searching and looking around.
  3. BTT_SetStateAsPassive — if no new perception event occurs, sets State back to Passive and resumes patrol.

SubTree_Investigating behavior subtree

This is the enemy’s default idle behavior.

The BTD_HasPatrolRoute Decorator checks whether PatrolRoute is valid:

ResultBehavior
Patrol route existsBTT_MoveAlongPatrolRoute — loops along the Spline path in BP_PatrolRoute
No patrol routeIdles in place, acting as a stationary guard

BP_PatrolRoute defines a path by placing Spline points in the level and supports binding different routes to different enemies.

SubTree_Passive behavior subtree and patrol route

SubTree_Passive runtime debug screenshot showing the Passive branch active and the enemy moving along its patrol route

6.2.4 Execution Layer: Task Nodes and Condition Checks (BTT & BTD)

Section titled “6.2.4 Execution Layer: Task Nodes and Condition Checks (BTT & BTD)”

The leaf nodes of the Behavior Tree consist of custom BTTasks and BTDecorators. They are the atomic operations of the AI system. Each node does one thing, and complex behavior is built by composing them.

Custom BTTask list:

Task NodeResponsibilityKey Implementation
BTT_FocusTargetLocks focus targetCalls the AI Controller’s Set Focus so the enemy keeps facing AttackTarget.
BTT_ClearFocusClears focus lockCalls Clear Focus to release forced head/body tracking.
BTT_SetMovementSpeedSets movement speedSets E_MovementSpeed (Idle / Walk / Run) through the BPI_EnemyAI interface.
BTT_MoveToIdealRangeMoves to ideal rangeUses Move To to approach AttackTarget and completes when reaching DefendRadius.
BTT_EquipWeaponEquips weaponsTriggers the weapon-draw montage through BPI_EnemyAI and switches weapons from the back Socket to the hand Socket.
BTT_RotateToPlayerRotates toward playerForcibly rotates the Pawn toward AttackTarget for directional correction at the hit moment.
BTT_ActiveComboGraphActivates attack comboActivates CG_Enemy_Combo through BPI_EnemyAI, executing attack animation and GAS damage logic.
BTT_MoveAlongPatrolRoutePatrols along routeReads route points from PatrolRoute, moves through them in sequence, and loops.
BTT_SetStateAsPassiveResets to passive stateSets Blackboard State to Passive, used for returning to patrol after investigation timeout.
BTT_DefaultAttackDefault attack fallbackSimplified attack logic used as a fallback when ComboGraph is unavailable.

Custom BTDecorator list:

Decorator NodeResponsibilityEvaluation Logic
BTD_HasPatrolRouteWhether a patrol route existsChecks whether the Blackboard PatrolRoute variable is valid, meaning non-null.
BTD_IsEnemyHasSwordsWhether weapons are equippedQueries the enemy’s weapon attachment state through BPI_EnemyAI.
BTD_IsWithinIdealRangeWhether inside ideal attack rangeCalculates the distance between the enemy and AttackTarget, then compares it with Blackboard DefendRadius.

BPI_EnemyAI Blueprint Interface definition showing functions such as SetMovementSpeed / EquipWeapon / ActiveComboGraph

Example internal BTT logic: BTT_EquipWeapon calling Pawn functions through BPI_EnemyAI

6.3 Spatial Intelligence: Principles and Practice of Environment Query System (EQS)

Section titled “6.3 Spatial Intelligence: Principles and Practice of Environment Query System (EQS)”

The Environment Query System (EQS) is a spatial reasoning tool provided by Unreal Engine. It allows AI to generate a set of candidate locations in the world, score and sort them through configurable Tests, and finally select the optimal location for the Behavior Tree to use.

In this project, EQS is mainly used to solve tactical movement for enemies. After an attack, the enemy needs to choose a reasonable position for strafing or repositioning instead of standing still and waiting for the next attack.

Query context — EQS_Context_AttackTarget:

Before executing an EQS query, a reference point for the query must be defined. EQS_Context_AttackTarget is a custom EQS Context. It reads the AttackTarget variable, namely the player, from the Behavior Tree’s Blackboard and uses the player’s world coordinates as the generator’s center reference point.

Generator — Points: Circle:

EQS_Strafe uses the Points: Circle generator. Centered on EQS_Context_AttackTarget, the player position, it uniformly generates 5 candidate locations on a circle with radius 400. These points represent possible tactical movement destinations for the enemy.

The reason for choosing a circular generator rather than a grid generator is that melee tactical movement is essentially arc movement around the player. Circular points naturally fit this motion pattern, and only five points are enough to cover the main directions around the player while keeping query cost very low.

EQS_Strafe query asset editor showing Generator: Points: Circle, Center=player, Radius=400, Points=5; Tests: Distance + PathExist

Test configuration:

After the generator produces candidate points, the following two Tests score and filter them:

  1. Distance Test: evaluates the distance between each candidate point and the Querier, namely the enemy itself. The filter range is configured as 150 ~ 500. Points that are too close (< 150) or too far (> 500) are discarded directly. This ensures the enemy does not move too close to the player, where it would be easily covered by combos, or too far away, which would break combat pacing.

  2. Path Exists Test: performs navigation path validation from the Querier to the candidate point. All points unreachable through NavMesh, such as positions blocked by walls or obstacles, are discarded. This is a hard filter condition that prevents the enemy from trying to move to physically unreachable locations and getting stuck on obstacles.

Using the query result:

The best location returned by the EQS query is written into the Blackboard variable PointOfInterest. Then the Strafe branch inside the Combat State of the Behavior Tree executes Move to PointOfInterest, driving the enemy to move to that point. The full flow forms a tactical loop: attack → EQS query for optimal strafe point → move to strafe point → re-evaluate distance → attack again.

EQS runtime debug visualization showing candidate points as colored spheres, with blue indicating selectable points and each point labeled with distance score to the enemy

PIE runtime enemy tactical movement result showing the enemy strafing around the player based on EQS query results after attacking

6.3.3 Design Considerations for EQS in This Project

Section titled “6.3.3 Design Considerations for EQS in This Project”

Why not move randomly?

Simple random movement creates two problems: the enemy may move behind a wall or into an unreachable area and get stuck, or it may move too far from the player and break combat rhythm. With the combined constraints of Distance Test and Path Exists Test, EQS ensures that tactical movement points remain within a reasonable combat range and are physically reachable.

Why use only 5 points?

EQS queries have performance cost. The more candidate points there are, the higher the per-query test cost. For melee enemy strafing, five evenly spaced circular points are sufficient to cover the front, back, left, right, and rear-side directions around the player. This keeps query cost low while preserving tactical variety.

Future extensions:

  • Dot Product Test (direction preference): add a dot product test against the enemy facing direction, making enemies prefer side or rear positions and simulating flanking behavior.
  • Multi-enemy coordination: when multiple enemies exist in the scene, add a Distance to Other Queriers test so enemies keep distance from one another, avoid clustering at the same position, and establish basic group-AI spacing.