Files
UE5-Modular-Game-Framework/docs/game/playercharacter.md
Lefteris Notas 040db37720 Add UI Overrides and Weapons Index documentation for Project Void
- Created ui-overrides.md detailing game-specific Widget Blueprint overrides, including purpose, widget index, visual styling, and accessibility requirements.
- Established weapons-index.md outlining all held weapon actors, including their components, logic, and comparisons for gameplay mechanics.
2026-05-21 22:27:57 +03:00

20 KiB
Raw Blame History

Player Character — BP_HorrorPlayerCharacter

Game: Project Void | Asset: BP_HorrorPlayerCharacter | Parent: GASP-based Character Asset Path: Content/Game/Characters/BP_HorrorPlayerCharacter.uasset Build Phase: 4 | Demonstrates: All 02-player systems (08-15) + 03-interaction (16) + 04-inventory (26,28,30,31,34) + 08-weapons (70,71,72) + 16-state (130)


Purpose

The player's physical embodiment in the game world. A GASP-based first-person character with all framework components attached. This is the single most important game asset — nearly every framework system interacts with it.


Architecture Overview

BP_HorrorPlayerCharacter (Character with GASP Animation Blueprint)
├── Components (auto-attached on spawn)
│   ├── CapsuleComponent (inherited)
│   ├── CameraComponent (first-person, head socket)
│   ├── CharacterMovementComponent (GASP — read-only)
│   ├── SkeletalMeshComponent (GASP — read-only)
│   │
│   ├── [02-player] BPC_HealthSystem            # 08 — Health, damage, death
│   ├── [02-player] BPC_StaminaSystem           # 09 — Sprint, action drain
│   ├── [02-player] BPC_StressSystem            # 10 — Psychological stress
│   ├── [02-player] BPC_MovementStateSystem     # 11 — Walk/Sprint/Crouch
│   ├── [02-player] BPC_HidingSystem            # 12 — Hide in lockers/beds
│   ├── [02-player] BPC_EmbodimentSystem        # 13 — First-person body
│   ├── [02-player] BPC_CameraStateLayer        # 14 — FOV/offset layers
│   ├── [02-player] BPC_PlayerMetricsTracker    # 15 — Accuracy, style
│   │
│   ├── [03-interaction] BPC_InteractionDetector # 16 — Raycast interact
│   │
│   ├── [04-inventory] BPC_InventorySystem      # 31 — Inventory grid
│   ├── [04-inventory] BPC_EquipmentSlotSystem  # 30 — Weapon/tool slots
│   ├── [04-inventory] BPC_ActiveItemSystem     # 26 — Quick-slot cycling
│   ├── [04-inventory] BPC_ConsumableSystem     # 28 — Use medkits/etc
│   ├── [04-inventory] BPC_KeyItemSystem        # 34 — Key items
│   ├── [04-inventory] BPC_JournalSystem        # 33 — Objectives
│   ├── [04-inventory] BPC_CollectibleTracker   # 27 — Collectibles found
│   ├── [04-inventory] BPC_DocumentArchiveSystem# 29 — Read documents
│   ├── [04-inventory] BPC_ItemCombineSystem    # 32 — Combine items
│   │
│   ├── [08-weapons] BPC_AmmoComponent          # 70 — Ammo pool
│   ├── [08-weapons] BPC_RecoilSystem           # 77 — Weapon recoil
│   ├── [08-weapons] BPC_HitReactionSystem      # 75 — Hit flinch
│   ├── [08-weapons] BPC_DamageReceptionSystem  # 72 — Receive damage
│   ├── [08-weapons] BPC_CombatFeedbackComponent# 71 — Hit markers
│   │
│   ├── [16-state] BPC_StateManager             # 130 — Action gating
│   │
│   ├── [07-narrative] BPC_NarrativeStateSystem # 58 — Narrative flags
│   ├── [07-narrative] BPC_ObjectiveSystem      # 59 — Active quests
│   └── [07-narrative] BPC_EndingAccumulator    # 68 — Ending tracker
│
├── Interfaces Implemented
│   ├── I_Damageable (take damage)
│   ├── I_Interactable (can be interacted with by NPCs)
│   └── I_Persistable (save/load state)

