196 lines
6.6 KiB
TypeScript
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;
|
|
}
|