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, ThreatDetectionComponent checks 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 OnThreatLevelChanged or OnThreatDurationExceeded.
  • 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:
SignalSourceRange
Threat levelClamp(LookDot, 0, 1) when LookDot > 0, else 0Instant alignment, not time-based
IsPlayerLookingAtMe()LookDot >= cos(PlayerLookAngleThreshold)Inside the angle cone; duration timer runs only while this is true
Look durationPlayerLookAccumulatedTime 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.
FieldNotes
Player Look Angle ThresholdHalf-angle cone in degrees. Default 15.
Player Look Time ThresholdSeconds 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.
FieldNotes
Swap Strafe On High ThreatOn duration exceeded, SECCombatControllerComponent calls MovementEvaluatorComponent::SwapStrafeSide().
Adjust Distance By ThreatEach threat update sets DistanceMultiplier = 1.0 + ThreatLevel × ThreatDistanceScale.
Threat Distance ScaleRequires 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

SystemLink
Targeting SystemFocus actor from assigned combat target / SetFocus.
Movement SystemThreat response fields on MovementBehaviorProfile; SECCombatControllerComponent wires them.
Action SystemOptional custom USECScorer reads GetCurrentThreatLevel() (see Advanced).
Combat RolesEach role can use a movement profile with its own threat toggles. Threat does not feed role assignment.

AdvancedDelegates and runtime API
Delegate / functionWhen
OnThreatLevelChangedThreat level moves by more than 0.01 since last broadcast
OnThreatDurationExceededContinuous 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 / IsThreatDetectionEnabledToggle evaluation; disabling clears threat state (tick may still run for debug)
SetTickIntervalThrottle 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.