Creation Steps

Step 1 — Create Blueprint

Content Browser → Game/Characters/
  Right-click → Blueprint Class
  Parent Class: Your GASP Character (or Character if GASP is added to ABP only)
  Name: BP_HorrorPlayerCharacter

Step 2 — Add All Components

In the Components panel, add each component from the list above. Order doesn't matter for Blueprint components — they auto-initialize on BeginPlay.

Tip: Create a Blueprint function InitializeAllComponents called from Event BeginPlay and verify every component is valid before proceeding.

Step 3 — Configure GASP Integration

[GASP Animation Blueprint Setup]
   │
   ├─ Assign GASP AnimBP to SkeletalMeshComponent → Anim Class
   │    └─ Default: ABP_GASP (read-only, do not modify)
   │
   ├─ [GASP Notifies] (extend via Animation Notify overrides, NOT by editing GASP)
   │    └─ Add AnimNotify slots to GASP montages in your ABP child:
   │         ├─ Notify_Footstep → BPC_MovementStateSystem.OnFootstep()
   │         ├─ Notify_EnterAction → BPC_StateManager.EnterAction(Tag)
   │         ├─ Notify_ExitAction → BPC_StateManager.ExitAction()
   │         ├─ Notify_DamageApplied → BPC_DamageReceptionSystem.ReceiveDamage()
   │         └─ (etc — see animation-catalog.md for all 14 notifies)
   │
   └─ [Motion Matching Database]
        └─ Assign your motion matching pose search database
           (GASP handles locomotion blend — you provide the poses)

Step 4 — Wire Event BeginPlay

Event BeginPlay
   │
   ├─ Parent: Event BeginPlay (essential for GASP init)
   │
   ├─ [Validate All Components]
   │    ├─ For each BPC_ component:
   │    │    ├─ GetComponentByClass → IsValid? → Log
   │    │    └─ If invalid: FL_GameUtilities.LogError("Missing component: X")
   │    │
   │    └─ REQUIRED components (game cannot function without):
   │         ├─ BPC_HealthSystem → if missing, ERROR + disable input
   │         ├─ BPC_InventorySystem → if missing, ERROR
   │         ├─ BPC_StateManager → if missing, ERROR
   │         └─ BPC_InteractionDetector → if missing, ERROR
   │
   ├─ [Initialize Health]
   │    ├─ BPC_HealthSystem.SetMaxHealth(100.0)
   │    └─ BPC_HealthSystem.SetCurrentHealth(100.0)
   │
   ├─ [Initialize Stamina]
   │    ├─ BPC_StaminaSystem.SetMaxStamina(100.0)
   │    └─ BPC_StaminaSystem.SetCurrentStamina(100.0)
   │
   ├─ [Initialize Stress]
   │    ├─ BPC_StressSystem.SetCurrentStress(0.0)
   │    └─ BPC_StressSystem.SetStressDecayRate(1.0)  // per second in safe areas
   │
   ├─ [Initialize Movement]
   │    ├─ BPC_MovementStateSystem.SetMovementMode(Walking)
   │    └─ BPC_MovementStateSystem.SetPosture(Standing)
   │
   ├─ [Initialize Camera]
   │    ├─ BPC_CameraStateLayer.SetDefaultFOV(90.0)
   │    └─ BPC_EmbodimentSystem.SetVisibilityMode(FirstPerson)
   │
   ├─ [Initialize Inventory]
   │    ├─ BPC_InventorySystem.Initialize(GridWidth=6, GridHeight=4, MaxWeight=50.0)
   │    └─ BPC_EquipmentSlotSystem.Initialize()
   │         └─ Create slots: PrimaryWeapon, Tool, Armor (3 equipment slots)
   │
   ├─ [Initialize State Manager]
   │    ├─ BPC_StateManager.SetupGatingRules(DA_StateGatingTable)
   │    └─ BPC_StateManager.SetInitialState(Standing)
   │
   ├─ [Bind System Interconnections]
   │    │
   │    ├─ BPC_HealthSystem.OnHealthChanged → BPC_StateManager.UpdateVitalSignals
   │    ├─ BPC_HealthSystem.OnDeath → BPC_DeathHandlingSystem.HandleDeath
   │    ├─ BPC_StressSystem.OnStressTierChanged → BPC_CameraStateLayer.SetStressBlur
   │    ├─ BPC_StressSystem.OnStressTierChanged → SS_AudioManager.SetFloatParameter("Stress", value)
   │    ├─ BPC_StaminaSystem.OnStaminaDepleted → BPC_StateManager.ForcePushState(Exhausted)
   │    ├─ BPC_MovementStateSystem.OnModeChanged → BPC_StateManager.UpdateMovementState
   │    ├─ BPC_MovementStateSystem.OnFootstep → SS_AudioManager.PlayFootstep(SurfaceTag)
   │    ├─ BPC_HidingSystem.OnHideStateChanged → BPC_StateManager.SetOverlayState
   │    ├─ BPC_HidingSystem.OnHideStateChanged → SS_EnhancedInputManager.PushContext(Hiding)
   │    └─ (etc — any cross-system event binding)
   │
   └─ [Ready]
        └─ Broadcast OnPlayerReady
             └─ Other systems wait for this before querying player state

