tengri/Content/Movement/Physics/BFL_Kinematics.ts

180 lines
7.7 KiB
TypeScript

// 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();