tengri/Content/Movement/TDD.md

1305 lines
41 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# Movement System - Technical Documentation (Stage 9 Refactored)
## Обзор
Детерминированная система движения для 3D-платформера, построенная на принципе **Functional Core, Imperative Shell**. Система обеспечивает математически предсказуемое поведение через композицию чистых функциональных модулей, с точной классификацией поверхностей, swept collision detection и ground snapping.
**Версия:** Stage 9 (Post-Refactoring)
**Архитектурный паттерн:** Pipeline Processor + Pure Function Libraries
**Статус:** Production Ready ✅
---
## Архитектурные принципы
### Core Design Philosophy
1. **Functional Core, Imperative Shell**
- Pure business logic в BFL_* модулях
- Imperative framework integration в AC_Movement
2. **Immutable State Transformation**
- `S_MovementState → ProcessMovement() → S_MovementState`
- Никогда не мутируем входящее состояние
3. **Pipeline Processing**
- Четкие последовательные фазы обработки
- Каждая фаза читает результаты предыдущей
4. **Separation of Concerns**
- AC_Movement: координация и framework integration
- BFL_MovementProcessor: бизнес-логика движения
- BFL_*: специализированные подсистемы
5. **Data-Oriented Design**
- Явные структуры данных (S_MovementState, S_MovementInput)
- Функции оперируют данными, не прячут их
---
## Компоненты системы
### 1. AC_Movement (Component - Imperative Shell)
**Роль:** Thin orchestration layer между UE Actor system и функциональной логикой
**Ответственности:**
- Lifecycle management (инициализация, cleanup)
- Component references (CapsuleComponent, DebugHUD)
- State storage (CurrentMovementState)
- Framework integration (SetActorLocation, SetActorRotation)
- Debug visualization coordination
**Ключевые методы:**
```typescript
// Инициализация системы
InitializeMovementSystem(
CapsuleComponentRef: CapsuleComponent | null,
DebugHUDComponentRef: AC_DebugHUD | null
): void
// Обработка движения (главная точка входа)
ProcessMovementInput(
InputVector: Vector,
DeltaTime: Float
): void
// Debug
UpdateDebugPage(): void
```
**Приватные поля:**
```typescript
CurrentMovementState: S_MovementState // Текущее состояние
Config: DA_MovementConfig // Конфигурация
AngleThresholdsRads: S_AngleThresholds // Кэшированные пороги в радианах
CapsuleComponent: CapsuleComponent | null // Ссылка на капсулу
DebugHUDComponent: AC_DebugHUD | null // Ссылка на debug HUD
IsInitialized: boolean // Флаг инициализации
```
**Размер:** ~230 LOC (↓ 62% от original)
---
### 2. BFL_MovementProcessor (Core - Functional Heart)
**Роль:** Unified movement processing pipeline - центральная точка всей логики движения
**Ответственности:**
- Orchestration всех подсистем в правильном порядке
- State transformation (CurrentState + Input → NextState)
- Phase sequencing и data flow
- Integration между subsystems
**Главный метод:**
```typescript
ProcessMovement(
CurrentState: S_MovementState,
Input: S_MovementInput,
IsShowVisualDebug: boolean = false
): S_MovementState
```
**Processing Pipeline (6 фаз):**
```typescript
// PHASE 1: INPUT & ROTATION
├─ Calculate input magnitude
└─ Update character rotation (BFL_RotationController)
// PHASE 2: GROUND DETECTION
├─ Check ground with trace (BFL_GroundProbe)
├─ Determine IsGrounded
└─ Classify surface type (BFL_SurfaceClassifier)
// PHASE 3: PHYSICS CALCULATION
├─ Calculate ground velocity (BFL_Kinematics) [if grounded]
OR Apply air friction (BFL_Kinematics) [if airborne]
├─ Apply gravity (BFL_Kinematics)
└─ Calculate horizontal speed
// PHASE 4: MOVEMENT APPLICATION (Sweep)
├─ Convert velocity to delta
├─ Perform swept collision (BFL_CollisionResolver)
└─ Calculate slide vector if blocked
// PHASE 5: GROUND SNAPPING
└─ Snap to ground if conditions met (BFL_GroundProbe)
// PHASE 6: STATE DETERMINATION
└─ Determine movement state (BFL_MovementStateMachine)
// RETURN: Complete new S_MovementState
```
**Вспомогательные методы:**
```typescript
CreateInitialState(
Location: Vector,
Rotation: Rotator
): S_MovementState
```
**Purity:** Impure (из-за collision traces), но deterministic
**Размер:** ~260 LOC
---
### 3. BFL_Kinematics (Physics Library)
**Роль:** Pure physics calculations для движения
**Ключевые методы:**
```typescript
// Ground movement с acceleration
CalculateGroundVelocity(
CurrentVelocity: Vector,
InputVector: Vector,
DeltaTime: Float,
Config: DA_MovementConfig
): Vector
// Friction (deceleration)
CalculateFriction(
CurrentVelocity: Vector,
DeltaTime: Float,
Config: DA_MovementConfig
): Vector
// Gravity application
CalculateGravity(
CurrentVelocity: Vector,
IsGrounded: boolean,
Config: DA_MovementConfig
): Vector
// Horizontal speed query
GetHorizontalSpeed(Velocity: Vector): Float
```
**Характеристики:**
- ✅ Pure functions
- ✅ VInterpTo для smooth movement
- ✅ Frame-rate independent (uses DeltaTime)
---
### 4. BFL_CollisionResolver (Collision Library)
**Роль:** Swept collision detection и surface sliding
**Ключевые методы:**
```typescript
// Главный swept trace
PerformSweep(
StartLocation: Vector,
DesiredDelta: Vector,
CapsuleComponent: CapsuleComponent | null,
Config: DA_MovementConfig,
DeltaTime: Float,
IsShowVisualDebug: boolean
): S_SweepResult
// Surface sliding projection
ProjectOntoSurface(
MovementDelta: Vector,
SurfaceNormal: Vector
): Vector
// Slide vector calculation
CalculateSlideVector(
SweepResult: S_SweepResult,
OriginalDelta: Vector,
StartLocation: Vector
): Vector
// Adaptive step size для swept trace
CalculateStepSize(
Velocity: Vector,
DeltaTime: Float,
Config: DA_MovementConfig
): Float
```
**Характеристики:**
- ⚠️ Impure (world traces)
- ✅ Deterministic stepping
- ✅ Tunneling protection
- ✅ Adaptive precision
---
### 5. BFL_GroundProbe (Ground Detection Library)
**Роль:** Ground detection, snapping, surface queries
**Ключевые методы:**
```typescript
// Ground detection trace
CheckGround(
CharacterLocation: Vector,
CapsuleComponent: CapsuleComponent | null,
AngleThresholdsRads: S_AngleThresholds,
Config: DA_MovementConfig,
IsShowVisualDebug: boolean
): HitResult
// Ground snapping calculation
CalculateSnapLocation(
CurrentLocation: Vector,
GroundHit: HitResult,
CapsuleComponent: CapsuleComponent | null,
SnapThreshold: Float
): Vector
// Snapping condition check
ShouldSnapToGround(
CurrentVelocityZ: Float,
GroundHit: HitResult,
IsGrounded: boolean
): boolean
// Surface type query
GetSurfaceType(
GroundHit: HitResult,
AngleThresholdsRads: S_AngleThresholds
): E_SurfaceType
```
**Характеристики:**
- ⚠️ Impure (LineTraceByChannel)
- ✅ Separate snapping logic
- ✅ Clear condition checking
---
### 6. BFL_RotationController (Rotation Library)
**Роль:** Character rotation toward movement direction
**Ключевые методы:**
```typescript
// Calculate target yaw from direction
CalculateTargetYaw(MovementDirection: Vector): Float
// Calculate full target rotation
CalculateTargetRotation(MovementDirection: Vector): Rotator
// Smooth rotation interpolation
InterpolateRotation(
CurrentRotation: Rotator,
TargetRotation: Rotator,
RotationSpeed: Float,
DeltaTime: Float,
MinSpeedForRotation: Float,
CurrentSpeed: Float
): S_RotationResult
// Convenience method
UpdateRotation(
CurrentRotation: Rotator,
MovementDirection: Vector,
Config: DA_MovementConfig,
DeltaTime: Float,
CurrentSpeed: Float
): S_RotationResult
```
**Характеристики:**
- ✅ Pure functions
- ✅ Wraparound handling (180°/-180°)
- ✅ Min speed threshold
---
### 7. BFL_MovementStateMachine (State Machine)
**Роль:** Determine movement state from context
**Ключевые методы:**
```typescript
// Main state determination
DetermineState(Context: S_MovementContext): E_MovementState
// Internal helpers
private DetermineAirborneState(Context: S_MovementContext): E_MovementState
private DetermineGroundedState(Context: S_MovementContext): E_MovementState
```
**State Priority Logic:**
```
1. IsGrounded?
├─ Yes: Check surface type
│ ├─ SteepSlope → Sliding
│ ├─ Wall/Ceiling → Blocked
│ └─ Walkable → Check input
│ ├─ Has input & speed > 1.0 → Walking
│ └─ Else → Idle
└─ No → Airborne
```
**Характеристики:**
- ✅ Pure FSM logic
- ✅ Priority-based transitions
- ✅ Clear state rules
---
### 8. BFL_SurfaceClassifier (Surface Classification)
**Роль:** Classify surface based on normal angle
**Ключевые методы:**
```typescript
// Main classification
Classify(
SurfaceNormal: Vector,
AngleThresholdsRads: S_AngleThresholds
): E_SurfaceType
// Type checking helpers
IsWalkable(surfaceType: E_SurfaceType): boolean
IsSteep(surfaceType: E_SurfaceType): boolean
IsWall(surfaceType: E_SurfaceType): boolean
IsCeiling(surfaceType: E_SurfaceType): boolean
IsNone(surfaceType: E_SurfaceType): boolean
```
**Classification Rules:**
```
Surface Angle → Type
─────────────────────
≤ Walkable → Walkable (0°-50°)
≤ SteepSlope → SteepSlope (50°-85°)
≤ Wall → Wall (85°-95°)
> Wall → Ceiling (95°-180°)
```
**Характеристики:**
- ✅ Pure functions
- ✅ Angle-based classification
- ✅ Type-safe queries
---
## Структуры данных
### S_MovementState (Complete State Snapshot)
**Роль:** Immutable snapshot всего состояния движения
```typescript
interface S_MovementState {
// ═══════════════════════════════════════════════════════
// TRANSFORM
// ═══════════════════════════════════════════════════════
Location: Vector // World location
Rotation: Rotator // Yaw rotation
// ═══════════════════════════════════════════════════════
// VELOCITY & PHYSICS
// ═══════════════════════════════════════════════════════
Velocity: Vector // Current velocity (cm/s)
Speed: Float // Horizontal speed (cm/s)
// ═══════════════════════════════════════════════════════
// GROUND STATE
// ═══════════════════════════════════════════════════════
IsGrounded: boolean // On walkable ground?
GroundHit: HitResult // Ground trace result
SurfaceType: E_SurfaceType // Current surface classification
// ═══════════════════════════════════════════════════════
// COLLISION STATE
// ═══════════════════════════════════════════════════════
IsBlocked: boolean // Blocked by collision?
CollisionCount: number // Collision checks this frame
// ═══════════════════════════════════════════════════════
// ROTATION STATE
// ═══════════════════════════════════════════════════════
IsRotating: boolean // Currently rotating?
RotationDelta: Float // Remaining angular distance (degrees)
// ═══════════════════════════════════════════════════════
// MOVEMENT STATE
// ═══════════════════════════════════════════════════════
MovementState: E_MovementState // Current FSM state
InputMagnitude: Float // Input magnitude (0-1)
}
```
**Usage Pattern:**
```typescript
// Immutable transformation
const newState = BFL_MovementProcessor.ProcessMovement(
currentState, // Never modified
input,
debugFlag
);
// Apply to actor
this.GetOwner().SetActorLocation(newState.Location);
this.GetOwner().SetActorRotation(newState.Rotation);
// Store for next frame
this.CurrentMovementState = newState;
```
---
### S_MovementInput (Input Encapsulation)
**Роль:** All data needed для movement processing
```typescript
interface S_MovementInput {
InputVector: Vector // Player input (normalized XY)
DeltaTime: Float // Frame delta time (seconds)
CapsuleComponent: CapsuleComponent | null // Collision capsule
Config: DA_MovementConfig // Movement config
AngleThresholdsRads: S_AngleThresholds // Surface thresholds (radians)
}
```
**Usage:**
```typescript
const input: S_MovementInput = {
InputVector: playerInput,
DeltaTime: deltaTime,
CapsuleComponent: this.CapsuleComponent,
Config: this.Config,
AngleThresholdsRads: this.AngleThresholdsRads
};
const newState = BFL_MovementProcessor.ProcessMovement(
this.CurrentMovementState,
input,
this.DebugHUDComponent?.ShowVisualDebug ?? false
);
```
---
### S_MovementContext (State Machine Input)
**Роль:** Context для state determination
```typescript
interface S_MovementContext {
IsGrounded: boolean // On walkable ground?
SurfaceType: E_SurfaceType // Surface classification
InputMagnitude: Float // Input strength (0-1)
CurrentSpeed: Float // Horizontal speed (cm/s)
VerticalVelocity: Float // Z velocity (cm/s)
IsBlocked: boolean // Blocked by collision?
}
```
---
### DA_MovementConfig (Configuration Asset)
**Роль:** Centralized movement constants
```typescript
class DA_MovementConfig extends PrimaryDataAsset {
// ═══════════════════════════════════════════════════════
// MOVEMENT PHYSICS
// ═══════════════════════════════════════════════════════
readonly MaxSpeed: Float = 800.0 // Max horizontal speed (cm/s)
readonly Acceleration: Float = 10.0 // VInterpTo acceleration rate
readonly Friction: Float = 8.0 // VInterpTo friction rate
readonly Gravity: Float = 980.0 // Gravity (cm/s²)
// ═══════════════════════════════════════════════════════
// SURFACE DETECTION
// ═══════════════════════════════════════════════════════
readonly AngleThresholdsDegrees: S_AngleThresholds = {
Walkable: 50.0, // ≤50° = walkable
SteepSlope: 85.0, // ≤85° = steep slope
Wall: 95.0 // ≤95° = wall
}
// ═══════════════════════════════════════════════════════
// COLLISION SETTINGS
// ═══════════════════════════════════════════════════════
readonly GroundTraceDistance: Float = 50.0 // Ground detection distance
readonly MinStepSize: Float = 1.0 // Min sweep step size
readonly MaxStepSize: Float = 50.0 // Max sweep step size
readonly MaxCollisionChecks: Float = 25 // Max checks per frame
// ═══════════════════════════════════════════════════════
// CHARACTER ROTATION
// ═══════════════════════════════════════════════════════
RotationSpeed: Float = 360.0 // Rotation speed (deg/s)
MinSpeedForRotation: Float = 50.0 // Min speed to rotate
ShouldRotateToMovement: boolean = true // Enable rotation
}
```
---
### Enums
```typescript
// Movement FSM states
enum E_MovementState {
Idle = 'Idle', // Stationary on ground
Walking = 'Walking', // Moving on ground
Airborne = 'Airborne', // In the air
Sliding = 'Sliding', // Sliding on steep slope
Blocked = 'Blocked' // Blocked by collision
}
// Surface classification
enum E_SurfaceType {
None = 'None', // No ground contact
Walkable = 'Walkable', // Normal walking ≤50°
SteepSlope = 'SteepSlope', // Sliding 50°-85°
Wall = 'Wall', // Collision 85°-95°
Ceiling = 'Ceiling' // Overhead >95°
}
```
---
## Data Flow Diagram
```
┌──────────────────────────────────────────────────────────────┐
│ AC_Movement │
│ (Imperative Shell) │
├──────────────────────────────────────────────────────────────┤
│ │
│ ProcessMovementInput(InputVector, DeltaTime) │
│ │ │
│ ▼ │
│ ┌────────────────────────┐ │
│ │ Prepare S_MovementInput│ │
│ └────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌─────────────────────────────────────┐ │
│ │ BFL_MovementProcessor │ │
│ │ .ProcessMovement() │ │
│ │ │ │
│ │ ┌─────────────────────────────┐ │ │
│ │ │ PHASE 1: Input & Rotation │ │ │
│ │ │ • Calculate input magnitude │ │ │
│ │ │ • BFL_RotationController │ │ │
│ │ └─────────────────────────────┘ │ │
│ │ │ │ │
│ │ ┌─────────▼───────────────────┐ │ │
│ │ │ PHASE 2: Ground Detection │ │ │
│ │ │ • BFL_GroundProbe │ │ │
│ │ │ • BFL_SurfaceClassifier │ │ │
│ │ └─────────────────────────────┘ │ │
│ │ │ │ │
│ │ ┌─────────▼───────────────────┐ │ │
│ │ │ PHASE 3: Physics │ │ │
│ │ │ • BFL_Kinematics │ │ │
│ │ │ - Ground velocity / Friction│ │ │
│ │ │ - Gravity │ │ │
│ │ └─────────────────────────────┘ │ │
│ │ │ │ │
│ │ ┌─────────▼───────────────────┐ │ │
│ │ │ PHASE 4: Movement (Sweep) │ │ │
│ │ │ • BFL_CollisionResolver │ │ │
│ │ │ - Perform sweep │ │ │
│ │ │ - Calculate slide │ │ │
│ │ └─────────────────────────────┘ │ │
│ │ │ │ │
│ │ ┌─────────▼───────────────────┐ │ │
│ │ │ PHASE 5: Ground Snapping │ │ │
│ │ │ • BFL_GroundProbe │ │ │
│ │ └─────────────────────────────┘ │ │
│ │ │ │ │
│ │ ┌─────────▼───────────────────┐ │ │
│ │ │ PHASE 6: State Determination│ │ │
│ │ │ • BFL_MovementStateMachine │ │ │
│ │ └─────────────────────────────┘ │ │
│ │ │ │ │
│ │ ┌─────────▼───────────────────┐ │ │
│ │ │ Return S_MovementState │ │ │
│ │ └─────────────────────────────┘ │ │
│ └─────────────────────────────────────┘ │
│ │ │
│ ▼ │
│ ┌────────────────────────┐ │
│ │ Apply to Actor │ │
│ │ • SetActorLocation() │ │
│ │ • SetActorRotation() │ │
│ └────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────┘
```
---
## Processing Pipeline Details
### Phase 1: Input & Rotation
```typescript
// Calculate input strength
const inputMagnitude = VectorLength(InputVector);
// Update rotation
const rotationResult = BFL_RotationController.UpdateRotation(
CurrentState.Rotation,
InputVector,
Config,
DeltaTime,
CurrentState.Speed
);
```
**Output:** `rotationResult.Rotation`, `rotationResult.IsRotating`
---
### Phase 2: Ground Detection
```typescript
// Perform ground trace
const groundHit = BFL_GroundProbe.CheckGround(
CurrentState.Location,
CapsuleComponent,
AngleThresholdsRads,
Config
);
// Determine ground state
const isGrounded = groundHit.BlockingHit;
// Classify surface
const surfaceType = BFL_GroundProbe.GetSurfaceType(
groundHit,
AngleThresholdsRads
);
```
**Output:** `groundHit`, `isGrounded`, `surfaceType`
---
### Phase 3: Physics Calculation
```typescript
let newVelocity = CurrentState.Velocity;
// Ground movement OR air friction
if (IsWalkable(surfaceType) && isGrounded) {
newVelocity = BFL_Kinematics.CalculateGroundVelocity(
newVelocity,
InputVector,
DeltaTime,
Config
);
} else {
newVelocity = BFL_Kinematics.CalculateFriction(
newVelocity,
DeltaTime,
Config
);
}
// Apply gravity
newVelocity = BFL_Kinematics.CalculateGravity(
newVelocity,
isGrounded,
Config
);
// Calculate speed
const newSpeed = BFL_Kinematics.GetHorizontalSpeed(newVelocity);
```
**Output:** `newVelocity`, `newSpeed`
---
### Phase 4: Movement Application (Sweep)
```typescript
// Convert velocity to displacement
const desiredDelta = newVelocity * DeltaTime;
// Perform swept collision
const sweepResult = BFL_CollisionResolver.PerformSweep(
CurrentState.Location,
desiredDelta,
CapsuleComponent,
Config,
DeltaTime,
IsShowVisualDebug
);
let finalLocation = sweepResult.Location;
// Handle collision sliding
if (sweepResult.Blocked) {
const slideVector = BFL_CollisionResolver.CalculateSlideVector(
sweepResult,
desiredDelta,
CurrentState.Location
);
// Apply slide if valid
if (VectorLength(slideVector) > 0.5 &&
Dot(Normal(slideVector), sweepResult.Hit.ImpactNormal) >= -0.1) {
finalLocation = sweepResult.Location + slideVector;
}
}
```
**Output:** `finalLocation`, `sweepResult`
---
### Phase 5: Ground Snapping
```typescript
if (BFL_GroundProbe.ShouldSnapToGround(
newVelocity.Z,
groundHit,
isGrounded
)) {
finalLocation = BFL_GroundProbe.CalculateSnapLocation(
finalLocation,
groundHit,
CapsuleComponent,
Config.GroundTraceDistance
);
}
```
**Output:** `finalLocation` (potentially snapped)
---
### Phase 6: State Determination
```typescript
const movementState = BFL_MovementStateMachine.DetermineState({
IsGrounded: isGrounded,
SurfaceType: surfaceType,
InputMagnitude: inputMagnitude,
CurrentSpeed: newSpeed,
VerticalVelocity: newVelocity.Z,
IsBlocked: sweepResult.Blocked
});
```
**Output:** `movementState` (E_MovementState)
---
### Final State Construction
```typescript
return {
Location: finalLocation,
Rotation: rotationResult.Rotation,
Velocity: newVelocity,
Speed: newSpeed,
IsGrounded: isGrounded,
GroundHit: groundHit,
SurfaceType: surfaceType,
IsBlocked: sweepResult.Blocked,
CollisionCount: sweepResult.CollisionCount,
IsRotating: rotationResult.IsRotating,
RotationDelta: rotationResult.RemainingDelta,
MovementState: movementState,
InputMagnitude: inputMagnitude
};
```
---
## API Reference
### AC_Movement
#### InitializeMovementSystem()
```typescript
InitializeMovementSystem(
CapsuleComponentRef: CapsuleComponent | null = null,
DebugHUDComponentRef: AC_DebugHUD | null = null
): void
```
**Описание:** Инициализирует систему движения
**Эффекты:**
- Sets `IsInitialized = true`
- Converts angle thresholds degrees → radians
- Creates initial movement state
- Registers debug page if HUD provided
**Пример:**
```typescript
this.MovementComponent.InitializeMovementSystem(
this.CharacterCapsule,
this.DebugHUDComponent
);
```
---
#### ProcessMovementInput()
```typescript
ProcessMovementInput(
InputVector: Vector,
DeltaTime: Float
): void
```
**Описание:** Main movement processing entry point
**Параметры:**
- `InputVector` - Camera-relative movement input (normalized)
- `DeltaTime` - Frame delta time (seconds)
**Flow:**
1. Constructs S_MovementInput
2. Calls BFL_MovementProcessor.ProcessMovement()
3. Applies resulting Location and Rotation to actor
**Пример:**
```typescript
// In EventTick
this.MovementComponent.ProcessMovementInput(
this.CalculateMovementInput(),
DeltaSeconds
);
```
---
### BFL_MovementProcessor
#### ProcessMovement()
```typescript
ProcessMovement(
CurrentState: S_MovementState,
Input: S_MovementInput,
IsShowVisualDebug: boolean = false
): S_MovementState
```
**Описание:** Unified movement processing - executes all 6 phases
**Параметры:**
- `CurrentState` - Current movement state (immutable)
- `Input` - Movement input data
- `IsShowVisualDebug` - Show debug traces in world
**Возвращает:** New complete movement state
**Purity:** Impure (collision traces), but deterministic
**Пример:**
```typescript
const newState = BFL_MovementProcessor.ProcessMovement(
this.CurrentMovementState,
{
InputVector: inputVector,
DeltaTime: deltaTime,
CapsuleComponent: this.CapsuleComponent,
Config: this.Config,
AngleThresholdsRads: this.AngleThresholdsRads
},
this.ShowDebug
);
// Apply results
this.GetOwner().SetActorLocation(newState.Location);
this.GetOwner().SetActorRotation(newState.Rotation);
this.CurrentMovementState = newState;
```
---
#### CreateInitialState()
```typescript
CreateInitialState(
Location: Vector,
Rotation: Rotator
): S_MovementState
```
**Описание:** Creates initial movement state with defaults
**Purity:** Pure
**Пример:**
```typescript
this.CurrentMovementState = BFL_MovementProcessor.CreateInitialState(
this.GetOwner().GetActorLocation(),
this.GetOwner().GetActorRotation()
);
```
---
## Best Practices
### Initialization
```typescript
// ✅ Good - proper initialization order
class BP_MainCharacter extends Character {
private MovementComponent: AC_Movement;
ReceiveBeginPlay(): void {
this.MovementComponent.InitializeMovementSystem(
this.GetCapsuleComponent(),
this.DebugHUDComponent
);
}
}
// ❌ Bad - using before initialization
ReceiveBeginPlay(): void {
this.MovementComponent.ProcessMovementInput(input, dt); // Will early-return!
}
```
---
### State Access
```typescript
// ✅ Good - direct state access
const currentSpeed = this.MovementComponent.CurrentMovementState.Speed;
const isGrounded = this.MovementComponent.CurrentMovementState.IsGrounded;
// 🔄 Alternative - expose via getter
class AC_Movement {
public GetMovementState(): S_MovementState {
return this.CurrentMovementState;
}
}
const state = this.MovementComponent.GetMovementState();
const speed = state.Speed;
```
---
### Testing
```typescript
// ✅ Good - test processor directly
describe('BFL_MovementProcessor', () => {
it('should accelerate on ground', () => {
const initialState = BFL_MovementProcessor.CreateInitialState(
new Vector(0, 0, 100),
new Rotator(0, 0, 0)
);
const input: S_MovementInput = {
InputVector: new Vector(1, 0, 0),
DeltaTime: 0.016,
CapsuleComponent: mockCapsule,
Config: testConfig,
AngleThresholdsRads: testThresholds
};
const newState = BFL_MovementProcessor.ProcessMovement(
initialState,
input,
false
);
expect(newState.Velocity.X).toBeGreaterThan(0);
expect(newState.MovementState).toBe(E_MovementState.Walking);
});
});
```
---
### Performance
```typescript
// ✅ Good - check initialization once
if (this.MovementComponent.IsInitialized) {
// Movement processing
}
// ✅ Good - cache config access
const maxSpeed = this.Config.MaxSpeed;
for (let i = 0; i < 100; i++) {
// Use maxSpeed
}
// ❌ Bad - repeated property access
for (let i = 0; i < 100; i++) {
if (speed > this.Config.MaxSpeed) { ... }
}
```
---
## Configuration Guidelines
### Movement Physics
| Parameter | Default | Description | Tuning Guide |
|-----------|---------|-------------|--------------|
| MaxSpeed | 800.0 | Max horizontal speed (cm/s) | Higher = faster character |
| Acceleration | 10.0 | VInterpTo acceleration rate | Higher = more responsive |
| Friction | 8.0 | VInterpTo friction rate | Higher = faster stopping |
| Gravity | 980.0 | Gravity force (cm/s²) | Standard Earth gravity |
### Surface Detection
| Parameter | Default | Description |
|-----------|---------|-------------|
| Walkable | 50° | Max walkable angle |
| SteepSlope | 85° | Max steep slope angle |
| Wall | 95° | Max wall angle |
### Collision
| Parameter | Default | Description | Performance Impact |
|-----------|---------|-------------|-------------------|
| MinStepSize | 1.0 | Min sweep step (cm) | Smaller = more precise, slower |
| MaxStepSize | 50.0 | Max sweep step (cm) | Larger = faster, less precise |
| MaxCollisionChecks | 25 | Max checks per frame | Higher = safer, more expensive |
| GroundTraceDistance | 50.0 | Ground detection distance (cm) | Balance precision vs cost |
### Rotation
| Parameter | Default | Description |
|-----------|---------|-------------|
| RotationSpeed | 360.0 | Rotation speed (deg/s) |
| MinSpeedForRotation | 50.0 | Min speed to rotate (cm/s) |
| ShouldRotateToMovement | true | Enable rotation |
---
## Performance Characteristics
### Frame Budget
- **Target:** <1ms per frame (60 FPS)
- **Typical:** 0.3-0.7ms
- **Max:** ~1.5ms (complex collision scenarios)
### Bottlenecks
1. **Swept Collision** (most expensive)
- Multiple CapsuleTraceByChannel calls
- Adaptive stepping helps
- Monitor `CollisionCount` in debug HUD
2. **Ground Detection** (moderate)
- Single LineTraceByChannel per frame
- Always runs (even airborne)
3. **Physics Calculations** (cheap)
- Pure math operations
- VInterpTo is optimized
### Optimization Tips
1. Increase `MinStepSize` if collision checks too high
2. Decrease `GroundTraceDistance` to minimum needed
3. Disable `ShouldRotateToMovement` for static NPCs
4. Use `IsShowVisualDebug = false` in production
---
## Testing Strategy
### Unit Testing (BFL_* modules)
```typescript
describe('BFL_Kinematics', () => {
it('should apply friction correctly', () => {
const velocity = new Vector(800, 0, 0);
const result = BFL_Kinematics.CalculateFriction(
velocity,
0.016,
testConfig
);
expect(result.X).toBeLessThan(velocity.X);
expect(result.Z).toBe(0);
});
});
```
### Integration Testing (BFL_MovementProcessor)
```typescript
describe('Movement Pipeline', () => {
it('should process complete frame', () => {
const state = processFullFrame(initialState, input);
expect(state.Location).not.toEqual(initialState.Location);
expect(state.Velocity).toBeDefined();
expect(state.MovementState).toBeDefined();
});
});
```
### Manual Testing (see ManualTestingChecklist.md)
- Ground detection
- Surface classification
- Collision response
- Rotation behavior
- Debug visualization
---
## Known Limitations
### Current Constraints
1. **Binary Ground State:** No partial contact detection
2. **Single Collision Shape:** Capsule only
3. **Frame-Dependent Stepping:** Sweep precision varies with framerate
4. **No Material Physics:** Surface material not considered
5. **Simple Sliding:** Basic projection, no advanced friction
### By Design
1. **Capsule Component Required:** System assumes capsule collision
2. **Deterministic Traces:** Relies on UE physics determinism
3. **Horizontal Focus:** Optimized for ground-based movement
4. **No Network Code:** Not yet optimized for multiplayer
---
## Future Extensions (Stage 10+)
### Planned Features
- **Jump System:** Vertical velocity application, coyote time, jump buffering
- **Steep Slope Sliding:** Physics-based sliding on non-walkable surfaces
- **Moving Platforms:** Platform attachment and relative movement
- **Wall Running:** Advanced surface interaction
- **Ledge Detection:** Edge detection for platforming
- **Material-Based Physics:** Surface material awareness
---
## File Structure
```
Content/
├── Movement/
│ ├── Components/
│ │ └── AC_Movement.ts # Imperative shell (~230 LOC)
│ ├── Core/
│ │ ├── BFL_MovementProcessor.ts # Functional core (~260 LOC)
│ │ ├── DA_MovementConfig.ts # Configuration asset
│ │ ├── DA_MovementConfigDefault.ts # Default config
│ │ ├── E_MovementState.ts # Movement states enum
│ │ ├── S_MovementInput.ts # Input structure
│ │ └── S_MovementState.ts # State structure
│ ├── Collision/
│ │ ├── BFL_CollisionResolver.ts # Swept collision
│ │ ├── BFL_GroundProbe.ts # Ground detection
│ │ └── S_SweepResult.ts # Sweep result structure
│ ├── Physics/
│ │ └── BFL_Kinematics.ts # Movement physics
│ ├── Rotation/
│ │ ├── BFL_RotationController.ts # Rotation logic
│ │ └── S_RotationResult.ts # Rotation result structure
│ ├── State/
│ │ ├── BFL_MovementStateMachine.ts # FSM logic
│ │ └── S_MovementContext.ts # State context structure
│ ├── Surface/
│ │ ├── BFL_SurfaceClassifier.ts # Surface classification
│ │ ├── E_SurfaceType.ts # Surface types enum
│ │ └── S_AngleThresholds.ts # Angle thresholds structure
│ └── Documentation/
│ ├── TDD.md # This document
│ └── ManualTestingChecklist.md # Testing procedures
└── Math/
└── Libraries/
└── BFL_Vectors.ts # Vector math utilities
```
---
## Troubleshooting
### Character Falling Through Ground
**Symptoms:** Character drops through walkable surface
**Checks:**
1. `GroundTraceDistance > 0`
2. Ground has `Visibility` collision channel
3. `CapsuleComponent` initialized correctly
4. `IsInitialized == true`
**Debug:**
```typescript
// Enable visual debug
this.DebugHUDComponent.ShowVisualDebug = true;
// Check ground hit in debug HUD
// Look for green line trace downward
```
---
### Excessive Collision Checks
**Symptoms:** `CollisionCount` consistently hitting `MaxCollisionChecks`
**Fixes:**
1. Increase `MaxStepSize` (careful: less precision)
2. Decrease `MaxSpeed`
3. Increase `MaxCollisionChecks` (careful: performance cost)
4. Check for collision geometry issues
**Debug:**
```typescript
// Monitor in debug HUD
CollisionCount / MaxCollisionChecks
// Should be <50% most frames
```
---
### Jittery Z Position
**Symptoms:** Character bouncing up/down slightly
**Fixes:**
1. Verify ground detection working (`IsGrounded` in debug HUD)
2. Check ground snapping active
3. Slightly increase `GroundTraceDistance`
4. Verify ground has consistent collision
---
### Character Not Rotating
**Symptoms:** Character faces wrong direction
**Checks:**
1. `Config.ShouldRotateToMovement == true`
2. `CurrentSpeed > Config.MinSpeedForRotation`
3. `SetActorRotation()` called each frame
4. Input vector not zero
**Debug:**
```typescript
// Check in debug HUD
Is Rotating: true/false
Rotation Delta: [degrees remaining]
Current Yaw: [current angle]
```
---
## Conclusion
Movement System представляет собой production-ready систему с следующими характеристиками:
### Архитектурные достижения ✅
- **Functional Core, Imperative Shell** pattern реализован полностью
- **Clear separation of concerns** между subsystems
- **Pipeline processing** с явными фазами
- **Immutable state transformations** везде где возможно
- **Testable design** благодаря pure function libraries
### Production Readiness ✅
- **Deterministic physics** с VInterpTo
- **Tunneling protection** через swept collision
- **Frame-rate independence** через DeltaTime
- **Performance optimized** (<1ms typical frame time)
- **Debug visualization** comprehensive
- **Extensible architecture** для future features
### Code Quality ✅
- **LOC reduced** 62% в AC_Movement (600 230)
- **Modularity** high - 8 focused modules
- **Documentation** comprehensive
- **Type safety** strong через TypeScript structs
**Production Status:** **Ready for Stage 10**
Архитектура готова для расширения Jump System и последующих features без major refactoring.