Step 5 — Wire Input Handling

[Event Graph — Input]

IA_Move (Axis2D) → CharacterMovementComponent.AddMovementInput
IA_Look  (Axis2D) → AddControllerYawInput + AddControllerPitchInput
   │
   ├─ [State Gating Check]
   │    └─ BPC_StateManager.IsActionPermitted(Move) ?
   │         ├─ True → process input
   │         └─ False → ignore input (blocked by state: cutscene, death, etc.)
   │
IA_Interact (Pressed) → BPC_InteractionDetector.Interact()
   └─ Also check: BPC_StateManager.IsActionPermitted(Interact)

IA_Sprint (Pressed) → BPC_StaminaSystem.StartSprint()
   └─ BPC_StateManager.IsActionPermitted(Sprint)? AND Stamina > 0?

IA_Sprint (Released) → BPC_StaminaSystem.StopSprint()

IA_Crouch (Pressed) → BPC_MovementStateSystem.ToggleCrouch()
   └─ BPC_StateManager.IsActionPermitted(Crouch)?

IA_Fire (Pressed) → BPC_ActiveItemSystem.UseEquippedItem()
   ├─ Routes to BP_Pistol_Held.UseItem() or BP_Shotgun_Held.UseItem()
   └─ BPC_StateManager.IsActionPermitted(Fire)?

IA_Fire (Released) → (cease fire for auto weapons)

IA_Aim (Pressed) → BPC_CameraStateLayer.SetLayer(Aiming)
   └─ FOV zooms to 55, slight camera offset forward

IA_Aim (Released) → BPC_CameraStateLayer.RemoveLayer(Aiming)
   └─ FOV returns to 90

IA_Reload (Pressed) → BPC_ActiveItemSystem.ReloadEquippedItem()
   └─ Routes to BP_Pistol_Held.Reload() or BP_Shotgun_Held.Reload()

IA_UseItem (Pressed) → BPC_ConsumableSystem.UseQuickSlotItem()
   └─ Uses whatever is in the quick-use slot (medkit, syringe, etc.)

IA_Flashlight (Pressed) → Toggle flashlight (if equipped in Tool slot)
   └─ Calls I_Toggleable.Toggle on BP_Flashlight_Held

IA_Jump (Pressed) → Character.Jump()
   └─ Also: BPC_ContextualTraversalSystem.TryVaultOrMantle()

