323 lines
14 KiB
Markdown
323 lines
14 KiB
Markdown
# 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<E_MovementMode, S_MovementSettings>` | `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.* |