tengri/Content/Movement/AC_Movement.ts

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}\` +
`Is Rotating: ${this.CurrentMovementState.IsRotating}\n` +
`Rotation Speed: ${this.Config.RotationSpeed}\` +
`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;
}