class_name FreeCamera extends CharacterBody3D const SPRINT_MULT := 2.0 const PITCH_LIMIT := deg_to_rad(85.0) var base_speed: float = ProjectSettings.get_setting("game/config/controls/camera/free_camera_speed") var x_sensitivity: float = ProjectSettings.get_setting( "game/config/controls/camera/x_axis_sensitivity" ) var x_acceleration: float = ProjectSettings.get_setting( "game/config/controls/camera/x_axis_acceleration" ) var y_sensitivity: float = ProjectSettings.get_setting( "game/config/controls/camera/y_axis_sensitivity" ) var y_acceleration: float = ProjectSettings.get_setting( "game/config/controls/camera/y_axis_acceleration" ) var invert_pitch: bool = ProjectSettings.get_setting("game/config/controls/camera/invert_pitch") @onready var _target := Vector2(rotation.x, rotation.y) func _unhandled_input(event: InputEvent) -> void: if event is InputEventMouseButton: Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED) elif event is InputEventMouseMotion: if Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED: camera_motion((event as InputEventMouseMotion).relative) func camera_motion(motion: Vector2) -> void: _target.y = _target.y - deg_to_rad(motion.x * x_sensitivity) _target.x = clampf( _target.x - deg_to_rad(motion.y * y_sensitivity) * (-1 if invert_pitch else 1), -PITCH_LIMIT, PITCH_LIMIT, ) func _physics_process(delta: float) -> void: # Rotation rotation.y = lerp_angle(rotation.y, _target.y, delta * x_acceleration) rotation.x = lerp_angle(rotation.x, _target.x, delta * y_acceleration) # Handle spatial movement var xz_input := Input.get_vector("camera_left", "camera_right", "camera_forward", "camera_back") var y_input := Input.get_vector("camera_down", "camera_up", "camera_down", "camera_up") var direction := (transform.basis * Vector3(xz_input.x, y_input.y, xz_input.y)).normalized() var speed := base_speed if Input.is_action_pressed("camera_sprint"): speed *= SPRINT_MULT if direction: velocity = direction * speed else: velocity = velocity.move_toward(Vector3.ZERO, speed) move_and_slide()