182 lines
8.9 KiB
Markdown
182 lines
8.9 KiB
Markdown
# 63 — BPC_FearSystem
|
||
|
||
## Blueprint Spec — UE 5.5–5.7
|
||
|
||
---
|
||
|
||
### Parent Class
|
||
`ActorComponent`
|
||
|
||
### Dependencies
|
||
- [`GI_GameFramework`](../01-core/04_GI_GameFramework.md) — Central game instance access
|
||
- [`BPC_PlayerMetricsTracker`](../02-player/15_BPC_PlayerMetricsTracker.md) — Player anxiety/stress metrics
|
||
- [`BPC_DifficultyManager`](89_BPC_DifficultyManager.md) — Fear intensity modifier
|
||
- [`BPC_StressSystem`](../02-player/10_BPC_StressSystem.md) — Player stress level
|
||
- [`BPC_AtmosphereController`](64_BPC_AtmosphereController.md) — Atmosphere response
|
||
- [`BPC_AudioManager`](66_BPC_AudioManager.md) — Audio feedback
|
||
- [`BPC_VFXManager`](67_BPC_VFXManager.md) — Visual feedback
|
||
- [`BPC_LightingManager`](65_BPC_LightingManager.md) — Lighting response
|
||
- [`BPC_NarrativeStateSystem`](../07-narrative/38_BPC_NarrativeStateSystem.md) — Story-aware fear triggers
|
||
|
||
### Purpose
|
||
Core fear and anxiety system that manages the player's fear level, fear sources, fear decay, and fear-induced gameplay effects. Acts as the central orchestrator for all horror-related feedback loops — audio, visual, AI behavior, and UI — driven by the player's current fear state and environmental context.
|
||
|
||
### Variables
|
||
|
||
| Name | Type | Description |
|
||
|------|------|-------------|
|
||
| `CurrentFearLevel` | Float (0–100) | Current fear value |
|
||
| `MaxFearLevel` | Float | Cap for fear (default 100) |
|
||
| `FearDecayRate` | Float | Passive fear reduction per second |
|
||
| `FearThresholds` | TMap\<EFearThreshold, Float\> | Threshold values for each fear tier |
|
||
| `ActiveFearSources` | TArray\<FFearSource\> | Currently contributing fear sources |
|
||
| `FearMultiplier` | Float | Global multiplier (from DifficultyManager) |
|
||
| `bIsInPanicState` | Bool | Overwhelmed by fear |
|
||
| `PanicDuration` | Float | Seconds of panic state |
|
||
| `PanicTimer` | Float | Panic countdown |
|
||
| `LastIncreaseTime` | Float | When fear last increased |
|
||
| `bFearDecayPaused` | Bool | Freeze decay |
|
||
| `EnvironmentalFearModifier` | Float | Ambient fear from atmosphere |
|
||
| `DarknessFearMultiplier` | Float | Extra fear in dark areas |
|
||
| `IsolatedFearMultiplier` | Float | Extra fear when alone |
|
||
| `ProximityFearMultiplier` | Float | Extra fear from nearby threats |
|
||
| `bIsInSafeZone` | Bool | Safe zone overrides fear |
|
||
|
||
### Enums
|
||
|
||
| Enum | Values | Description |
|
||
|------|--------|-------------|
|
||
| `EFearThreshold` | Calm, Uneasy, Nervous, Afraid, Terrified, Panic | Fear tiers |
|
||
|
||
### Structs
|
||
|
||
| Struct | Fields | Description |
|
||
|--------|--------|-------------|
|
||
| `FFearSource` | SourceName: FName, BaseValue: Float, CurrentValue: Float, DecayDelay: Float, bIsDecaying: Bool, TimeSinceTrigger: Float, Tag: FGameplayTag | Active fear contributor |
|
||
| `FFearEvent` | Source: FName, Value: Float, Duration: Float, bInstant: Bool, bStack: Bool, AssociatedTag: FGameplayTag | Incoming fear impulse |
|
||
|
||
### Functions
|
||
|
||
| Name | Inputs | Outputs | Description |
|
||
|------|--------|---------|-------------|
|
||
| `Initialize` | — | — | Setup thresholds, bind events |
|
||
| `AddFear` | Event: FFearEvent | — | Add fear from any source |
|
||
| `RemoveFearSource` | SourceName: FName | — | Remove specific fear source |
|
||
| `ClearAllFear` | — | — | Reset fear to baseline |
|
||
| `GetFearLevel` | — | Float | Current fear value |
|
||
| `GetFearThreshold` | — | EFearThreshold | Current fear tier |
|
||
| `IsInPanic` | — | Bool | Panic state check |
|
||
| `SetFearDecayRate` | NewRate: Float | — | Override decay speed |
|
||
| `PauseFearDecay` | bPaused: Bool | — | Freeze/unfreeze decay |
|
||
| `UpdateEnvironmentalFear` | Modifier: Float | — | Ambient fear contribution |
|
||
| `CalculateFearTier` | FearValue: Float | EFearThreshold | Determine current tier |
|
||
| `TriggerPanic` | Duration: Float | — | Force panic state |
|
||
| `ResolvePanic` | — | — | End panic state early |
|
||
| `ApplyFearEffect` | Effect: EFearEffect | — | Gameplay consequences of fear |
|
||
|
||
### Event Dispatchers
|
||
|
||
| Name | Parameters | Fired When |
|
||
|------|-----------|-----------|
|
||
| `OnFearLevelChanged` | NewFear: Float, Threshold: EFearThreshold | Any fear change |
|
||
| `OnFearThresholdReached` | Threshold: EFearThreshold | Cross a fear tier boundary |
|
||
| `OnPanicStarted` | — | Panic state entered |
|
||
| `OnPanicEnded` | — | Panic state ended |
|
||
| `OnFearSourceAdded` | Source: FFearSource | New fear source registered |
|
||
| `OnFearSourceRemoved` | SourceName: FName | Fear source expired |
|
||
|
||
### Blueprint Flow
|
||
|
||
```
|
||
[Tick — every frame]
|
||
└─► If not bFearDecayPaused AND not bIsInPanicState:
|
||
CurrentFearLevel -= FearDecayRate * DeltaTime
|
||
Clamp CurrentFearLevel to 0..MaxFearLevel
|
||
└─► Process active fear sources:
|
||
For each FFearSource in ActiveFearSources:
|
||
Source.TimeSinceTrigger += DeltaTime
|
||
If Source.TimeSinceTrigger > Source.DecayDelay:
|
||
Source.bIsDecaying = true
|
||
Source.CurrentValue -= DecayRate * DeltaTime
|
||
If Source.CurrentValue <= 0:
|
||
Remove from ActiveFearSources
|
||
Fire OnFearSourceRemoved
|
||
└─► If bIsInPanicState:
|
||
PanicTimer -= DeltaTime
|
||
If PanicTimer <= 0:
|
||
ResolvePanic()
|
||
└─► CalculateFearTier(CurrentFearLevel)
|
||
└─► If tier changed since last frame:
|
||
Fire OnFearThresholdReached(NewThreshold)
|
||
|
||
[AddFear]
|
||
└─► Apply modifiers:
|
||
EffectiveValue = Event.Value * FearMultiplier
|
||
EffectiveValue *= EnvironmentalFearModifier
|
||
EffectiveValue *= DarknessFearModifier (if in dark volume)
|
||
EffectiveValue *= IsolatedFearModifier (if no allies)
|
||
EffectiveValue *= ProximityFearModifier (if enemies nearby)
|
||
└─► If Event.bStack:
|
||
Find existing source by Event.Source
|
||
If found: Stack.Value += EffectiveValue
|
||
Else: Create new FFearSource
|
||
└─► Else:
|
||
Create new FFearSource with Event parameters
|
||
└─► CurrentFearLevel += EffectiveValue
|
||
└─► Clamp to MaxFearLevel
|
||
└─► Check if panic threshold crossed:
|
||
If CurrentFearLevel >= FearThresholds[Panic]:
|
||
TriggerPanic(PanicDuration)
|
||
└─► Fire OnFearLevelChanged(CurrentFearLevel, CurrentThreshold)
|
||
└─► Fire OnFearSourceAdded(NewSource)
|
||
|
||
[TriggerPanic]
|
||
└─► bIsInPanicState = true
|
||
└─► PanicTimer = Duration (or PanicDuration default)
|
||
└─► ApplyFearEffect(EPanicEffects)
|
||
└─► BPC_AtmosphereController.TriggerPanicMode()
|
||
└─► BPC_AudioManager.PlayPanicAudio()
|
||
└─► BPC_VFXManager.TriggerPanicVFX()
|
||
└─► UI: Show panic overlay
|
||
└─► Fire OnPanicStarted
|
||
|
||
[ResolvePanic]
|
||
└─► bIsInPanicState = false
|
||
└─► CurrentFearLevel = FearThresholds[Terrified] * 0.8
|
||
└─► BPC_AtmosphereController.EndPanicMode()
|
||
└─► BPC_AudioManager.StopPanicAudio()
|
||
└─► Fire OnPanicEnded
|
||
|
||
[ApplyFearEffect — based on current threshold]
|
||
└─► EFearThreshold.Calm: No effects
|
||
└─► EFearThreshold.Uneasy: Subtle audio cues, slight camera sway
|
||
└─► EFearThreshold.Nervous: UI vignette, breathing sounds, reduced stamina regen
|
||
└─► EFearThreshold.Afraid: Visibility distortion, movement speed penalty, aim shake
|
||
└─► EFearThreshold.Terrified: Severe vignette, stammering audio, weapon sway
|
||
└─► EFearThreshold.Panic: Tunnel vision, audio distortion, sprint penalty, AI gets buffs
|
||
```
|
||
|
||
### Communications With
|
||
|
||
| Target | Method | Why |
|
||
|--------|--------|-----|
|
||
| [`BPC_PlayerMetricsTracker`](../02-player/15_BPC_PlayerMetricsTracker.md) | Get Owner Component | Track fear history for metrics |
|
||
| [`BPC_StressSystem`](../02-player/10_BPC_StressSystem.md) | Get Owner Component | Stress/fear feedback loop |
|
||
| [`BPC_DifficultyManager`](89_BPC_DifficultyManager.md) | Get Owner Component | Fear intensity modifier |
|
||
| [`BPC_AtmosphereController`](64_BPC_AtmosphereController.md) | Direct call | Atmosphere panic mode |
|
||
| [`BPC_AudioManager`](66_BPC_AudioManager.md) | Direct call | Panic audio, fear ambience |
|
||
| [`BPC_VFXManager`](67_BPC_VFXManager.md) | Direct call | Visual effects per tier |
|
||
| [`BPC_LightingManager`](65_BPC_LightingManager.md) | Direct call | Dynamic lighting response |
|
||
| [`SS_UIManager`](../06-ui/32_SS_UIManager.md) | Subsystem | HUD fear indicator, panic overlay |
|
||
| [`BPC_NarrativeStateSystem`](../07-narrative/38_BPC_NarrativeStateSystem.md) | Get Owner Component | Story-aware fear modifiers |
|
||
| [`BPC_HealthSystem`](../02-player/08_BPC_HealthSystem.md) | Get Owner Component | Panic damage if health low |
|
||
| [`AI_EnemyControllers`](../09-ai/55_BPC_AIControllerBase.md) | Event Dispatcher | AI aggression rise with player fear |
|
||
|
||
### Reuse Notes
|
||
- Single instance on player character (or PlayerController)
|
||
- All fear sources are stackable and independently decayable
|
||
- Thresholds are designer-configurable at runtime
|
||
- Fear multiplier from DifficultyManager allows difficulty to scale horror
|
||
- Safe zones (checkpoints, safe rooms) pause fear accumulation and decay
|
||
- Panic state is a temporary debuff with full cleanup on resolve
|
||
- UI reads OnFearLevelChanged dispatcher, never polls |