Add developer documentation for systems 11-16, including architecture overview and implementation patterns
- 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.
This commit is contained in:
456
docs/developer/02-player-systems.md
Normal file
456
docs/developer/02-player-systems.md
Normal file
@@ -0,0 +1,456 @@
|
||||
# 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.*
|
||||
Reference in New Issue
Block a user