Threat Detection
Documentation Unreal Engine AI Threat Detection
Track whether the focus target is looking at this AI and react through movement or custom logic.
Each tick,ThreatDetectionComponentchecks whether the focus target's aim aligns with this AI. Alignment sets threat level; sustained stare inside the cone fires duration events.
Viewport
LVL_SEC_Showcase>Threat
Enemy strafes around the player. Aim toward the AI to raise threat (even outside the 15° cone); hold inside the cone for 3s to fire OnThreatDurationExceeded and swap strafe side when the profile allows it.
When to Use This
- Enemies that swap strafe side or back off when the player stares at them.
- Per-role threat response through movement profiles: turn flags on for one profile, leave them off for another.
- Custom barks, animations, or action score boosts on
OnThreatLevelChangedorOnThreatDurationExceeded. - An optional layer on Targeting; you need a focus actor first.
The component ticks each frame. Movement and actions stay separate:
SECCombatControllerComponent binds delegates when it finds ThreatDetectionComponent, and built-in movement handlers run only if MovementEvaluatorComponent exists and the active profile enables them.How It Works
Each tick, the component reads
AAIController::GetFocusActor():- Pawn focus:
GetControlRotation()(camera / control rotation). - Other actor: actor forward vector.
- No focus: threat level goes to
0.
The component builds a look dot from the focus target toward this AI:
| Signal | Source | Range |
|---|---|---|
| Threat level | Clamp(LookDot, 0, 1) when LookDot > 0, else 0 | Instant alignment, not time-based |
IsPlayerLookingAtMe() | LookDot >= cos(PlayerLookAngleThreshold) | Inside the angle cone; duration timer runs only while this is true |
| Look duration | PlayerLookAccumulatedTime while IsPlayerLookingAtMe() | Drives OnThreatDurationExceeded; uses CurrentThreatTimeThreshold (starts at PlayerLookTimeThreshold) |
Threat level can read above zero while
IsPlayerLookingAtMe() stays false: the focus target aims toward the AI but sits outside the cone.Threat level follows aim alignment each tick.
OnThreatLevelChanged fires when the value moves by more than 0.01.Look duration hits
CurrentThreatTimeThreshold and OnThreatDurationExceeded fires. The timer resets; the next threshold picks a random value in [PlayerLookTimeThreshold, PlayerLookTimeThreshold × 2]. Look-away clears duration and restores the base threshold.Setup
1. Component on the AI controller
AEnemyControllerBase adds ThreatDetectionComponent in its constructor and calls SetThreatDetectionEnabled(false) until SECCombatControllerComponent turns evaluation on at BeginPlay.On a custom controller, add Threat Detection Component to the AIController, not the pawn.
2. Enable evaluation
SECCombatControllerComponent binds threat delegates on BeginPlay when it finds ThreatDetectionComponent on the same controller:Details
SEC Combat Controller Component (SECCombatControllerComponent)
Threat Response
Enable Threat Detection
Binds threat delegates on BeginPlay when ThreatDetectionComponent exists. Enable Threat Detection only controls SetThreatDetectionEnabled(true) on BeginPlay.
Enable Threat Detection defaults to on; BeginPlay calls
SetThreatDetectionEnabled(true). Uncheck it to skip threat evaluation (the component may still tick for debug draw). Delegates bind whenever the component exists. EnemyControllerBase starts with evaluation off; this flag turns it on.3. Focus target
Register and assign a combat target so the AI sets focus on the player pawn (Targeting System). No focus means threat stays at zero.
4. Tune detection
Details
Threat Detection Component (ThreatDetectionComponent)
Threat Detection
Player Look Angle Threshold
15
Player Look Time Threshold
3
Debug
Debug Log Threat
Debug Draw Threat
AI controller component. Evaluation starts disabled in EnemyControllerBase; SECCombatControllerComponent calls SetThreatDetectionEnabled(true) on BeginPlay when Enable Threat Detection is on.
| Field | Notes |
|---|---|
| Player Look Angle Threshold | Half-angle cone in degrees. Default 15. |
| Player Look Time Threshold | Seconds of continuous look before OnThreatDurationExceeded. Resets on look-away. |
5. Movement responses (per combat role)
SECCombatControllerComponent reads threat fields on the active UMovementBehaviorProfile and applies strafe swap or distance scaling when that profile enables them (profile swaps with combat role):Details
Movement Behavior Profile (MovementBehaviorProfile)
Threat Response
Swap Strafe On High Threat
Adjust Distance By Threat
Threat Distance Scale
1
Role-swapped fields on the active movement profile. Make* presets leave both flags false.
| Field | Notes |
|---|---|
| Swap Strafe On High Threat | On duration exceeded, SECCombatControllerComponent calls MovementEvaluatorComponent::SwapStrafeSide(). |
| Adjust Distance By Threat | Each threat update sets DistanceMultiplier = 1.0 + ThreatLevel × ThreatDistanceScale. |
| Threat Distance Scale | Requires adjust-by-threat. Clamped 0-5. |
Assign profiles in
EnemyAIConfig → RoleMovementProfiles. MakeAttacker() and MakeWaiter() leave threat fields at false; enable them on each MovementBehaviorProfile asset you assign.Read Threat Level
Call
Get Current Threat Level on ThreatDetectionComponent (BlueprintCallable, returns 0.0-1.0).Bind
On Threat Level Changed for continuous updates. Bind On Threat Duration Exceeded for stare-duration reactions; SECCombatControllerComponent wires strafe swap when the profile allows it.Integration
| System | Link |
|---|---|
| Targeting System | Focus actor from assigned combat target / SetFocus. |
| Movement System | Threat response fields on MovementBehaviorProfile; SECCombatControllerComponent wires them. |
| Action System | Optional custom USECScorer reads GetCurrentThreatLevel() (see Advanced). |
| Combat Roles | Each role can use a movement profile with its own threat toggles. Threat does not feed role assignment. |
AdvancedDelegates and runtime API
| Delegate / function | When |
|---|---|
OnThreatLevelChanged | Threat level moves by more than 0.01 since last broadcast |
OnThreatDurationExceeded | Continuous look within angle threshold reaches the time threshold |
GetCurrentThreatLevel() | Raw alignment 0-1 |
GetPlayerLookDuration() | Seconds accumulated this look session (resets on look-away) |
IsPlayerLookingAtMe() | Focus target inside PlayerLookAngleThreshold cone |
SetThreatDetectionEnabled / IsThreatDetectionEnabled | Toggle evaluation; disabling clears threat state (tick may still run for debug) |
SetTickInterval | Throttle tick rate (0 = every frame) |
ThreatDetectionComponent belongs on the AIController, not the pawn. It never touches MovementEvaluatorComponent. SECCombatControllerComponent::OnThreatLevelUpdated and OnThreatDurationExceeded hold the movement hooks. HandleDeath calls SetThreatDetectionEnabled(false).AdvancedCustom action scoring
Add a Blueprint or C++
USECScorer to an action's scoring list. Read threat from the controller:float ScoreMultiplier_Implementation(const FSECScoringContext& Context) const override
{
const UThreatDetectionComponent* Threat =
Context.Controller->FindComponentByClass<UThreatDetectionComponent>();
const float Level = Threat ? Threat->GetCurrentThreatLevel() : 0.f;
return 1.f + Level * 0.5f;
}You write and tune the curve; the plugin ships no default scorer for threat.
AdvancedDebug
Per-instance flags on the component (Debug Log Threat, Debug Draw Threat) or global console cheats:
SEC.Debug.Threat.Draw 1
SEC.Debug.Threat.Log 1
Draw mode shows the look cone from the focus target and a progress arc on the AI while stared at (white → orange → red).
AlternativeManual wiring without SECCombatControllerComponent
Add
ThreatDetectionComponent to your AIController and call SetThreatDetectionEnabled(true).Bind
OnThreatDurationExceeded to your handler (strafe swap, bark, etc.). The component header documents no movement coupling; you wire the pairing.