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 ring
Seen = 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:
StateMeaning
UnknownNever sensed (or fully forgotten). No memory.
ForgottenGrace expired. Fires once, then the entry drops.
SuspiciousHeard or half-glimpsed it. Knows something is there, not locked on.
LostSaw it, then lost it. Remembers the last spot and searches the grace window.
DetectedSensed 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 DistanceRateCurve and AngleRateCurve (flat by default).
  • Cross SuspicionThreshold and the target becomes Suspicious, so the AI investigates.
  • Reach 1.0 and the target becomes Detected, so the AI engages.
  • Hearing raises the meter to at least SuspicionThreshold (or HearingBump if higher), so sound reaches Suspicious but not Detected.
  • Damage reveals the attacker at once (straight to Detected).
Prefer the old instant-on-sight behavior? Set bGradualEscalation = false.

Losing a target

  • Brief sight breaks count for nothing. A Detected target drops to Lost only after ConfirmLostDelay seconds of unbroken no-sight, so the cone exits of normal strafing leave the state alone.
  • Point-blank targets stay seen. Anything within ProximityRadius holds 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 UEnemyAIConfigAwarenessConfig.

Step 2: Gate target selection (required)

Set UEnemyAIConfigTarget 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:
MinRequiredStateFeel
DetectedDisengage 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.
SuspiciousAlso 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
PropertyDefaultPurpose
bAutoCreatePerceptionComponenttrueBuild a perception component from this config if the controller has none
SightRadius1500How far the AI can see (cm)
LoseSightRadius1800Distance at which an already-seen target is lost (cm)
PeripheralVisionHalfAngle90Half-angle of the sight cone (90 = full 180°)
HearingRange1200How far the AI can hear (cm)
bEnableDamageSensetrueA hit from behind reveals the attacker
Gradual meter
PropertyDefaultPurpose
bGradualEscalationtrueFill the meter over time; false = instant Detected on sight (legacy)
EscalationRate0.9Meter units per second at best range and angle (~1.1 s to detect)
SuspicionThreshold0.2Meter 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
HearingBump0.45Meter value a hearing stimulus jumps to (capped under 1.0)
Proximity and loss
PropertyDefaultPurpose
ProximityRadius220Targets within this radius stay Detected regardless of sight (cm). 0 disables
ConfirmLostDelay0.5Continuous seconds of no-sight before Detected drops to Lost
GraceLossDuration5.0Seconds a target stays Lost (searchable) before Forgotten
SuspiciousDecayDuration8.0Seconds a Suspicious target lingers before Forgotten
EvaluationInterval0.1How often the meter and decay tick runs (s)
Memory, mapping, filtering
PropertyDefaultPurpose
bTrackLastKnownLocationtrueRecord 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

EventParamsWhen
OnTargetSuspiciousTarget, StimulusLocationA target first reaches Suspicious, the investigate entry point. Carries where to look.
OnTargetSpottedTargetA target first reaches Detected.
OnTargetLostTargetA Detected target drops to Lost (search window starts).
OnTargetForgottenTargetA target ages out; the entry drops right after.
OnAwarenessProgressTarget, Progress01The meter crosses a quarter step (0.25 / 0.5 / 0.75 / 1.0). Use for UI or stingers.
OnAlertLevelChangedHighestStateThe highest state across all targets changes.
OnTargetStateChangedTarget, Old, NewAny 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, times
GetMostAwareTarget lets 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, and ResolvedTarget each tick. Bind LastKnownLocation into 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 (a BlueprintNativeEvent) 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:
StateEnter whenDoes
Patrolmost-aware target < Suspiciousfollow a spline (stock AI Move To)
Investigatemost-aware target >= Suspicious and < Detectedmove to the stimulus / last-known, look around
Combata target is Detectedyour existing SEC combat sub-tree
Searchwas Detected, now LostPoll Last Known LocationAI Move To, wait out the grace window
ReturnOnTargetForgotten firesAI 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 OnTargetSpottedBroadcastAwarenessToAllies(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

HookTypeUse it to
ShouldIgnoreActor(Actor)BlueprintNativeEventDrop 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)BlueprintNativeEventRemap a non-sight stimulus (hearing/damage) to a state, e.g. ignore hearing while the target carries a "Sneaking" tag.
GetDesiredFacingLocation(OutLoc)BlueprintNativeEventCustom facing while not Detected (see above).
InnerSelectorPropertyRun your own selector on the awareness-filtered list (default: nearest).
bGradualEscalation = falsePropertyRevert 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 OnTargetStateChanged to a print, or read GetAwarenessState / GetHighestAwarenessState on tick.
  • Read GetAwarenessProgress to see the meter fill in real time, or bind OnAwarenessProgress.
  • Check the chain: bind OnTargetSpotted and walk into the cone. It fires when you enter and stays quiet when you stand behind the enemy.

Integration Points

SystemHow Awareness Connects
Targeting SystemThe Awareness Filtered Target Selector gates which targets reach selection; MinRequiredState sets the disengage feel
StateTree IntegrationThe Awareness State At Least condition and Poll Last Known Location task branch the brain on awareness
Combat RolesOnly sensed targets feed role assignment, since the selector filters first
Threat DetectionThreat tracks the player's attention; Awareness tracks what the AI has perceived. Use both for "knows you are there and knows you are watching"