232 lines
10 KiB
TypeScript
232 lines
10 KiB
TypeScript
// Movement/AC_Movement.ts
|
|
|
|
import type { AC_DebugHUD } from '#root/Debug/Components/AC_DebugHUD.ts';
|
|
import { BFL_MovementProcessor } from '#root/Movement/Core/BFL_MovementProcessor.ts';
|
|
import type { DA_MovementConfig } from '#root/Movement/Core/DA_MovementConfig.ts';
|
|
import { DA_MovementConfigDefault } from '#root/Movement/Core/DA_MovementConfigDefault.ts';
|
|
import { E_MovementState } from '#root/Movement/Core/E_MovementState.ts';
|
|
import type { S_MovementState } from '#root/Movement/Core/S_MovementState.ts';
|
|
import { E_SurfaceType } from '#root/Movement/Surface/E_SurfaceType.ts';
|
|
import { S_AngleThresholds } from '#root/Movement/Surface/S_AngleThresholds.ts';
|
|
import { ActorComponent } from '#root/UE/ActorComponent.ts';
|
|
import type { CapsuleComponent } from '#root/UE/CapsuleComponent.ts';
|
|
import type { Float } from '#root/UE/Float.ts';
|
|
import { HitResult } from '#root/UE/HitResult.ts';
|
|
import { MathLibrary } from '#root/UE/MathLibrary.ts';
|
|
import { Rotator } from '#root/UE/Rotator.ts';
|
|
import { StringLibrary } from '#root/UE/StringLibrary.ts';
|
|
import { SystemLibrary } from '#root/UE/SystemLibrary.ts';
|
|
import { Vector } from '#root/UE/Vector.ts';
|
|
|
|
/**
|
|
* Movement System Component
|
|
* Core deterministic movement system for 3D platformer
|
|
* Handles surface classification and movement physics calculations
|
|
*/
|
|
export class AC_Movement extends ActorComponent {
|
|
// ════════════════════════════════════════════════════════════════════════════════════════
|
|
// FUNCTIONS
|
|
// ════════════════════════════════════════════════════════════════════════════════════════
|
|
|
|
// ────────────────────────────────────────────────────────────────────────────────────────
|
|
// Debug
|
|
// ────────────────────────────────────────────────────────────────────────────────────────
|
|
|
|
/**
|
|
* Update debug HUD with current movement info
|
|
* @category Debug
|
|
*/
|
|
public UpdateDebugPage(): void {
|
|
if (SystemLibrary.IsValid(this.DebugHUDComponent)) {
|
|
if (
|
|
this.DebugHUDComponent.ShouldUpdatePage(
|
|
this.DebugPageID,
|
|
SystemLibrary.GetGameTimeInSeconds()
|
|
)
|
|
) {
|
|
this.DebugHUDComponent.UpdatePageContent(
|
|
this.DebugPageID,
|
|
// Constants
|
|
`Max Speed: ${this.Config.MaxSpeed}\n` +
|
|
`Acceleration: ${this.Config.Acceleration}\n` +
|
|
`Friction: ${this.Config.Friction}\n` +
|
|
`Gravity: ${this.Config.Gravity}\n` +
|
|
`Initialized: ${this.IsInitialized}\n` +
|
|
`\n` +
|
|
// Current State
|
|
`Current Velocity: ${StringLibrary.ConvVectorToString(this.CurrentMovementState.Velocity)}\n` +
|
|
`Speed: ${this.CurrentMovementState.Speed}\n` +
|
|
`Is Grounded: ${this.CurrentMovementState.IsGrounded}\n` +
|
|
`Surface Type: ${this.CurrentMovementState.SurfaceType}\n` +
|
|
`Movement State: ${this.CurrentMovementState.MovementState}\n` +
|
|
`Input Magnitude: ${this.CurrentMovementState.InputMagnitude}` +
|
|
`\n` +
|
|
// Rotation
|
|
`Current Yaw: ${this.CurrentMovementState.Rotation.yaw}\n` +
|
|
`Rotation Delta: ${this.CurrentMovementState.RotationDelta}\n°` +
|
|
`Is Rotating: ${this.CurrentMovementState.IsRotating}\n` +
|
|
`Rotation Speed: ${this.Config.RotationSpeed}\n°` +
|
|
`Min Speed: ${this.Config.MinSpeedForRotation}` +
|
|
`\n` +
|
|
// Position
|
|
`Location: ${StringLibrary.ConvVectorToString(this.GetOwner().GetActorLocation())}` +
|
|
`\n` +
|
|
// Sweep Collision
|
|
`Collision Checks: ${this.CurrentMovementState.CollisionCount}/${this.Config.MaxCollisionChecks}\n` +
|
|
`Sweep Blocked: ${this.CurrentMovementState.IsBlocked}\n` +
|
|
`Ground Distance: ${this.Config.GroundTraceDistance} cm`
|
|
);
|
|
}
|
|
}
|
|
}
|
|
|
|
// ────────────────────────────────────────────────────────────────────────────────────────
|
|
// Default
|
|
// ────────────────────────────────────────────────────────────────────────────────────────
|
|
|
|
/**
|
|
* Process movement input from player controller
|
|
* Normalizes input and calculates target velocity
|
|
* @param InputVector - Raw input from WASD/gamepad stick
|
|
* @param DeltaTime - Time since last frame for frame-rate independence
|
|
* @category Default
|
|
*/
|
|
public ProcessMovementInput(InputVector: Vector, DeltaTime: Float): void {
|
|
if (this.IsInitialized) {
|
|
this.CurrentMovementState = BFL_MovementProcessor.ProcessMovement(
|
|
this.CurrentMovementState,
|
|
{
|
|
InputVector,
|
|
DeltaTime,
|
|
CapsuleComponent: this.CapsuleComponent,
|
|
Config: this.Config,
|
|
AngleThresholdsRads: this.AngleThresholdsRads,
|
|
},
|
|
SystemLibrary.IsValid(this.DebugHUDComponent)
|
|
? this.DebugHUDComponent.ShowVisualDebug
|
|
: false
|
|
);
|
|
|
|
this.GetOwner().SetActorLocation(this.CurrentMovementState.Location);
|
|
this.GetOwner().SetActorRotation(this.CurrentMovementState.Rotation);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Initialize movement system with angle conversion
|
|
* Converts degree thresholds to radians for runtime performance
|
|
* @category Default
|
|
*/
|
|
public InitializeMovementSystem(
|
|
CapsuleComponentRef: CapsuleComponent | null = null,
|
|
DebugHUDComponentRef: AC_DebugHUD | null = null
|
|
): void {
|
|
this.CapsuleComponent = CapsuleComponentRef;
|
|
this.DebugHUDComponent = DebugHUDComponentRef;
|
|
this.IsInitialized = true;
|
|
|
|
this.AngleThresholdsRads = {
|
|
Walkable: MathLibrary.DegreesToRadians(
|
|
this.Config.AngleThresholdsDegrees.Walkable
|
|
),
|
|
SteepSlope: MathLibrary.DegreesToRadians(
|
|
this.Config.AngleThresholdsDegrees.SteepSlope
|
|
),
|
|
Wall: MathLibrary.DegreesToRadians(
|
|
this.Config.AngleThresholdsDegrees.Wall
|
|
),
|
|
};
|
|
|
|
this.CurrentMovementState = BFL_MovementProcessor.CreateInitialState(
|
|
this.GetOwner().GetActorLocation(),
|
|
this.GetOwner().GetActorRotation()
|
|
);
|
|
|
|
if (SystemLibrary.IsValid(this.DebugHUDComponent)) {
|
|
this.DebugHUDComponent.AddDebugPage(
|
|
this.DebugPageID,
|
|
'Movement Info',
|
|
60
|
|
);
|
|
}
|
|
}
|
|
|
|
// ════════════════════════════════════════════════════════════════════════════════════════
|
|
// VARIABLES
|
|
// ════════════════════════════════════════════════════════════════════════════════════════
|
|
|
|
// ────────────────────────────────────────────────────────────────────────────────────────
|
|
// Components
|
|
// ────────────────────────────────────────────────────────────────────────────────────────
|
|
|
|
/**
|
|
* Reference to debug HUD component for displaying camera info
|
|
* Optional, used for debugging purposes
|
|
* @category Components
|
|
*/
|
|
private DebugHUDComponent: AC_DebugHUD | null = null;
|
|
|
|
/**
|
|
* Reference to character's capsule component for collision detection
|
|
* @category Components
|
|
*/
|
|
private CapsuleComponent: CapsuleComponent | null = null;
|
|
|
|
// ────────────────────────────────────────────────────────────────────────────────────────
|
|
// Default
|
|
// ────────────────────────────────────────────────────────────────────────────────────────
|
|
|
|
/**
|
|
* Default movement state
|
|
* @category Default
|
|
*/
|
|
private CurrentMovementState: S_MovementState = {
|
|
Location: new Vector(0, 0, 0),
|
|
Rotation: new Rotator(0, 0, 0),
|
|
Velocity: new Vector(0, 0, 0),
|
|
Speed: 0.0,
|
|
IsGrounded: false,
|
|
GroundHit: new HitResult(),
|
|
SurfaceType: E_SurfaceType.None,
|
|
IsBlocked: false,
|
|
CollisionCount: 0,
|
|
IsRotating: false,
|
|
RotationDelta: 0.0,
|
|
MovementState: E_MovementState.Idle,
|
|
InputMagnitude: 0.0,
|
|
};
|
|
|
|
/**
|
|
* Default movement configuration
|
|
* @category Default
|
|
* @instanceEditable true
|
|
*/
|
|
private readonly Config: DA_MovementConfig = new DA_MovementConfigDefault();
|
|
|
|
/**
|
|
* Runtime cached angle thresholds in radians
|
|
* Converted from degrees during initialization for performance
|
|
* @category Default
|
|
*/
|
|
private AngleThresholdsRads: S_AngleThresholds = {
|
|
Walkable: 0.0,
|
|
SteepSlope: 0.0,
|
|
Wall: 0.0,
|
|
};
|
|
|
|
/**
|
|
* Debug page identifier for organizing debug output
|
|
* Used by debug HUD to categorize information
|
|
* @category Default
|
|
* @instanceEditable true
|
|
*/
|
|
private readonly DebugPageID: string = 'MovementInfo';
|
|
|
|
/**
|
|
* Flag indicating if movement system has been initialized
|
|
* Ensures angle thresholds are converted before use
|
|
* @category Debug
|
|
*/
|
|
private IsInitialized = false;
|
|
}
|