class_name ShotSetup extends Node3D const PITCH_MIN := deg_to_rad(-60.0) const PITCH_MAX := deg_to_rad(-5.0) const ZOOM_LENGTH := 0.1 const ZOOM_MIN := 1.0 const ZOOM_MAX := 12.0 enum Phase { AIMING, LATERAL, POWER, FINISHED, } 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") var _phase: Phase = Phase.AIMING @onready var direction: Node3D = %Direction @onready var pitch: Node3D = %Pitch @onready var camera: Camera3D = %Camera @onready var camera_distance := camera.position.z: set = _set_camera_distance @onready var _target_rotation := Vector2(pitch.rotation.x, direction.rotation.y) func _set_camera_distance(value: float) -> void: var tween := get_tree().create_tween() tween.tween_property(camera, "position", Vector3(0, 0, value), ZOOM_LENGTH).set_trans( Tween.TRANS_SINE ) camera_distance = value 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: if _phase == Phase.AIMING: # Can only control camera while aiming _target_rotation.y = _target_rotation.y - deg_to_rad(motion.x * x_sensitivity) _target_rotation.x = clampf( _target_rotation.x - deg_to_rad(motion.y * y_sensitivity) * (-1 if invert_pitch else 1), PITCH_MIN, PITCH_MAX ) func _physics_process(delta: float) -> void: if _phase == Phase.AIMING: # Camera zoom if Input.is_action_just_pressed("shot_zoom_in"): camera_distance = max(camera_distance - 1.0, ZOOM_MIN) if Input.is_action_just_pressed("shot_zoom_out"): camera_distance = min(camera_distance + 1.0, ZOOM_MAX) # Rotation direction.rotation.y = lerp_angle( direction.rotation.y, _target_rotation.y, delta * x_acceleration ) pitch.rotation.x = lerp_angle(pitch.rotation.x, _target_rotation.x, delta * y_acceleration)