# 11 — Movement State System (`BPC_MovementStateSystem`) ## Purpose Tracks the player's current movement mode and posture state. Acts as a central query point for other systems (animations, stamina, audio, camera) to react to how the player is moving. Does not control movement input — only reports and reacts to state changes. ## Dependencies - **Requires:** `FL_GameUtilities` (tag queries) - **Required By:** `ABP_GASP` (animations), `BPC_StaminaSystem` (regen blocking), `BPC_CameraStateLayer` (FOV changes), `BPC_AudioManager` (footstep type), `BPC_InteractionDetector` (range scaling) - **Engine/Plugin Requirements:** GameplayTags, GASP (ground/animation/strafing platform) ## Class Info | Property | Value | |----------|-------| | **Parent Class** | `ActorComponent` | | **Class Type** | Blueprint Component | | **Asset Path** | `Content/Framework/Player/BPC_MovementStateSystem` | | **Implements Interfaces** | None | --- ## 1. Enums ### `E_PostureState` | Value | Description | |-------|-------------| | `Standing = 0` | Full height, normal locomotion | | `Crouching = 1` | Reduced height, slower speed | | `Prone = 2` | Fully prone, crawling (horror immersion) | | `Sliding = 3` | Transient — while sliding downhill or under obstacles | | `Climbing = 4` | Ledge or ladder climbing | | `Vaulting = 5` | Transient — while vaulting over obstacles | ### `E_MovementMode` | Value | Description | |-------|-------------| | `Idle = 0` | Standing still | | `Walking = 1` | Slow, careful movement | | `Jogging = 2` | Normal movement speed | | `Sprinting = 3` | Fast movement, stamina drain | | `CrouchWalk = 4` | Slow crouch movement | | `Sneaking = 5` | Ultra-slow, near-silent movement (special) | ### `E_StanceTransition` | Value | Description | |-------|-------------| | `Instant = 0` | Immediate transition (no animation blend) | | `Smooth = 1` | Smooth blend over TransitionBlendTime | | `Forced = 2` | External force (knocked down, pushed) | --- ## 2. Structs ### `S_MovementSettings` | Field | Type | Description | |-------|------|-------------| | `MovementMode` | `E_MovementMode` | Which mode this applies to | | `MaxWalkSpeed` | `Float` | Max speed in this mode (cm/s) | | `Acceleration` | `Float` | Acceleration rate | | `Deceleration` | `Float` | Deceleration rate | | `GroundFriction` | `Float` | Friction modifier | | `bCanSprint` | `Boolean` | Can the player sprint from this mode? | | `bCanCrouch` | `Boolean` | Can the player crouch from this mode? | | `StaminaDrainMultiplier` | `Float` | Multiplier on stamina drain while in this mode | ### `S_FootstepProfile` | Field | Type | Description | |-------|------|-------------| | `SurfaceType` | `EPhysicalSurface` | Surface being stepped on | | `MovementMode` | `E_MovementMode` | Player's current movement mode | | `SoundSoft` | `SoundBase` | Footstep sound at low velocity | | `SoundHard` | `SoundBase` | Footstep sound at high velocity | | `VelocityThreshold` | `Float` | Speed at which to switch from Soft to Hard | | `Decal` | `MaterialInterface` | Footprint decal (mud, snow, blood) | --- ## 3. Variables ### Configuration (Instance Editable, Expose On Spawn) | Variable | Type | Default | Category | Description | |----------|------|---------|----------|-------------| | `MovementSettings` | `Map` | `all modes` | `Movement Config` | Speed/accel values per movement mode | | `TransitionBlendTime` | `Float` | `0.2` | `Movement Config` | Blend duration for smooth stance transitions | | `bApplyMovementPenalties` | `Boolean` | `true` | `Movement Config` | Allow stress/health to affect movement speed | | `CrouchHeight` | `Float` | `60.0` | `Movement Config` | Capsule half-height while crouching | | `ProneHeight` | `Float` | `30.0` | `Movement Config` | Capsule half-height while prone | | `StandingHeight` | `Float` | `96.0` | `Movement Config` | Capsule half-height while standing | | `bUseVelocityBasedFootsteps` | `Boolean` | `true` | `Movement Config` | Auto-select footstep sound based on velocity | | `DefaultFootstepProfile` | `S_FootstepProfile` | `-` | `Movement Config` | Fallback footstep when no surface match | ### Internal (Private / Protected, No Expose) | Variable | Type | Default | Category | Description | |----------|------|---------|----------|-------------| | `CurrentPosture` | `E_PostureState` | `Standing` | `Movement State` | Current posture | | `PreviousPosture` | `E_PostureState` | `Standing` | `Movement State` | Previous posture (for transition detection) | | `CurrentMovementMode` | `E_MovementMode` | `Idle` | `Movement State` | Current movement mode | | `PreviousMovementMode` | `E_MovementMode` | `Idle` | `Movement State` | Previous movement mode | | `bIsOnGround` | `Boolean` | `true` | `Movement State` | Whether the player is grounded | | `bIsMoving` | `Boolean` | `false` | `Movement State` | Whether the player is currently moving | | `CurrentSpeed` | `Float` | `0.0` | `Movement State` | Current character speed (cm/s) | | `bIsClimbing` | `Boolean` | `false` | `Movement State` | Whether currently climbing | | `LastValidFloorNormal` | `Vector` | `(0,0,1)` | `Movement State` | Last valid ground normal | | `CapsuleRef` | `UCapsuleComponent` | `None` | `Movement State` | Cached reference to capsule component | ### Replicated (if multiplayer) | Variable | Type | Condition | Description | |----------|------|-----------|-------------| | `CurrentPosture` | `E_PostureState` | `RepNotify` | Replicated posture state | | `CurrentMovementMode` | `E_MovementMode` | `RepNotify` | Replicated movement mode | --- ## 4. Functions ### Public Functions #### `SetMovementMode` → `void` - **Description:** Sets the current movement mode and applies corresponding movement settings to the CharacterMovementComponent. - **Parameters:** | Param | Type | Description | |-------|------|-------------| | `NewMode` | `E_MovementMode` | Desired movement mode | | `Transition` | `E_StanceTransition` | How to handle the transition | - **Blueprint Authority:** Server (if MP), Any (single-player) - **Flow:** 1. If NewMode == CurrentMovementMode: return 2. PreviousMovementMode = CurrentMovementMode 3. CurrentMovementMode = NewMode 4. Apply MovementSettings[NewMode] to CharacterMovementComponent 5. Fire OnMovementModeChanged 6. If transition is Forced: apply impulse or knockback 7. Notify ABP_GASP via interface or direct cast #### `SetPosture` → `void` - **Description:** Sets the current posture and adjusts capsule size accordingly. - **Parameters:** | Param | Type | Description | |-------|------|-------------| | `NewPosture` | `E_PostureState` | Desired posture | | `Transition` | `E_StanceTransition` | How to handle the transition | - **Flow:** 1. If NewPosture == CurrentPosture: return 2. If NewPosture == Prone and CurrentPosture == Standing: must go through Crouching first 3. PreviousPosture = CurrentPosture 4. CurrentPosture = NewPosture 5. Update capsule height based on NewPosture 6. Fire OnPostureChanged 7. Notify ABP_GASP #### `GetCurrentSpeedNormalised` → `Float [0.0 - 1.0]` - **Description:** Returns speed as fraction of CurrentMovementMode's MaxWalkSpeed. - **Flow:** Return CurrentSpeed / MovementSettings[CurrentMovementMode].MaxWalkSpeed #### `CanTransitionToPosture` → `Boolean` - **Parameters:** | Param | Type | Description | |-------|------|-------------| | `TargetPosture` | `E_PostureState` | Desired posture | - **Flow:** 1. Check ceiling clearance for upright transitions 2. Check if MovementSettings allows this posture from current mode 3. Return clearance OK and setting allows #### `SetSprinting` → `void` - **Parameters:** | Param | Type | Description | |-------|------|-------------| | `bSprinting` | `Boolean` | Whether to sprint | - **Flow:** 1. If bSprinting and CanSprint(): SetMovementMode(Sprinting) 2. If !bSprinting: restore previous movement mode 3. Fire OnSprintStateChanged #### `SetCrouching` → `void` - **Parameters:** | Param | Type | Description | |-------|------|-------------| | `bCrouching` | `Boolean` | Whether to crouch | - **Flow:** 1. If bCrouching: SetPosture(Crouching), SetMovementMode(CrouchWalk) 2. If !bCrouching: SetPosture(Standing), restore previous walk mode #### `ApplyMovementPenalty` → `void` - **Parameters:** | Param | Type | Description | |-------|------|-------------| | `Multiplier` | `Float` | Speed multiplier [0.0 - 1.0] | | `Duration` | `Float` | How long the penalty lasts | | `PenaltyTag` | `GameplayTag` | Identifier (e.g. Injury, Fear, SlowEffect) | - **Flow:** 1. Modify current MovementSettings[CurrentMovementMode].MaxWalkSpeed *= Multiplier 2. Start timer for Duration 3. On timer end: restore original MaxWalkSpeed for this mode ### Protected / Private Functions #### `OnMovementUpdated (Tick)` → `void` - **Description:** Called each tick. Updates speed tracking, detects movement start/stop, checks ground state. - **Flow:** 1. Get velocity from CharacterMovementComponent 2. CurrentSpeed = velocity.Size() 3. OldMoving = bIsMoving 4. bIsMoving = CurrentSpeed > 10.0 5. If bIsMoving != OldMoving: fire OnMovementStart or OnMovementStop 6. Check bIsOnGround from movement component #### `CalculateFootstep` → `S_FootstepProfile` - **Description:** Selects the correct footstep sound based on surface and movement mode. - **Flow:** 1. Perform line trace from foot location downward 2. Get surface type from physical material 3. Look up S_FootstepProfile matching SurfaceType and CurrentMovementMode 4. If no match: return DefaultFootstepProfile --- ## 5. Event Dispatchers | Dispatcher | Parameters | Bind Access | Description | |------------|-----------|-------------|-------------| | `OnMovementModeChanged` | `E_MovementMode OldMode`, `E_MovementMode NewMode` | `Public` | Fired when movement mode changes | | `OnPostureChanged` | `E_PostureState OldPosture`, `E_PostureState NewPosture` | `Public` | Fired when posture changes | | `OnMovementStart` | `none` | `Public` | Fired when the player starts moving from idle | | `OnMovementStop` | `none` | `Public` | Fired when the player stops moving | | `OnSprintStateChanged` | `bool bIsSprinting` | `Public` | Fired when sprint state toggles | | `OnJumped` | `none` | `Public` | Fired when the player jumps | | `OnLanded` | `float FallVelocity` | `Public` | Fired when the player lands after a fall | | `OnClimbStarted` | `AActor ClimbableActor` | `Public` | Fired when climbing begins | | `OnClimbEnded` | `none` | `Public` | Fired when climbing ends | | `OnFootstep` | `E_MovementMode Mode`, `EPhysicalSurface Surface` | `Public` | Fired on each footstep for audio | --- ## 6. Overridden Events / Custom Events ### Event: `BeginPlay` - **Description:** Initialises state, caches references, binds to owner's character movement events. - **Flow:** 1. Get Owner as Character 2. Cache CharacterMovementComponent and CapsuleComponent 3. Bind to Character's OnJumped and OnLanded delegates 4. Set initial MovementMode = Idle, Posture = Standing 5. Apply default MovementSettings to movement component ### Event: `Tick (if enabled)` - **Description:** Updates speed tracking and detects transitions. - **Flow:** 1. Call OnMovementUpdated 2. Check for automatic posture transitions (e.g., falling -> standing on land) ### Custom Event: `OnTakeDamageAffectsMovement` - **Description:** Listener bound to BPC_HealthSystem.OnDamageTaken. - **Flow:** 1. If damage was significant (> 20% health): apply brief movement penalty 2. Penalty severity scales with damage amount --- ## 7. Blueprint Graph Logic Flow ```mermaid flowchart TD A[SetMovementMode called] --> B{Valid transition?} B -->|No| C[Return] B -->|Yes| D[Store PreviousMode] D --> E[Set CurrentMode = NewMode] E --> F[Apply MovementSettings to CharMoveComp] F --> G[Fire OnMovementModeChanged] G --> H{NewMode == Sprinting?} H -->|Yes| I[Notify BPC_StaminaSystem: StartContinuousDrain] H -->|No| J{PreviousMode == Sprinting?} J -->|Yes| K[Notify BPC_StaminaSystem: StopContinuousDrain] J -->|No| L[Update ABP_GASP blend values] I --> L K --> L ``` --- ## 8. Communication Matrix | Who Talks | How | What Is Sent | |-----------|-----|-------------| | `BPC_MovementStateSystem` | `Dispatcher` | `OnMovementModeChanged` -> `ABP_GASP`, `BPC_StaminaSystem`, `BPC_CameraStateLayer` | | `BPC_MovementStateSystem` | `Dispatcher` | `OnPostureChanged` -> `ABP_GASP`, `BPC_InteractionDetector`, `BP_AudioManager` | | `BPC_MovementStateSystem` | `Dispatcher` | `OnFootstep` -> `BP_AudioManager` (footstep SFX) | | `BPC_MovementStateSystem` | `Dispatcher` | `OnJumped` / `OnLanded` -> `BPC_StaminaSystem` (landing drain) | | `BPC_MovementStateSystem` | `Dispatcher` | `OnSprintStateChanged` -> `BPC_StaminaSystem`, `BPC_CameraStateLayer` (FOV) | | `External (Input)` | `Direct` | `PC_PlayerController` calls SetMovementMode / SetPosture | | `BPC_MovementStateSystem` | `Listener` | Binds to `BPC_HealthSystem.OnDamageTaken` for injury penalties | --- ## 9. Validation / Testing Checklist - [ ] Movement mode changes correctly apply speed/accel values to CharacterMovementComponent - [ ] Posture changes correctly adjust capsule height and collision - [ ] Prone requires crouch intermediate transition - [ ] Sprinting auto-stops when stamina hits 0 (via stamina listener) - [ ] Movement penalties correctly modify MaxWalkSpeed and restore after duration - [ ] OnMovementStart/OnMovementStop fire correctly at speed thresholds - [ ] Footstep profile selection works for all surface types - [ ] Edge case: Forced transition (knockback) applies impulse regardless of state - [ ] Edge case: CanTransitionToPosture returns false when ceiling is too low - [ ] Edge case: Rapid mode switching does not cause animation glitches (blend time enforced) --- ## 10. Reuse Notes - This component is the central "movement oracle" — other systems query posture/mode instead of polling the CharacterMovementComponent. - Footstep profiles should be defined in a Data Asset (DA_FootstepProfileTable) for easy content team iteration. - The component does NOT handle input — that remains in PC_PlayerController. - For AI characters, a simplified version can expose only Walking and Sprinting modes with no posture system. - GASP integration: set GASP-specific variables (bStrafing, bSprinting) in the AnimationBlueprint on each mode change. --- *Blueprint Spec: Movement State System. Conforms to TEMPLATE.md v1.0 — part of the UE5 Modular Game Framework.*