// 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_DebugHUD } from '#root/Debug/Components/AC_DebugHUD.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, DebugComponentRef: AC_DebugHUD ): void { this.InputDeviceComponent = InputDeviceRef; this.DebugHUDComponent = DebugComponentRef; this.IsInitialized = true; if (SystemLibrary.IsValid(this.DebugHUDComponent)) { this.DebugHUDComponent.AddDebugPage( this.DebugPageID, 'Camera System', 60 ); } } /** * Update debug HUD with current camera info * @category Debug */ public UpdateDebugPage(): void { if (SystemLibrary.IsValid(this.DebugHUDComponent)) { if ( this.DebugHUDComponent.ShouldUpdatePage( this.DebugPageID, SystemLibrary.GetGameTimeInSeconds() ) ) { this.DebugHUDComponent.UpdatePageContent( this.DebugPageID, `Current Device: ${SystemLibrary.IsValid(this.InputDeviceComponent) ? this.InputDeviceComponent.GetCurrentInputDevice() : 'Input Device Component Not Found'}\n` + `Sensitivity: ${SystemLibrary.IsValid(this.InputDeviceComponent) && this.InputDeviceComponent.IsGamepad() ? this.CameraSettings.GamepadSensitivity : this.CameraSettings.MouseSensitivity}\n` + `Pitch: ${this.GetCameraRotation().Pitch}°\n` + `Yaw: ${this.GetCameraRotation().Yaw}°\n` + `Is Rotating: ${this.IsCameraRotating() ? 'Yes' : 'No'}\n` + `Smoothing: ${this.CameraSettings.SmoothingSpeed}\n` + `Invert Y: ${this.CameraSettings.InvertYAxis ? 'Yes' : 'No'}` ); } } } // ════════════════════════════════════════════════════════════════════════════════════════ // 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; /** * Reference to debug HUD component for displaying camera info * Optional, used for debugging purposes * @category Components */ public DebugHUDComponent: AC_DebugHUD | null = null; /** * Debug page identifier for organizing debug output * Used by debug HUD to categorize information * @category Debug */ public readonly DebugPageID: string = 'CameraInfo'; }