IA_OpenWatch (Pressed) → SS_EnhancedInputManager.PushContext(WristwatchUI)
   ├─ SS_UIManager.ShowMenu(InventoryMenu)
   └─ Camera pans down to wristwatch

IA_PauseMenu (Pressed) → PC_HorrorController.OpenPauseMenu()

IA_QuickHeal (Pressed) → BPC_ConsumableSystem.QuickUse(MedKit)
   └─ Uses first available medkit in inventory

IA_QuickSlot1-8 → BPC_ActiveItemSystem.SetQuickSlot(SlotIndex)

Step 6 — Wire Component Communication

Each BPC_ component should communicate via Event Dispatchers, not direct references to other components. This keeps components decoupled.

Core Dispatcher Bindings (in Event BeginPlay):

[Damage Pipeline]
BPC_DamageReceptionSystem.OnDamageReceived
   ├─ → BPC_HealthSystem.ApplyDamage(Damage)
   ├─ → BPC_HitReactionSystem.PlayHitReaction(DamageInfo)
   ├─ → BPC_CombatFeedbackComponent.ShowHitMarker(DamageInfo)
   ├─ → WBP_ScreenEffectController.ShowDamageVignette()
   └─ → BPC_PlayerMetricsTracker.RecordDamageTaken(Damage)

[Health to State]
BPC_HealthSystem.OnHealthChanged(NewHealth, MaxHealth)
   ├─ → BPC_StateManager.UpdateVitalSignals()
   ├─ → WBP_DiegeticHUDFrame.UpdateHealthBar()
   └─ → SS_AudioManager.SetFloatParameter("HealthPercent", ratio)

[Health to Death]
BPC_HealthSystem.OnDeath(DeathCause, Killer)
   ├─ → BPC_DeathHandlingSystem.HandleDeath()
   └─ → BPC_StateManager.ForcePushState(Death)

[Stress System]
BPC_StressSystem.OnStressTierChanged(OldTier, NewTier)
   ├─ → PS_HorrorPlayerState.SetSanityTier(NewTier * 25)  // convert tier to 0-100
   ├─ → BPC_CameraStateLayer.SetStressBlur(NewTier)
   │    ├─ Calm → no blur
   │    ├─ Uneasy → slight peripheral blur
   │    ├─ Disturbed → moderate blur + vignette
   │    ├─ Breaking → heavy blur + tunnel vision
   │    └─ Catatonic → near-black screen
   ├─ → BPC_MemoryDriftSystem.SetIntensity(NewTier)
   │    └─ Triggers visual/audio hallucinations
   ├─ → SS_AudioManager.SetFloatParameter("StressTier", NewTier)
   └─ → BPC_StateManager.UpdateVitalSignals()

[Stamina System]
BPC_StaminaSystem.OnStaminaChanged(Current, Max)
   ├─ → WBP_DiegeticHUDFrame.UpdateStaminaBar()
   └─ → (If depleted) BPC_StateManager.ForcePushState(Exhausted)
        └─ Blocks Sprint action for 3 seconds

[Hiding System]
BPC_HidingSystem.OnEnterHiding(HidingSpot)
   ├─ → BPC_StateManager.SetOverlayState(Hiding)
   ├─ → SS_EnhancedInputManager.PushContext(Hiding)
   ├─ → BPC_CameraStateLayer.SetLayer(HidePeek)
   ├─ → BPC_StressSystem.StartStressDecay()  // stress decays while hidden
   └─ → WBP_DiegeticHUDFrame.ShowBreathHoldMeter()

BPC_HidingSystem.OnExitHiding()
   ├─ → BPC_StateManager.ClearOverlayState(Hiding)
   ├─ → SS_EnhancedInputManager.PopContext(Hiding)
   ├─ → BPC_CameraStateLayer.RemoveLayer(HidePeek)
   └─ → WBP_DiegeticHUDFrame.HideBreathHoldMeter()

