Files

109 lines
3.2 KiB
GDScript

extends Node3D
@export var target: Node3D
@export var follow_offset := Vector3(0, 10, 8)
@export var follow_speed := 12.0
@export var rotation_smooth_speed := 18.0
@export var focus_smooth_speed := 14.0
@export var pitch_degrees := -55.0
@export var mouse_sensitivity := 0.002
@export var deadzone_right := 3.0
@export var deadzone_forward := 3.0
@export var min_zoom_offset := Vector3(0, 5, 4)
@export var max_zoom_offset := Vector3(0, 16, 12)
@export var zoom_step := 0.1
var yaw := 0.0
var smoothed_yaw := 0.0
var zoom := 0.5
var zoom_smooth := 0.5
var focus_position := Vector3.ZERO
var desired_focus_position := Vector3.ZERO
func _ready() -> void:
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
if target:
focus_position = target.global_position
desired_focus_position = focus_position
_apply_camera_transform()
func _unhandled_input(event: InputEvent) -> void:
if event is InputEventMouseMotion:
yaw -= event.relative.x * mouse_sensitivity
if event is InputEventMouseButton:
if event.button_index == MOUSE_BUTTON_WHEEL_UP and event.pressed:
zoom = maxf(zoom - zoom_step, 0.0)
elif event.button_index == MOUSE_BUTTON_WHEEL_DOWN and event.pressed:
zoom = minf(zoom + zoom_step, 1.0)
if event.is_action_pressed("ui_cancel"):
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
func _physics_process(delta: float) -> void:
if target == null:
return
var rot_t := 1.0 - exp(-rotation_smooth_speed * delta)
var focus_t := 1.0 - exp(-focus_smooth_speed * delta)
var follow_t := 1.0 - exp(-follow_speed * delta)
smoothed_yaw = lerp_angle(smoothed_yaw, yaw, rot_t)
rotation = Vector3(deg_to_rad(pitch_degrees), smoothed_yaw, 0)
var target_pos := target.global_position
var diff := target_pos - desired_focus_position
var cam_right := Vector3.RIGHT.rotated(Vector3.UP, smoothed_yaw).normalized()
var cam_forward := Vector3.FORWARD.rotated(Vector3.UP, smoothed_yaw).normalized()
var diff_right := diff.dot(cam_right)
var diff_forward := diff.dot(cam_forward)
if abs(diff_right) > deadzone_right:
desired_focus_position += cam_right * (diff_right - sign(diff_right) * deadzone_right)
if abs(diff_forward) > deadzone_forward:
desired_focus_position += (
cam_forward * (diff_forward - sign(diff_forward) * deadzone_forward)
)
desired_focus_position.y = target_pos.y
focus_position = focus_position.lerp(desired_focus_position, focus_t)
zoom_smooth = lerpf(zoom_smooth, zoom, follow_t)
var active_offset := min_zoom_offset.lerp(max_zoom_offset, zoom_smooth)
var rotated_offset := active_offset.rotated(Vector3.UP, smoothed_yaw)
var desired_position := focus_position + rotated_offset
global_position = global_position.lerp(desired_position, follow_t)
func apply_presentation_preset(focus: Vector3, yaw_degrees: float, zoom_value: float) -> void:
yaw = deg_to_rad(yaw_degrees)
smoothed_yaw = yaw
zoom = clampf(zoom_value, 0.0, 1.0)
zoom_smooth = zoom
focus_position = focus
desired_focus_position = focus
_apply_camera_transform()
func _apply_camera_transform() -> void:
rotation = Vector3(deg_to_rad(pitch_degrees), smoothed_yaw, 0)
var active_offset := min_zoom_offset.lerp(max_zoom_offset, zoom_smooth)
global_position = focus_position + active_offset.rotated(Vector3.UP, smoothed_yaw)