Awareness System
Documentation Unreal Engine AI Awareness Perception
Per-AI perception memory: enemies notice, investigate, chase, and forget targets like a guard would.
Enemies fight only what they have sensed. They notice you over time, lose you when you break line of sight, and remember where you went.
Interactive Awareness States
Move the player through the cone and hearing ringSeen = Detected. Lose sight = Lost (grace), then Suspicious if still heard, then Unknown.
When to Use This
- Souls-like enemies that aggro on sight, not through walls
- Stealth and horror games where the player can break line of sight and slip away
- "Investigate the noise" behavior: the AI heard you but has not seen you
- A patrol, spot, chase, lose, search, return-to-post loop
- An on-screen awareness meter that fills as the enemy notices you
- Pack alerting: one enemy spots the player and warns nearby allies
Opt-in. Leave the config off and behavior is unchanged.
How It Works
The Awareness component lives on the AI controller and wraps Unreal's
UAIPerceptionComponent. Unreal's senses report raw stimuli; the Awareness layer turns those into a remembered, per-target state and fires events you can bind to.The Five States
Each sensed target holds one state, ordered from least to most aware:
| State | Meaning |
|---|---|
| Unknown | Never sensed (or fully forgotten). No memory. |
| Forgotten | Grace expired. Fires once, then the entry drops. |
| Suspicious | Heard or half-glimpsed it. Knows something is there, not locked on. |
| Lost | Saw it, then lost it. Remembers the last spot and searches the grace window. |
| Detected | Sensed with confidence. Engaged. |
Detection fills over time
Sight does not jump to Detected. Each target carries a
0..1 perception meter that fills while the AI sees it:- Fill rate scales with distance and angle. A centred, close target fills fast; one at the cone edge and far away trickles up. Shape this with
DistanceRateCurveandAngleRateCurve(flat by default). - Cross
SuspicionThresholdand the target becomes Suspicious, so the AI investigates. - Reach
1.0and the target becomes Detected, so the AI engages. - Hearing raises the meter to at least
SuspicionThreshold(orHearingBumpif higher), so sound reaches Suspicious but not Detected. - Damage reveals the attacker at once (straight to Detected).
Prefer the old instant-on-sight behavior? SetbGradualEscalation = false.
Losing a target
- Brief sight breaks count for nothing. A Detected target drops to Lost only after
ConfirmLostDelayseconds of unbroken no-sight, so the cone exits of normal strafing leave the state alone. - Point-blank targets stay seen. Anything within
ProximityRadiusholds Detected regardless of line of sight, so an enemy keeps a target standing against it even as its attack swings the body away. - Lost is a search window. The AI remembers the spot for
GraceLossDuration, then forgets and disengages. The clock starts when Lost begins, so a noisy target cannot reset it. - Re-acquiring is instant. See the target again during grace and it snaps back to Detected.
The component also records each target's last-known location and velocity, which drives "search where I last saw you" behavior.
The mental model
A meter fills while the AI sees a target (Suspicious, then Detected). A short hysteresis keeps flicker from demoting it, a proximity floor pins close targets, and a grace clock ages Lost to Forgotten. Every state is a threshold on that one meter.
Quick Setup
"Only fight what I have sensed" takes two steps. Both are required.
Step 1: Give the enemy senses
Create a
USECAwarenessConfig data asset (Right-click → Miscellaneous → Data Asset → SECAwarenessConfig), set the sight and hearing ranges, and assign it to your enemy's UEnemyAIConfig → AwarenessConfig.Step 2: Gate target selection (required)
Set
UEnemyAIConfig → Target Selector to an Awareness Filtered Target Selector. This step makes the AI ignore targets it has not sensed.Skip Step 2 and the enemy senses targets but still engages everyone. A config on its own records awareness; the filtered selector acts on it. The plugin logs a warning on possession if you set a config without the selector.
The selector's
MinRequiredState sets how the AI behaves when it loses sight:MinRequiredState | Feel |
|---|---|
| Detected | Disengage and investigate. The AI breaks off the moment it loses sight and your Blueprint runs the search. Recommended for stealth/patrol enemies. |
| Lost (default) | Keep fighting. The AI chases the live target through the grace window, then gives up at Forgotten. |
| Suspicious | Also engages investigate-by-sound targets directly. |
See Targeting System for the full selector picture.
Two ways to provide perception
Let the config build it (default). With
bAutoCreatePerceptionComponent on, the component builds a UAIPerceptionComponent from the config's sense settings.Bring your own. Add a
UAIPerceptionComponent to your controller Blueprint, configure the senses there, and set bAutoCreatePerceptionComponent to false so the component binds to yours. In this mode only the memory and meter fields apply; the sense fields are ignored.Team setup matters. Unreal's senses detect across teams only. Give the player a team id different from the enemy (
AEnemyControllerBase defaults enemies to team 1). When the player shares the enemy's team, sight reports nothing and awareness looks broken, though the cause is the team config. To exclude a single actor (like a debug fly-cam), see Extension Points.Tuning
All fields live on the
USECAwarenessConfig data asset.Senses
| Property | Default | Purpose |
|---|---|---|
bAutoCreatePerceptionComponent | true | Build a perception component from this config if the controller has none |
SightRadius | 1500 | How far the AI can see (cm) |
LoseSightRadius | 1800 | Distance at which an already-seen target is lost (cm) |
PeripheralVisionHalfAngle | 90 | Half-angle of the sight cone (90 = full 180°) |
HearingRange | 1200 | How far the AI can hear (cm) |
bEnableDamageSense | true | A hit from behind reveals the attacker |
Gradual meter
| Property | Default | Purpose |
|---|---|---|
bGradualEscalation | true | Fill the meter over time; false = instant Detected on sight (legacy) |
EscalationRate | 0.9 | Meter units per second at best range and angle (~1.1 s to detect) |
SuspicionThreshold | 0.2 | Meter at or above this reports Suspicious; 1.0 reports Detected |
DistanceRateCurve | (none) | Multiplier on fill rate by distance (X = dist / SightRadius). Flat 1.0 if unset |
AngleRateCurve | (none) | Multiplier on fill rate by angle off-centre (X = angle / half-angle). Flat 1.0 if unset |
HearingBump | 0.45 | Meter value a hearing stimulus jumps to (capped under 1.0) |
Proximity and loss
| Property | Default | Purpose |
|---|---|---|
ProximityRadius | 220 | Targets within this radius stay Detected regardless of sight (cm). 0 disables |
ConfirmLostDelay | 0.5 | Continuous seconds of no-sight before Detected drops to Lost |
GraceLossDuration | 5.0 | Seconds a target stays Lost (searchable) before Forgotten |
SuspiciousDecayDuration | 8.0 | Seconds a Suspicious target lingers before Forgotten |
EvaluationInterval | 0.1 | How often the meter and decay tick runs (s) |
Memory, mapping, filtering
| Property | Default | Purpose |
|---|---|---|
bTrackLastKnownLocation | true | Record LastKnownLocation / LastKnownVelocity per target |
StimulusToStateMap | (empty) | Remap a sense class to a state (e.g. hearing → Detected for an alert archetype) |
IgnoredActorClasses | (empty) | Classes the AI never perceives. See Extension Points |
The Building Blocks for Behavior
Events, queries, two StateTree nodes, and a facing toggle. You compose behavior from these in Blueprint; the plugin ships no hard-coded patrol or investigate logic.
Events
| Event | Params | When |
|---|---|---|
OnTargetSuspicious | Target, StimulusLocation | A target first reaches Suspicious, the investigate entry point. Carries where to look. |
OnTargetSpotted | Target | A target first reaches Detected. |
OnTargetLost | Target | A Detected target drops to Lost (search window starts). |
OnTargetForgotten | Target | A target ages out; the entry drops right after. |
OnAwarenessProgress | Target, Progress01 | The meter crosses a quarter step (0.25 / 0.5 / 0.75 / 1.0). Use for UI or stingers. |
OnAlertLevelChanged | HighestState | The highest state across all targets changes. |
OnTargetStateChanged | Target, Old, New | Any state change (catch-all). |
Queries
ESECAwarenessState GetAwarenessState(AActor* Target) const; // this target's state
float GetAwarenessProgress(AActor* Target) const; // 0..1, drive a UI bar
AActor* GetMostAwareTarget(ESECAwarenessState& OutState) const; // best target to react to
bool GetLastKnownLocation(AActor* Target, FVector& OutLocation, float& OutAgeSeconds) const;
void GetTargetsInState(ESECAwarenessState MinState, TArray<AActor*>& OutTargets) const;
ESECAwarenessState GetHighestAwarenessState() const;
FSECAwarenessEntry GetAwarenessEntry(AActor* Target) const; // full entry: state, last-known, timesGetMostAwareTargetlets a patrol or investigate Blueprint pick something to react to without running combat target selection.
StateTree nodes
- Awareness State At Least (condition) passes when a target's state reaches a minimum. Gate Patrol, Investigate, Combat, and Search states with it. Leave Target empty to test the most-aware target.
- Poll Last Known Location (task) outputs
LastKnownLocation,AgeSeconds,bValid, andResolvedTargeteach tick. BindLastKnownLocationinto an AI Move To to walk the AI to where it last saw the target.
Full node reference on the StateTree Integration page.
Facing
AEnemyControllerBase tracks the live target only while it is Detected. Once a target is Suspicious or Lost, the controller faces the last-known location, so a searching enemy looks where it last saw you rather than through a wall. With no awareness config, the controller keeps default focus tracking, so existing non-stealth enemies are unaffected.- Toggle with
bFaceLastKnownWhenNotDetected(on by default). - Override
GetDesiredFacingLocation(aBlueprintNativeEvent) for custom facing: return a world location to face, or false to keep the default.
Recipes: Building Behaviors
The pieces compose into behavior. The ladder runs from one node to the full loop.
Recipe 1: Go home when forgotten
The smallest useful behavior, and what the showcase controller does:
Event OnTargetForgotten
-> AI Move To (HomeLocation) // HomeLocation captured at BeginPlay
That is the whole "give up and walk back to post" behavior. No StateTree changes.
Recipe 2: Investigate a noise
Event OnTargetSuspicious(Target, StimulusLocation)
-> AI Move To (StimulusLocation) // facing follows movement
-> on arrive: play a look-around
Hearing only reaches Suspicious, so the AI walks over to check instead of attacking. See you there and the meter fills to Detected; otherwise the Suspicious entry decays and
OnTargetForgotten sends it home (Recipe 1).Recipe 3: The full patrol, search, return loop
Drive it from the StateTree with the Awareness State At Least condition:
| State | Enter when | Does |
|---|---|---|
| Patrol | most-aware target < Suspicious | follow a spline (stock AI Move To) |
| Investigate | most-aware target >= Suspicious and < Detected | move to the stimulus / last-known, look around |
| Combat | a target is Detected | your existing SEC combat sub-tree |
| Search | was Detected, now Lost | Poll Last Known Location → AI Move To, wait out the grace window |
| Return | OnTargetForgotten fires | AI Move To home, then back to Patrol |
Combat movement (the Movement Evaluator) runs only inside the Combat state. Patrol, Investigate, Search, and Return use stock navigation, so they stay out of the combat layer. For the disengage feel, set the selector's
MinRequiredState = Detected (Quick Setup).Recipe 4: An awareness meter UI
Tick (or bind OnAwarenessProgress)
-> GetAwarenessProgress(Target) -> set HUD bar fill (0..1)
GetAwarenessProgress returns the rising meter while Suspicious, 1.0 while Detected, and the draining grace fraction while Lost, so one bar reads as noticing, spotted, losing you.Recipe 5: Pack alerting
Wire
OnTargetSpotted → BroadcastAwarenessToAllies(Radius) so one enemy spotting you grants nearby same-team allies a Detected entry on the player. For a softer "they heard something" alert, call ForceAwareOf(Target, Suspicious) on the allies yourself.Extension Points
| Hook | Type | Use it to |
|---|---|---|
ShouldIgnoreActor(Actor) | BlueprintNativeEvent | Drop all stimuli from an actor. The default ignores anything in IgnoredActorClasses; add DefaultPawn or spectator classes there. Override for tag- or team-based rules. |
ResolveStimulusState(Sense, Source) | BlueprintNativeEvent | Remap a non-sight stimulus (hearing/damage) to a state, e.g. ignore hearing while the target carries a "Sneaking" tag. |
GetDesiredFacingLocation(OutLoc) | BlueprintNativeEvent | Custom facing while not Detected (see above). |
InnerSelector | Property | Run your own selector on the awareness-filtered list (default: nearest). |
bGradualEscalation = false | Property | Revert to instant Detected-on-sight. |
Ignore the showcase fly-cam
When a stray Unreal DefaultPawn or debug fly-cam keeps getting noticed, add its class to IgnoredActorClasses. Sight skips ResolveStimulusState after the meter change, so the ignore list (or a ShouldIgnoreActor override) is how you filter actors out of perception.
Debug
Awareness runs server-side. To watch it during play:
- Bind
OnTargetStateChangedto a print, or readGetAwarenessState/GetHighestAwarenessStateon tick. - Read
GetAwarenessProgressto see the meter fill in real time, or bindOnAwarenessProgress. - Check the chain: bind
OnTargetSpottedand walk into the cone. It fires when you enter and stays quiet when you stand behind the enemy.
Integration Points
| System | How Awareness Connects |
|---|---|
| Targeting System | The Awareness Filtered Target Selector gates which targets reach selection; MinRequiredState sets the disengage feel |
| StateTree Integration | The Awareness State At Least condition and Poll Last Known Location task branch the brain on awareness |
| Combat Roles | Only sensed targets feed role assignment, since the selector filters first |
| Threat Detection | Threat tracks the player's attention; Awareness tracks what the AI has perceived. Use both for "knows you are there and knows you are watching" |