[Inventory Events]
BPC_InventorySystem.OnItemAdded(ItemData, SlotIndex)
   ├─ → WBP_InventoryMenu.UpdateSlot(SlotIndex)
   ├─ → BPC_CollectibleTracker.CheckItem(ItemData) → if collectible, track it
   ├─ → WBP_NotificationToast.Show("Picked up: " + DisplayName)
   └─ → (If weapon) BPC_EquipmentSlotSystem.AutoEquipIfSlotEmpty(ItemData)

BPC_InventorySystem.OnItemRemoved(ItemData, SlotIndex)
   ├─ → WBP_InventoryMenu.ClearSlot(SlotIndex)
   └─ → (If equipped) BPC_EquipmentSlotSystem.UnequipSlot()

[Equipment Events]
BPC_EquipmentSlotSystem.OnItemEquipped(SlotTag, ItemData)
   ├─ → BPC_StateManager.SetEquipmentState(SlotTag, ItemData)
   ├─ → Spawn BP_*_Held actor (pistol, shotgun, flashlight)
   │    └─ Attach to hand socket on SkeletalMeshComponent
   └─ → BPC_ActiveItemSystem.SetCurrentItem(SlotTag, HeldActor)

[State Manager Events]
BPC_StateManager.OnStateChanged(OldState, NewState)
   ├─ → BPC_MovementStateSystem.SetStateRestrictions(NewState)
   │    └─ Death → no movement; Cutscene → no movement; etc.
   ├─ → WBP_HUDController.UpdateHUDActive(newState)
   │    └─ Hide HUD during cutscene/death; show during gameplay
   └─ → SS_EnhancedInputManager.SetContextVisibility(NewState)
        └─ Disable gameplay contexts during UI/Cutscene states

BPC_StateManager.OnActionDenied(ActionTag, BlockReason)
   └─ → WBP_InteractionPromptDisplay.ShowBlocked(ActionTag, BlockReason)
        └─ "Cannot fire — you are hiding"
        └─ "Cannot interact — cutscene playing"

Health, Stamina, Stress — The Core Survival Triad

These three systems work together to create the horror survival experience:

                        ┌──────────────────────┐
                        │   HEALTH (100 max)    │
                        │   ├─ Damage reduces   │
                        │   ├─ Medkit restores   │
                        │   └─ 0 HP = DEATH     │
                        └──────────┬───────────┘
                                   │ low health
                                   ▼
┌──────────────────────┐    ┌──────────────────────┐
│  STAMINA (100 max)    │    │  STRESS (0-100)      │
│  ├─ Sprint: -10/sec   │    │  ├─ Darkness: +2/sec │
│  ├─ Vault: -15/use    │    │  ├─ Enemy near: +5/s │
│  ├─ Combat: -5/action │    │  ├─ Void: +8/sec     │
│  └─ Regen: +5/sec     │    │  └─ Decay: -1/sec    │
│      (only when still)│    │      (safe areas)    │
└──────────┬───────────┘    └──────────┬───────────┘
           │ depleted                  │ high stress (75+)
           ▼                           ▼
    ┌──────────────┐          ┌──────────────────┐
    │  EXHAUSTED   │          │  HALLUCINATIONS  │
    │  ├─ Can't run│          │  ├─ False enemies │
    │  ├─ Walk slow│          │  ├─ Sounds/lights │
    │  └─ 3s cooldown│        │  └─ Screen distort│
    └──────────────┘          └──────────────────┘

Key Variables (Class Defaults)

Variable Type Default Purpose
MaxHealth Float 100.0 Set via BPC_HealthSystem in BeginPlay
MaxStamina Float 100.0 Set via BPC_StaminaSystem
MaxStress Float 100.0 Set via BPC_StressSystem
WalkSpeed Float 300.0 GASP default
SprintSpeed Float 600.0 GASP default
CrouchSpeed Float 150.0 GASP default
InteractionRange Float 300.0 How far the player can interact
bCanSprint Boolean true Disabled when exhausted or state-blocked
bIsFirstPerson Boolean true Horror game — no third-person toggle
DefaultFOV Float 90.0 Normal gameplay FOV
AimFOV Float 55.0 When aiming down sights
HidePeekFOV Float 70.0 When peeking from hiding

