// Movement/Physics/BFL_Kinematics.ts import type { DA_MovementConfig } from '#root/Movement/Core/DA_MovementConfig.ts'; import { BlueprintFunctionLibrary } from '#root/UE/BlueprintFunctionLibrary.ts'; import type { Float } from '#root/UE/Float.ts'; import { MathLibrary } from '#root/UE/MathLibrary.ts'; import { Vector } from '#root/UE/Vector.ts'; class BFL_KinematicsClass extends BlueprintFunctionLibrary { // ════════════════════════════════════════════════════════════════════════════════════════ // GROUND MOVEMENT // ════════════════════════════════════════════════════════════════════════════════════════ /** * Calculate new velocity for ground-based movement with acceleration * Uses VInterpTo for smooth acceleration towards target velocity * Only affects horizontal (XY) components, preserves vertical (Z) * * @param CurrentVelocity - Current character velocity (cm/s) * @param InputVector - Normalized input direction from player/AI * @param DeltaTime - Frame delta time for frame-rate independence (s) * @param Config - Movement configuration with MaxSpeed and Acceleration * @returns New velocity vector with updated horizontal components * * @example * // Character moving forward with input (1, 0, 0) * const newVel = Kinematics.CalculateGroundVelocity( * new Vector(400, 0, 0), // Current velocity * new Vector(1, 0, 0), // Forward input * 0.016, // 60 FPS delta * config * ); * // Returns: Vector(450, 0, 0) - accelerated towards MaxSpeed * * @pure true * @category Ground Movement */ public CalculateGroundVelocity( CurrentVelocity: Vector, InputVector: Vector, DeltaTime: Float, Config: DA_MovementConfig ): Vector { if (MathLibrary.VectorLength(InputVector) > 0.01) { const CalculateTargetVelocity = ( inputVector: Vector, maxSpeed: Float ): Vector => new Vector( MathLibrary.Normal(inputVector).X * maxSpeed, MathLibrary.Normal(inputVector).Y * maxSpeed, MathLibrary.Normal(inputVector).Z * maxSpeed ); return MathLibrary.VInterpTo( new Vector(CurrentVelocity.X, CurrentVelocity.Y, 0), CalculateTargetVelocity(InputVector, Config.MaxSpeed), DeltaTime, Config.Acceleration ); } else { return this.CalculateFriction(CurrentVelocity, DeltaTime, Config); } } // ════════════════════════════════════════════════════════════════════════════════════════ // FRICTION // ════════════════════════════════════════════════════════════════════════════════════════ /** * Apply friction to horizontal velocity (deceleration when no input) * Smoothly interpolates velocity towards zero using friction rate * Only affects horizontal (XY) components, preserves vertical (Z) * * @param CurrentVelocity - Current character velocity (cm/s) * @param DeltaTime - Frame delta time (s) * @param Config - Movement configuration with Friction rate * @returns New velocity vector with friction applied to horizontal components * * @example * // Character sliding to stop after input released * const newVel = Kinematics.ApplyFriction( * new Vector(500, 0, 0), // Moving forward * 0.016, // 60 FPS delta * config // Friction = 8.0 * ); * // Returns: Vector(450, 0, 0) - smoothly decelerating * * @pure true * @category Friction */ public CalculateFriction( CurrentVelocity: Vector, DeltaTime: Float, Config: DA_MovementConfig ): Vector { return MathLibrary.VInterpTo( new Vector(CurrentVelocity.X, CurrentVelocity.Y, 0), new Vector(0, 0, CurrentVelocity.Z), DeltaTime, Config.Friction ); } // ════════════════════════════════════════════════════════════════════════════════════════ // GRAVITY // ════════════════════════════════════════════════════════════════════════════════════════ /** * Apply gravity to vertical velocity when airborne * Only affects Z component, horizontal velocity unchanged * Gravity is NOT applied when grounded (Z velocity set to 0) * * @param CurrentVelocity - Current character velocity (cm/s) * @param IsGrounded - Whether character is on walkable surface * @param Config - Movement configuration with Gravity force * @returns New velocity vector with gravity applied to vertical component * * @example * // Character falling (not grounded) * const newVel = Kinematics.ApplyGravity( * new Vector(500, 0, -200), // Moving forward and falling * false, // Not grounded * config // Gravity = 980 cm/s² * ); * // Returns: Vector(500, 0, -216.8) - falling faster * * @example * // Character on ground * const newVel = Kinematics.ApplyGravity( * new Vector(500, 0, -10), // Small downward velocity * true, // Grounded * config * ); * // Returns: Vector(500, 0, 0) - vertical velocity zeroed * * @pure true * @category Gravity */ public CalculateGravity( CurrentVelocity: Vector, IsGrounded: boolean, Config: DA_MovementConfig ): Vector { if (!IsGrounded) { return new Vector( CurrentVelocity.X, CurrentVelocity.Y, CurrentVelocity.Z - Config.Gravity ); } else { return new Vector(CurrentVelocity.X, CurrentVelocity.Y, 0); } } // ════════════════════════════════════════════════════════════════════════════════════════ // VELOCITY QUERIES // ════════════════════════════════════════════════════════════════════════════════════════ /** * Get horizontal speed (magnitude of XY velocity) * Ignores vertical component, useful for animation and debug display * * @param Velocity - Velocity vector to measure * @returns Speed in cm/s (horizontal plane only) * * @example * const speed = Kinematics.GetHorizontalSpeed(new Vector(300, 400, -100)); * // Returns: 500.0 (sqrt(300² + 400²)) * * @pure true * @category Velocity Queries */ public GetHorizontalSpeed(Velocity: Vector): Float { return MathLibrary.VectorLength(new Vector(Velocity.X, Velocity.Y, 0)); } } export const BFL_Kinematics = new BFL_KinematicsClass();