tengri/Content/Camera/Components/AC_Camera.ts

196 lines
6.6 KiB
TypeScript

// Camera/Components/AC_Camera.ts
import type { S_CameraSettings } from '#root/Camera/Structs/S_CameraSettings.ts';
import type { S_CameraState } from '#root/Camera/Structs/S_CameraState.ts';
import type { AC_InputDevice } from '#root/Input/Components/AC_InputDevice.ts';
import { ActorComponent } from '#root/UE/ActorComponent.ts';
import type { Float } from '#root/UE/Float.ts';
import { MathLibrary } from '#root/UE/MathLibrary.ts';
import { SystemLibrary } from '#root/UE/SystemLibrary.ts';
import { Vector } from '#root/UE/Vector.ts';
/**
* Camera System Component
* Deterministic camera control with smooth rotation and device-aware sensitivity
* Provides precise control over camera behavior for consistent experience
*/
export class AC_Camera extends ActorComponent {
// ════════════════════════════════════════════════════════════════════════════════════════
// FUNCTIONS
// ════════════════════════════════════════════════════════════════════════════════════════
/**
* Process look input and update camera rotation
* @param InputDelta - Input delta (X = Yaw, Y = Pitch)
* @param DeltaTime - Time since last frame
* @category Input Processing
*/
public ProcessLookInput(InputDelta: Vector, DeltaTime: Float): void {
if (this.IsInitialized) {
const invertMultiplier = this.CameraSettings.InvertYAxis ? -1.0 : 1.0;
let sensitivity: Float = 0;
if (SystemLibrary.IsValid(this.InputDeviceComponent)) {
sensitivity = this.InputDeviceComponent.IsGamepad()
? this.CameraSettings.GamepadSensitivity
: this.CameraSettings.MouseSensitivity;
} else {
sensitivity = this.CameraSettings.MouseSensitivity;
}
const CalculateTargetPitch = (
targetPitch: Float,
inputDeltaY: Float,
deltaTime: Float
): Float =>
targetPitch - inputDeltaY * sensitivity * invertMultiplier * deltaTime;
const CalculateTargetYaw = (
targetYaw: Float,
inputDeltaX: Float,
deltaTime: Float
): Float => targetYaw + inputDeltaX * sensitivity * deltaTime;
this.CameraState = {
CurrentPitch: this.CameraState.CurrentPitch,
CurrentYaw: this.CameraState.CurrentYaw,
TargetPitch: MathLibrary.ClampFloat(
CalculateTargetPitch(
this.CameraState.TargetPitch,
InputDelta.Y,
DeltaTime
),
this.CameraSettings.PitchMin,
this.CameraSettings.PitchMax
),
TargetYaw: CalculateTargetYaw(
this.CameraState.TargetYaw,
InputDelta.X,
DeltaTime
),
LastInputDelta: InputDelta,
InputMagnitude: MathLibrary.VectorLength(InputDelta),
};
}
}
/**
* Update camera rotation with smooth interpolation
* @param DeltaTime - Time since last frame
* @category Camera Updates
*/
public UpdateCameraRotation(DeltaTime: Float): void {
if (this.IsInitialized) {
if (this.CameraSettings.SmoothingSpeed > 0) {
// Smooth interpolation to target rotation
this.CameraState.CurrentPitch = MathLibrary.FInterpTo(
this.CameraState.CurrentPitch,
this.CameraState.TargetPitch,
DeltaTime,
this.CameraSettings.SmoothingSpeed
);
this.CameraState.CurrentYaw = MathLibrary.FInterpTo(
this.CameraState.CurrentYaw,
this.CameraState.TargetYaw,
DeltaTime,
this.CameraSettings.SmoothingSpeed
);
} else {
// Instant rotation (no smoothing)
this.CameraState.CurrentPitch = this.CameraState.TargetPitch;
this.CameraState.CurrentYaw = this.CameraState.TargetYaw;
}
}
}
/**
* Get current camera rotation for applying to SpringArm
* @returns Current camera rotation values
* @category Public Interface
* @pure true
*/
public GetCameraRotation(): { Pitch: Float; Yaw: Float } {
return {
Pitch: this.CameraState.CurrentPitch,
Yaw: this.CameraState.CurrentYaw,
};
}
/**
* Check if camera is currently rotating
* @returns True if there's active rotation input
* @category State Queries
* @pure true
*/
public IsCameraRotating(): boolean {
return this.CameraState.InputMagnitude > 0.01;
}
/**
* Initialize camera system with default settings
* @category System Setup
*/
public InitializeCameraSystem(InputDeviceRef: AC_InputDevice): void {
this.InputDeviceComponent = InputDeviceRef;
this.IsInitialized = true;
// Reset camera state
this.CameraState = {
CurrentPitch: 0.0,
CurrentYaw: 0.0,
TargetPitch: 0.0,
TargetYaw: 0.0,
LastInputDelta: new Vector(0, 0, 0),
InputMagnitude: 0.0,
};
}
// ════════════════════════════════════════════════════════════════════════════════════════
// VARIABLES
// ════════════════════════════════════════════════════════════════════════════════════════
/**
* Camera configuration settings
* Controls sensitivity, limits, and smoothing behavior
* @category Camera Config
* @instanceEditable true
*/
public readonly CameraSettings: S_CameraSettings = {
MouseSensitivity: 100.0,
GamepadSensitivity: 150.0,
InvertYAxis: false,
PitchMin: -89.0,
PitchMax: 89.0,
SmoothingSpeed: 20.0,
};
/**
* Current camera rotation state
* Tracks current, target, and input data
* @category Camera State
*/
private CameraState: S_CameraState = {
CurrentPitch: 0.0,
CurrentYaw: 0.0,
TargetPitch: 0.0,
TargetYaw: 0.0,
LastInputDelta: new Vector(0, 0, 0),
InputMagnitude: 0.0,
};
/**
* System initialization state flag
* @category Camera State
*/
private IsInitialized: boolean = false;
/**
* Reference to input device component for device detection
* Set externally, used for sensitivity adjustments
* @category Components
*/
public InputDeviceComponent: AC_InputDevice | null = null;
}