Blueprint Wiring Checklist

Components

  • Add BPC_HealthSystem (08)
  • Add BPC_StaminaSystem (09)
  • Add BPC_StressSystem (10)
  • Add BPC_MovementStateSystem (11)
  • Add BPC_HidingSystem (12)
  • Add BPC_EmbodimentSystem (13)
  • Add BPC_CameraStateLayer (14)
  • Add BPC_PlayerMetricsTracker (15)
  • Add BPC_InteractionDetector (16)
  • Add BPC_InventorySystem (31)
  • Add BPC_EquipmentSlotSystem (30)
  • Add BPC_ActiveItemSystem (26)
  • Add BPC_ConsumableSystem (28)
  • Add BPC_KeyItemSystem (34)
  • Add BPC_JournalSystem (33)
  • Add BPC_CollectibleTracker (27)
  • Add BPC_DocumentArchiveSystem (29)
  • Add BPC_ItemCombineSystem (32)
  • Add BPC_AmmoComponent (70)
  • Add BPC_RecoilSystem (77)
  • Add BPC_HitReactionSystem (75)
  • Add BPC_DamageReceptionSystem (72)
  • Add BPC_CombatFeedbackComponent (71)
  • Add BPC_StateManager (130)
  • Add BPC_NarrativeStateSystem (58)
  • Add BPC_ObjectiveSystem (59)
  • Add BPC_EndingAccumulator (68)

Event BeginPlay

  • Call parent BeginPlay
  • Validate all critical components → log errors if missing
  • Initialize Health, Stamina, Stress to max values
  • Initialize Inventory (6×4 grid, 50 weight)
  • Initialize Equipment Slots (PrimaryWeapon, Tool, Armor)
  • Initialize State Manager with DA_StateGatingTable
  • Bind all inter-component dispatchers (Health→Death, Stress→Blur, etc.)

Input

  • Bind IA_Move, IA_Look (always active unless state-blocked)
  • Bind IA_Interact (state-gated)
  • Bind IA_Sprint (stamina-gated + state-gated)
  • Bind IA_Crouch (state-gated)
  • Bind IA_Fire (state-gated + equipment-gated)
  • Bind IA_Aim (equipment-gated)
  • Bind IA_Reload (state-gated)
  • Bind IA_UseItem (state-gated)
  • Bind IA_Flashlight (state-gated)
  • Bind IA_Jump (state-gated)
  • Bind IA_OpenWatch (state-gated → pushes wristwatch context)
  • Bind IA_PauseMenu
  • Bind IA_QuickHeal
  • Bind IA_QuickSlot1-8
  • Every input check: BPC_StateManager.IsActionPermitted before processing

Notes for Expansion

  • GASP customization: Never edit GASP AnimBP directly. Create a child AnimBP and override/insert notifies. Add your own locomotion states (limping, crawling) as new GASP states.
  • Component order: Add components in dependency order if they have BeginPlay initialization dependencies. Health before DeathHandling; Inventory before Equipment.
  • Multiplayer: All health/stamina/stress mutations must be server-authoritative. Use HasAuthority() gates. Replicate with RepNotify.
  • Performance: If FPS drops, consider lazy-initializing non-critical components (CollectibleTracker, DocumentArchive, PlayerMetricsTracker).
  • Mod support: Keep all default values in a DA_PlayerConfig Data Asset (health, stamina, speed, FOV) so modders can override without touching BP.

BP_HorrorPlayerCharacter — The player pawn for Project Void. See GAMEINDEX.md for full game structure. See INDEX.md for all framework component specs.