- Created detailed documentation for systems 102-135 covering achievements, settings, polish, data assets, input management, and state management. - Added INDEX.md for easy navigation of developer reference materials. - Introduced architecture-overview.md to provide a high-level understanding of the framework's structure and communication methods. - Compiled implementation-patterns.md to outline common UE5 Blueprint patterns for consistent development practices.
457 lines
26 KiB
Markdown
457 lines
26 KiB
Markdown
# 02 — Player State & Embodiment Systems (Systems 08-15)
|
|
|
|
**Category Purpose:** These 8 systems form the player character's core simulation layer — health, stamina, stress, movement, hiding, first-person body, camera, and metrics tracking. They cascade: health affects stress, stress affects movement, movement affects camera. All feed into the animation system (ABP_GASP) via event dispatchers.
|
|
|
|
---
|
|
|
|
## System Index
|
|
|
|
| # | System | Asset Type | Role |
|
|
|---|--------|-----------|------|
|
|
| 08 | `BPC_HealthSystem` | Component | Health pool, damage resistance, death trigger, healing |
|
|
| 09 | `BPC_StaminaSystem` | Component | Stamina pool, sprint/action drain, exhaustion states |
|
|
| 10 | `BPC_StressSystem` | Component | Psychological stress, tiers (Calm→Catatonic), hallucinations |
|
|
| 11 | `BPC_MovementStateSystem` | Component | Movement mode + posture tracking; GASP liaison; footsteps |
|
|
| 12 | `BPC_HidingSystem` | Component | Hide/peek/breath-hold; LOS checks; stress decay while hidden |
|
|
| 13 | `BPC_EmbodimentSystem` | Component | First-person body mesh, arm IK, visibility modes, overlays |
|
|
| 14 | `BPC_CameraStateLayer` | Component | Camera FOV/offset/rotation layers for all states; shake system |
|
|
| 15 | `BPC_PlayerMetricsTracker` | Component | Player metrics: accuracy, deaths, playstyle ratios |
|
|
|
|
---
|
|
|
|
## Category Data Flow — The Cascade
|
|
|
|
```
|
|
┌──────────────────────────────────────────────────────────────────────┐
|
|
│ PLAYER SIMULATION CASCADE │
|
|
│ │
|
|
│ Combat Damage │
|
|
│ ↓ │
|
|
│ BPC_HealthSystem │
|
|
│ ↓ dispatchers: OnDamageTaken → │
|
|
│ BPC_StressSystem ←── also fed by: enemy proximity, environment, │
|
|
│ ↓ dispatchers: OnStressTierChanged → narrative events │
|
|
│ BPC_CameraStateLayer (FOV pulse, chromatic aberration) │
|
|
│ BPC_MovementStateSystem (movement penalties at high stress) │
|
|
│ ↓ dispatchers: OnMovementModeChanged → │
|
|
│ BPC_StaminaSystem (regen blocked while sprinting) │
|
|
│ ABP_GASP (animation selection) │
|
|
│ ↓ dispatchers: OnSprintStateChanged → │
|
|
│ BPC_StaminaSystem (continuous drain during sprint) │
|
|
│ │
|
|
│ BPC_HidingSystem ←── interacts with both: │
|
|
│ ↓ stress decay while hidden │
|
|
│ ↓ camera constrained while hiding │
|
|
│ ↓ movement disabled while inside spot │
|
|
│ │
|
|
│ BPC_EmbodimentSystem ←── visual overlays from damage/water │
|
|
│ BPC_PlayerMetricsTracker ←── records everything for analytics │
|
|
└──────────────────────────────────────────────────────────────────────┘
|
|
```
|
|
|
|
---
|
|
|
|
## 08 — BPC_HealthSystem: Health, Damage & Death
|
|
|
|
**What It Does:** The central survivability component. Manages a health pool (MaxHealth → CurrentHealth), applies damage with type-based resistance calculation, handles healing, tracks death state (Alive → Dying → Dead → PermaDeath), and fires dispatchers that cascade to stress, UI, and death handling systems.
|
|
|
|
**How It Works Internally:**
|
|
|
|
**Damage Application Flow:**
|
|
1. `ApplyDamage(DamageEvent)` called by weapon, trap, or environment
|
|
2. Early-out checks: Is DeathState == Dead? Is bIsInvincible? → return 0
|
|
3. Calculate resistance: look up `S_DamageResistance` for `DamageType`, multiply `BaseAmount` by `Multiplier`
|
|
4. `CurrentHealth -= EffectiveDamage`
|
|
5. Reset `RegenDelay` timer (regen starts after delay from last damage)
|
|
6. Fire `OnDamageTaken` → `BPC_StressSystem` reacts, HUD updates
|
|
7. Check thresholds: if `CurrentHealth <= 0` → `HandleDeath()`; if `CurrentHealth <= CriticalHealthPercent * MaxHealth` → fire `OnHealthCritical`
|
|
8. If DamageType is `Fear` → stress multiplier on `BPC_StressSystem`
|
|
|
|
**Resistance System:**
|
|
- Default resistances stored as array of `S_DamageResistance` (type → multiplier)
|
|
- 7 damage types: Physical, Arcane, Fire, Poison, Fear, Environmental, True (bypasses all)
|
|
- `AddResistance()` / `RemoveResistance()` at runtime for buffs/debuffs
|
|
|
|
**Death States:**
|
|
- `Alive` → normal; `Dying` → downed, waiting for recovery/final death; `Dead` → no actions; `PermaDeath` → save-scrubbing locked
|
|
- On death: clear all timers (regen, DoT, invincibility), fire `OnDeath`, notify `GM_CoreGameMode.HandlePlayerDead()`
|
|
|
|
**Health Regeneration:**
|
|
- `RegenDelay` seconds after last damage before regen starts
|
|
- Timer ticks `RegenRate` HP per second until `CurrentHealth >= MaxHealth`
|
|
- Blocked by death state
|
|
|
|
**Implementation Patterns:**
|
|
- `GetHealthNormalised()` returns 0.0-1.0 for UI bars — smooth interpolation, never raw polling
|
|
- `KillInstant()` bypasses everything for scripted deaths
|
|
- `ApplyDamageOverTime()` creates a looping timer with unique SourceName to prevent stacking
|
|
- `SetMaxHealth(NewMax, bMaintainRatio)` scales CurrentHealth proportionally or clamps
|
|
- All dispatchers fire on authority; UI binds and reacts
|
|
|
|
**Integration Points:**
|
|
- **Listens to:** Nothing directly (called by damagers)
|
|
- **Broadcasts:** `OnHealthChanged`, `OnDamageTaken`, `OnHealthCritical`, `OnDeath`, `OnDeathStateChanged`, `OnInvincibilityChanged`
|
|
- **Key consumers:** `BPC_StressSystem` (damage → stress), `WBP_HUD` (health bar), `GM_CoreGameMode` (death), `BPC_HitReactionSystem` (stagger)
|
|
|
|
**Edge Cases:**
|
|
- Invincibility blocks all damage for its duration (used after respawn/dodge)
|
|
- DoT with same SourceName replaces existing (no stacking)
|
|
- ApplyHealing on dead character returns 0, no dispatchers
|
|
- Negative damage treated as 0
|
|
|
|
---
|
|
|
|
## 09 — BPC_StaminaSystem: Stamina Pool & Exhaustion
|
|
|
|
**What It Does:** Manages a stamina resource that drains during sprinting, jumping, climbing, dodging, and special attacks. Enforces minimum stamina thresholds per action, applies exhaustion penalties (Normal → Low → Exhausted), and coordinates with MovementState for regen blocking while moving.
|
|
|
|
**How It Works Internally:**
|
|
|
|
**Drain System:**
|
|
- Each `E_StaminaActionType` (Sprint, Jump, Climb, SpecialAttack, Dodge, Environment) has a `S_StaminaDrainRate` config: `DrainPerSecond` (continuous), `DrainFlat` (one-shot), `MinStamina` (threshold to perform), `CooldownAfterUse`
|
|
- `DrainStamina(ActionType)` checks: cooldown active? sufficient stamina? → deduct, update exhaustion, start regen delay
|
|
- `StartContinuousDrain(ActionType)` for sprint/climb — timer runs at 0.1s intervals
|
|
- `StopContinuousDrain(ActionType)` stops when action ends
|
|
|
|
**Exhaustion States:**
|
|
- `Normal` (full operation) → `Low` (below LowThreshold, heavy breathing) → `Exhausted` (below ExhaustedThreshold, cannot sprint, slow regen)
|
|
- `UpdateExhaustionState()` checks `CurrentStamina / MaxStamina` against configured thresholds
|
|
- Transition downward is instant; recovery is gradual
|
|
- `OnExhausted` dispatcher → player controller shows feedback, sprint blocked
|
|
|
|
**Regeneration:**
|
|
- `RegenSettings` configures: `RegenRate`, `RegenDelay`, `ExhaustedRegenRate`, `ExhaustedRegenDelay`, `RegenBlockedWhileMoving`
|
|
- If `RegenBlockedWhileMoving`: listens to `BPC_MovementStateSystem.OnMovementModeChanged`, pauses regen when speed > walk
|
|
- `BlockRegen(Duration)` for external debuffs
|
|
|
|
**Implementation Patterns:**
|
|
- `CanAffordAction(ActionType)` checks both stamina level and cooldown before allowing
|
|
- Per-action cooldowns prevent dodge/jump spamming
|
|
- `RestoreStamina(Amount, Tags)` for potions/resting
|
|
- `SetMaxStamina(NewMax, bMaintainRatio)` scales current proportionally
|
|
|
|
**Integration Points:**
|
|
- **Called by:** `PC_PlayerController` (sprint, jump, dodge input)
|
|
- **Broadcasts:** `OnStaminaChanged` → `WBP_HUD`, `OnExhausted` → movement/audio, `OnExhaustionStateChanged` → `ABP_GASP` (breathing anim)
|
|
- **Listens to:** `BPC_MovementStateSystem.OnMovementModeChanged` (regen blocking)
|
|
- **Key consumers:** `BPC_MovementStateSystem` (exhausted blocks sprint), `BPC_CameraStateLayer` (exhaustion effects)
|
|
|
|
**Edge Cases:**
|
|
- Multiple continuous drains stack independently
|
|
- DrainStamina during cooldown returns false without side effects
|
|
- MaxStamina change with bMaintainRatio preserves current percentage
|
|
- All timers cleaned on component destroy
|
|
|
|
---
|
|
|
|
## 10 — BPC_StressSystem: Psychological Stress & Sanity
|
|
|
|
**What It Does:** Simulates the player's psychological state via an accumulating stress meter. Multiple stress sources contribute simultaneously (enemy proximity, environmental horror, health deficit, narrative events, supernatural, isolation). Stress tiers (Calm→Uneasy→Distressed→Panicked→Terrified→Catatonic) drive visual distortion, audio hallucinations, movement penalties, and narrative branching.
|
|
|
|
**How It Works Internally:**
|
|
|
|
**Multi-Source Architecture:**
|
|
- `ActiveSources` map (FName identifier → `S_StressSourceData`) tracks all contributing sources
|
|
- Each source has: `CurrentIntensity`, `MaxIntensity`, `DecayRate`, `SourceTags`
|
|
- `AddStressSource()` adds or updates a source; `RemoveStressSource()` removes it
|
|
- `RecalculateFromSources()` sums all source intensities and updates total
|
|
|
|
**Stress Events:**
|
|
- `AddStress(Event)` can be instant (`bIsInstant`) or gradual (adds to source system)
|
|
- `HealthDeficitMultiplier` amplifies incoming stress when health < 50% — creates death spiral feel
|
|
- `OnDamageTakenHandler` converts damage amount to stress (Fear damage type gets 2x multiplier)
|
|
- `ForcePanic(Duration)` temporarily forces Panicked tier for narrative use
|
|
|
|
**Tier System:**
|
|
- 6 tiers with configurable thresholds: `Uneasy` (subtle audio), `Distressed` (visual noise, heartbeat), `Panicked` (heavy distortion, movement penalty), `Terrified` (hallucinations, input inversion), `Catatonic` (freeze/stumble)
|
|
- `UpdateTier()` compares `CurrentStress` against threshold values
|
|
- Tier transitions fire `OnStressTierChanged` — systems react to tier, not raw stress value
|
|
- `TierEntryTimes` map records when each tier was entered for duration tracking
|
|
|
|
**Hallucination System:**
|
|
- At `Terrified` tier: `HandleHallucinationCheck()` rolls random chance each tick
|
|
- Triggers random hallucination events (visual, audio, dialogue)
|
|
- Stops when tier drops below `Distressed`
|
|
|
|
**Safe Zones & Recovery:**
|
|
- `SetSafeZone(bSafe)` toggles passive decay
|
|
- `PassiveDecayTick()` slowly reduces stress when in safe area or below Distressed
|
|
- `OnSafeZoneChanged` dispatcher → atmosphere system adjusts
|
|
|
|
**Implementation Patterns:**
|
|
- Sources with identifiers enable precise tracking (e.g., "Enemy_Guard_12", "Area_Basement")
|
|
- `GetTierDuration(Tier)` for narrative systems to query how long player has been panicked
|
|
- At Catatonic, further stress accumulation is blocked (immune at max)
|
|
- All effects driven by tier dispatchers, never by polling
|
|
|
|
**Integration Points:**
|
|
- **Called by:** Enemies (proximity), environment triggers, `BPC_HealthSystem` (damage handler)
|
|
- **Broadcasts:** `OnStressTierChanged` → `BPC_CameraStateLayer` (post-process), `ABP_GASP` (anim), `WBP_HUD` (vignette), `OnHallucinationTriggered` → hallucination/audio managers, `OnCatatonicStateEntered` → input lockdown
|
|
- **Listens to:** `BPC_HealthSystem.OnDamageTaken`
|
|
|
|
**Edge Cases:**
|
|
- Catatonic blocks all non-instant stress additions
|
|
- Stress clamping prevents overflow past MaxStress
|
|
- Source with matching identifier updates existing entry (no duplicate sources)
|
|
- ForcePanic temporarily locks tier and restores gradually after duration
|
|
|
|
---
|
|
|
|
## 11 — BPC_MovementStateSystem: Movement Mode & Posture
|
|
|
|
**What It Does:** The "movement oracle" — tracks the player's current state (movement mode + posture), reports changes via dispatchers, and applies movement settings to the CharacterMovementComponent. Other systems query here instead of polling the movement component directly. Bridges gameplay state to GASP animation.
|
|
|
|
**How It Works Internally:**
|
|
|
|
**Dual State Tracking:**
|
|
- `CurrentMovementMode` (Idle, Walking, Jogging, Sprinting, CrouchWalk, Sneaking) — speed tier
|
|
- `CurrentPosture` (Standing, Crouching, Prone, Sliding, Climbing, Vaulting) — body position
|
|
- These are independent — you can be Sprinting while Standing, or CrouchWalk while Crouching
|
|
- `PreviousMovementMode` and `PreviousPosture` stored for transition detection
|
|
|
|
**Movement Settings Application:**
|
|
- `MovementSettings` map (Mode → `S_MovementSettings`) defines: `MaxWalkSpeed`, `Acceleration`, `Deceleration`, `GroundFriction`, `bCanSprint`, `bCanCrouch`, `StaminaDrainMultiplier`
|
|
- `SetMovementMode(NewMode)` applies the corresponding settings to `CharacterMovementComponent`
|
|
- `SetPosture(NewPosture)` adjusts CapsuleComponent half-height (Standing=96, Crouch=60, Prone=30)
|
|
- Prone requires going through Crouching first (enforced)
|
|
|
|
**Movement Penalties:**
|
|
- `ApplyMovementPenalty(Multiplier, Duration, PenaltyTag)` temporarily multiplies MaxWalkSpeed
|
|
- Timer restores original value after Duration
|
|
- Used by stress system (movement penalty at high stress), injury system, debuffs
|
|
- Each penalty tagged for tracking — multiple penalties stack multiplicatively?
|
|
|
|
**Footstep System:**
|
|
- `CalculateFootstep()`: line trace downward from foot → get surface physical material → look up `S_FootstepProfile` matching surface and mode
|
|
- `DefaultFootstepProfile` as fallback
|
|
- Fires `OnFootstep` dispatcher with mode and surface type for audio system
|
|
- Velocity threshold determines soft vs hard footstep sound
|
|
|
|
**GASP Integration:**
|
|
- On every mode/posture change: notify ABP_GASP via direct reference or interface
|
|
- Sets GASP-specific animation variables (bStrafing, bSprinting, gait, stance)
|
|
- This is the ONLY component that talks directly to ABP_GASP for movement state
|
|
|
|
**Implementation Patterns:**
|
|
- Does NOT handle input — input remains in `PC_PlayerController`
|
|
- `CanTransitionToPosture(TargetPosture)` traces for ceiling clearance
|
|
- `SetSprinting(bSprinting)` wraps SetMovementMode with stamina awareness
|
|
- `OnMovementUpdated(Tick)` checks velocity, detects start/stop, tracks ground state
|
|
- `GetCurrentSpeedNormalised()` for smooth animation blend values
|
|
|
|
**Integration Points:**
|
|
- **Called by:** `PC_PlayerController` (input → mode changes)
|
|
- **Broadcasts:** `OnMovementModeChanged`, `OnPostureChanged`, `OnMovementStart/Stop`, `OnSprintStateChanged`, `OnJumped/Landed`, `OnFootstep`
|
|
- **Key consumers:** `ABP_GASP` (animation), `BPC_StaminaSystem` (drain/regen), `BPC_CameraStateLayer` (FOV), `BP_AudioManager` (footsteps), `BPC_InteractionDetector` (range scaling)
|
|
|
|
**Edge Cases:**
|
|
- Forced transitions (knockdown) apply impulse regardless of current state
|
|
- Cannot transition to upright if ceiling is too low (traced by CanTransitionToPosture)
|
|
- Rapid mode switching is protected by TransitionBlendTime
|
|
- Sprinting auto-stops when stamina hits 0 (external listener)
|
|
|
|
---
|
|
|
|
## 12 — BPC_HidingSystem: Stealth & Concealment
|
|
|
|
**What It Does:** Manages the player entering, occupying, peeking from, and exiting environmental hiding spots. Handles line-of-sight checks against enemies, breath-holding mechanics, and stress reduction while concealed. The central hub for all stealth gameplay.
|
|
|
|
**How It Works Internally:**
|
|
|
|
**Hide State Machine:**
|
|
```
|
|
Exposed → Entering → Hidden ⇄ Peeking → Exiting → Exposed
|
|
```
|
|
- `Entering/Exiting`: transient animation states
|
|
- `Hidden`: fully concealed, LOS blocked, stress decaying
|
|
- `Peeking`: partial exposure, camera offset, timed max duration
|
|
- Each transition broadcasts `OnHideStateChanged`
|
|
|
|
**Hide Spot Types:**
|
|
- `Locker`: fully enclosed (wardrobe, locker) — complete concealment
|
|
- `BehindCover`: behind low wall/crate — peeking possible
|
|
- `Under`: under bed/table — prone entry
|
|
- `InShadow`: standing in shadow volume — dynamic, proximity-based
|
|
- `TallGrass`: crouch-moving through vegetation — partial concealment
|
|
- Each type stored in `S_HideSpotInfo` from the hiding spot actor
|
|
|
|
**Entry Protocol:**
|
|
1. Player presses interact near a hide spot
|
|
2. `EnterHideSpot(HideSpotActor)` → validate I_HidingSpot interface, check slot availability
|
|
3. Set `CurrentHideState = Entering`, disable movement input
|
|
4. Play entering animation → animation notify triggers `OnAnimationHideEnterComplete`
|
|
5. Set `CurrentHideState = Hidden`, start stress decay timer, start periodic LOS check
|
|
|
|
**Line of Sight (LOS) System:**
|
|
- `IsPlayerDetectable(EnemyLocation, DetectionRange)` called by AI perception
|
|
- If not hidden: always detectable
|
|
- If hidden: line trace from enemy to player → if trace hits hide spot actor before player: concealed
|
|
- Peeking state increases detection radius
|
|
- `PerformLOSCheck()` runs on timer: iterates all enemies in range, checks each
|
|
- If any enemy has LOS: fire `OnHideSpotCompromised` → stress spike, forced exit warning
|
|
|
|
**Peek System:**
|
|
- `StartPeek(Direction)` — Left/Right/Over from behind cover
|
|
- Camera moves to peek socket location on hide spot actor
|
|
- `MaxPeekDuration` timer forces return to Hidden
|
|
- `PeekCooldown` prevents rapid toggling
|
|
|
|
**Stress Interaction:**
|
|
- `StressDecayWhileHidden` applied per second while in Hidden state
|
|
- `bBlocksStress` on hide spot prevents new stress sources from affecting player
|
|
- Hide spots double as psychological safe rooms
|
|
|
|
**Implementation Patterns:**
|
|
- `ForceKickFromHide()` for enemy discovery — bForceExit skips animation
|
|
- `TryBreathHold()` reduces noise for 8 seconds near enemies
|
|
- `OnDamageWhileHiding` handler: penetrating damage forces exit; non-penetrating converts to stress
|
|
- Destroying a hide spot while player is inside force-exits them
|
|
|
|
**Integration Points:**
|
|
- **Called by:** `PC_PlayerController` (interact input), AI (IsPlayerDetectable queries)
|
|
- **Broadcasts:** `OnHideStateChanged`, `OnEntered/ExitedHidingSpot`, `OnPeekStarted/Ended`, `OnHideSpotCompromised`, `OnForcedExitWarning`, `OnBreathHoldChanged`
|
|
- **Key consumers:** `BPC_CameraStateLayer` (peek/hide offsets), `BPC_StressSystem` (decay), `ABP_GASP` (hide anims), `AI_EnemyController` (awareness), `WBP_HUD` (hide indicators)
|
|
|
|
**Edge Cases:**
|
|
- EnterHideSpot while already hiding returns false
|
|
- ExitHideSpot while Exposed does nothing
|
|
- Multiple players can't occupy limited-slot spots
|
|
- Peek max duration and cooldown enforced
|
|
- Shutting down the hide spot actor force-exits the player
|
|
|
|
---
|
|
|
|
## 13 — BPC_EmbodimentSystem: First-Person Body
|
|
|
|
**What It Does:** Creates first-person body awareness — the player sees their arms, shadow, and optionally legs/torso in context-appropriate situations. Manages mesh visibility modes, environmental body overlays (blood, water, mud), wall proximity detection for arm IK, and shadow casting.
|
|
|
|
**How It Works Internally:**
|
|
|
|
**Visibility Modes:**
|
|
- `FullBody` (third-person, mirrors, death) → `ArmsOnly` (default first-person) → `ArmsAndShadow` → `Minimal` (only hands, high stress) → `Hidden` (cutscenes, UI)
|
|
- `SetVisibilityMode(NewMode, bInstant)` toggles mesh components: ArmsMesh, BodyShadowComponent, optional TorsoMesh
|
|
- `S_BodyPartVisibility` struct derived from mode controls individual part visibility
|
|
|
|
**Overlay System:**
|
|
- `E_BodyOverlayState`: Clean, BloodSpatter, WaterDroplets, Mud, Toxic
|
|
- `ApplyOverlay(Overlay)` with blend: sets MaterialParameter on ArmsMesh toward `TargetValue` at `BlendSpeed`
|
|
- Auto-fades after `Duration` seconds
|
|
- `ClearOverlay(Type)` removes single or all overlays
|
|
- Multiple overlays stack: blood + water = combined effect on material
|
|
- `ApplyOverlayBlendTick()` runs each frame for smooth transitions
|
|
|
|
**Wall Proximity / Arm IK:**
|
|
- `CheckWallProximity()`: line trace from camera forward by `BrushTraceDistance`
|
|
- If wall detected: apply IK offset to arms (avoids clipping), set `bIsNearWall = true`
|
|
- Fires `OnWallProximityChanged` → ABP_Arms for IK adjustment
|
|
|
|
**Damage/Environment Integration:**
|
|
- `OnDamageTakenBloodHandler`: blood overlay intensity scales with damage amount
|
|
- `OnEnterWaterHandler`: water droplets overlay with fast blend, auto-dries
|
|
- Bound to `BPC_HealthSystem.OnDamageTaken` and water volume triggers
|
|
|
|
**Implementation Patterns:**
|
|
- Mesh references cached at BeginPlay from owner (first-person skeletal mesh)
|
|
- Shadow uses separate component with shadow-only material — not full character mesh
|
|
- All overlay blending uses Material Parameter Collections for real-time updates
|
|
- Wall proximity is simple line trace; advanced IK requires arms animation blueprint
|
|
|
|
**Integration Points:**
|
|
- **Listens to:** `BPC_HealthSystem.OnDamageTaken` (blood), water volume triggers
|
|
- **Broadcasts:** `OnVisibilityModeChanged` → `BPC_CameraStateLayer` (FOV adjust), `OnOverlayChanged` → `WBP_HUD` (screen effects), `OnWallProximityChanged` → ABP_Arms
|
|
|
|
**Edge Cases:**
|
|
- Rapid visibility changes don't cause rendering glitches due to fade transitions
|
|
- Overlays stack: intensity values combined via material logic
|
|
- Hidden mode overrides all — hides everything regardless of other settings
|
|
|
|
---
|
|
|
|
## 14 — BPC_CameraStateLayer: Dynamic Camera Controller
|
|
|
|
**What It Does:** Centralizes all camera-modifying logic: field-of-view changes per state, camera shake system with priority queuing, post-process overrides (vignette, chromatic aberration, color grading), head bob, and location/rotation offsets per game state. Other systems request camera changes here instead of directly manipulating the camera.
|
|
|
|
**How It Works Internally:**
|
|
|
|
**Camera State System:**
|
|
- 10 states: Default, Aiming, Sprinting, Crouching, Peeking, Hiding, Stressed, Injured, Death, Cutscene
|
|
- Each has `S_CameraStateConfig`: TargetFOV, BlendSpeed, HeadOffset, HeadRotation, pitch constraints, head bob settings
|
|
- `RequestCameraState(NewState, bImmediate)` sets targets and starts blending
|
|
- `BlendToTargetFOV()` runs per tick: smooth interpolation to target FOV
|
|
- `BlendCameraOffset()` interpolates head position/rotation offsets
|
|
|
|
**Camera Shake System:**
|
|
- `S_CameraShakeRequest`: ShakeClass, Scale, Priority (Low/Medium/High/Cinematic), Duration, bIsLooping, Tag
|
|
- Priority system: higher priority shakes override lower; same tag replaces existing
|
|
- `PlayCameraShake(ShakeRequest)` adds to ActiveShakeRequests map and starts playback
|
|
- If Duration > 0: timer auto-stops shake
|
|
- `StopCameraShake(ShakeTag)` removes specific shake
|
|
|
|
**Post-Process Overrides:**
|
|
- `S_PostProcessOverride`: vignette, chromatic aberration, color grading LUT
|
|
- `ApplyPostProcessOverride(Override, bInstant)` blends Material Parameter Collection values
|
|
- `ClearPostProcessOverride(BlendTime)` returns to defaults
|
|
- Used by stress system (CA at high stress), injury (vignette), death (fade to black)
|
|
|
|
**Dynamic Effects:**
|
|
- **Sprint:** FOV widens by SprintFOVMultiplier
|
|
- **Stress:** `UpdateStressPulse()` applies sine-wave FOV oscillation for "unease" feel
|
|
- **Crouch:** slight downward offset
|
|
- **Peek:** camera moves to hide spot peek socket
|
|
- **Hiding:** constricted FOV, darkness effect
|
|
|
|
**Reactivity:**
|
|
- Binds to `BPC_MovementStateSystem.OnMovementModeChanged` → Sprint/Crouch/Default FOV
|
|
- Binds to `BPC_StressSystem.OnStressTierChanged` → stress effects at Panicked+
|
|
- Binds to `BPC_HealthSystem.OnDamageTaken` → injury shake, vignette
|
|
- Called directly by `BPC_HidingSystem` for peek/hide camera states
|
|
|
|
**Implementation Patterns:**
|
|
- Uses Material Parameter Collection (MPC_CameraEffects) for post-process parameters
|
|
- Camera shakes authored as Blueprint Camera Shake classes
|
|
- Pitch constraints enforced during hiding/peeking states
|
|
- All blending is frame-rate independent via DeltaTime
|
|
|
|
**Integration Points:**
|
|
- **Broadcasts:** `OnCameraStateChanged`, `OnFOVChanged`, `OnShakeStarted/Ended`, `OnPostProcessChanged`
|
|
- **Called by:** Any system needing camera change
|
|
- **Key consumers:** PlayerCameraManager (direct application), `WBP_HUD` (post-process materials)
|
|
|
|
**Edge Cases:**
|
|
- Shake with same tag and lower priority is ignored (not stacked)
|
|
- Rapid FOV switching blends smoothly — no snap transitions
|
|
- Stress pulse uses sine wave to prevent jitter
|
|
- All active shakes stopped on component destroy or pawn unpossess
|
|
|
|
---
|
|
|
|
## 15 — BPC_PlayerMetricsTracker: Analytics & Playstyle
|
|
|
|
**What It Does:** Records player behavior metrics throughout a session: accuracy (shots fired vs hit), deaths count, damage dealt/received, items used, hiding time, sprint time, objectives completed. Used by `BPC_PlaystyleClassifier` to categorize player as Aggressive/Stealthy/Explorer/Balanced, and by `BPC_DifficultyManager` for adaptive tuning.
|
|
|
|
**How It Works Internally:**
|
|
- Listens to relevant dispatchers from HealthSystem (deaths), WeaponBase (shots/hits), InventorySystem (items used), HidingSystem (hide time), MovementState (sprint time)
|
|
- Accumulates counters and ratios internally
|
|
- Provides query functions for other adaptive systems
|
|
- Persists across sessions via `I_Persistable` for long-term playstyle tracking
|
|
|
|
**Implementation Patterns:**
|
|
- Pure listener — never calls into other systems, only receives events
|
|
- All metrics are gameplay-tag keyed for extensibility
|
|
- Ratios computed on demand, not continuously
|
|
|
|
---
|
|
|
|
## Common Implementation Patterns in This Category
|
|
|
|
1. **Cascade Architecture:** Systems don't poll each other — they bind to dispatchers. Health change → stress reaction → camera effect → movement penalty. Each system reacts independently.
|
|
2. **Normalized Values for UI:** `GetHealthNormalised()`, `GetStaminaNormalised()`, `GetStressNormalised()` all return 0.0-1.0 — UI widgets interpolate smoothly.
|
|
3. **Timer-Based Ticks:** Regen, drain, stress decay all use 0.1s interval timers — not event tick. Better performance.
|
|
4. **State Not Polling:** Camera doesn't ask "am I sprinting?" — it binds to `OnMovementModeChanged` and reacts.
|
|
5. **Threshold Not Continuous:** Stress/hiding systems use tier/state thresholds — other systems react to tier changes, not raw values.
|
|
6. **Data Config Everything:** Damage resistances, movement speeds, stamina drain rates, stress thresholds — all in exposed variables or Data Assets, never hardcoded.
|
|
|
|
---
|
|
|
|
*Developer Reference v1.0 — 02 Player Systems. Companion to docs/blueprints/02-player/ specs.*
|