147 lines
5.5 KiB
GDScript
147 lines
5.5 KiB
GDScript
class_name GameCamera3D
|
|
extends Node3D
|
|
|
|
const ACTION_CAMERA_UP: StringName = &"camera_up"
|
|
const ACTION_CAMERA_DOWN: StringName = &"camera_down"
|
|
const ACTION_CAMERA_LEFT: StringName = &"camera_left"
|
|
const ACTION_CAMERA_RIGHT: StringName = &"camera_right"
|
|
|
|
const MOUSE_SENSITIVITY_PATH: StringName = &"game/input/sensitivity"
|
|
const CONTROLLER_SENSITIVITY_PATH: StringName = &"game/input/controller_sensitivity"
|
|
const INVERT_X_PATH: StringName = &"game/input/camera_invert_x"
|
|
const INVERT_Y_PATH: StringName = &"game/input/camera_invert_y"
|
|
const CONTROLLER_INVERT_X_PATH: StringName = &"game/input/camera_controller_invert_x"
|
|
const CONTROLLER_INVERT_Y_PATH: StringName = &"game/input/camera_controller_invert_y"
|
|
|
|
@export var camera: Camera3D
|
|
@export_range(-360, 360, 0.5, "suffix:°") var look_min_vertical_angle: float = -85.0
|
|
@export_range(-360, 360, 0.5, "suffix:°") var look_max_vertical_angle: float = 85.0
|
|
|
|
@export_group("Acceleration")
|
|
@export var mouse_acceleration: bool = false
|
|
@export_exp_easing("attenuation") var mouse_friction: float = 15.0
|
|
@export var controller_acceleration: bool = true
|
|
@export_exp_easing("attenuation") var controller_friction: float = 15.0
|
|
|
|
@export_group("Input")
|
|
@export_subgroup("Sensitivity")
|
|
@export_range(0.0, 100.0, 0.001, "or_greater") var mouse_sensitivity: float = 1.0
|
|
@export_range(0.0, 100.0, 0.001, "or_greater") var controller_sensitivity: float = 0.75
|
|
@export_subgroup("Invert")
|
|
@export var invert_x: bool = false
|
|
@export var invert_y: bool = false
|
|
@export var controller_invert_x: bool = false
|
|
@export var controller_invert_y: bool = false
|
|
|
|
var rotational_direction: Vector2
|
|
var rotational_velocity: Vector2
|
|
var input_event: InputEvent
|
|
var using_controller: bool = false
|
|
|
|
|
|
func _ready() -> void:
|
|
# Update values based on project settings.
|
|
var _update_settings: Callable = func() -> void:
|
|
mouse_sensitivity = ProjectSettings.get_setting(MOUSE_SENSITIVITY_PATH, 1.6)
|
|
controller_sensitivity = ProjectSettings.get_setting(CONTROLLER_SENSITIVITY_PATH, 5.0)
|
|
invert_x = ProjectSettings.get_setting(INVERT_X_PATH, false)
|
|
invert_y = ProjectSettings.get_setting(INVERT_Y_PATH, false)
|
|
controller_invert_x = ProjectSettings.get_setting(CONTROLLER_INVERT_X_PATH, false)
|
|
controller_invert_y = ProjectSettings.get_setting(CONTROLLER_INVERT_Y_PATH, false)
|
|
|
|
ProjectSettings.settings_changed.connect(_update_settings)
|
|
_update_settings.call()
|
|
|
|
|
|
func _physics_process(delta: float) -> void:
|
|
_process_input(delta)
|
|
|
|
|
|
func _unhandled_input(event: InputEvent) -> void:
|
|
if event is InputEventMouseMotion or event is InputEventJoypadMotion:
|
|
input_event = event
|
|
|
|
|
|
func apply_rotation(rot: Vector2) -> void:
|
|
rotate_y(-rot.x)
|
|
rotation.x = rotation.x - rot.y
|
|
rotation_degrees.x = clampf(rotation_degrees.x, look_min_vertical_angle, look_max_vertical_angle)
|
|
|
|
|
|
func get_sensitivity() -> float:
|
|
var sensitivity: float = mouse_sensitivity if not using_controller else controller_sensitivity
|
|
var frame_rate: float = Engine.get_frames_per_second() / 60.0
|
|
sensitivity *= frame_rate
|
|
#print(frame_rate)
|
|
|
|
return sensitivity
|
|
|
|
|
|
func _process_input(delta: float) -> void:
|
|
if Input.mouse_mode != Input.MOUSE_MODE_CAPTURED or not InputManager.window_focused():
|
|
return
|
|
|
|
if input_event is InputEventMouseMotion:
|
|
_process_mouse(input_event, delta)
|
|
using_controller = false
|
|
rotational_direction = Vector2.ZERO
|
|
input_event = null
|
|
|
|
elif input_event is InputEventJoypadMotion:
|
|
_process_controller(delta)
|
|
using_controller = true
|
|
rotational_direction = Vector2.ZERO
|
|
|
|
# Decelerating when nothing is being pressed.
|
|
elif not rotational_velocity.is_zero_approx() and rotational_direction.is_zero_approx():
|
|
input_event = null
|
|
|
|
if not using_controller and mouse_acceleration:
|
|
rotational_velocity = _lerp_rotational_velocity(get_sensitivity() / 10, mouse_friction, delta)
|
|
elif using_controller and controller_acceleration:
|
|
rotational_velocity = _lerp_rotational_velocity(get_sensitivity(), controller_friction,delta)
|
|
apply_rotation(rotational_velocity)
|
|
else:
|
|
rotational_velocity = Vector2.ZERO
|
|
|
|
apply_rotation(rotational_velocity)
|
|
|
|
|
|
func _process_mouse(event: InputEventMouseMotion, delta: float) -> void:
|
|
# TODO: Somehow fix the fps-dependent mouse :/
|
|
# https://yosoyfreeman.github.io/godot/achieving-better-mouse-input-in-godot-4-the-perfect-camera-controller-full-project/
|
|
var viewport_transform: Transform2D = get_tree().get_root().get_final_transform()
|
|
rotational_direction = event.xformed_by(viewport_transform).get_relative()
|
|
|
|
if invert_x:
|
|
rotational_direction.x = -rotational_direction.x
|
|
|
|
if invert_y:
|
|
rotational_direction.y = -rotational_direction.y
|
|
|
|
if mouse_acceleration:
|
|
rotational_velocity = _lerp_rotational_velocity(deg_to_rad(get_sensitivity() / 10.0), mouse_friction, delta)
|
|
apply_rotation(rotational_velocity)
|
|
else:
|
|
apply_rotation(rotational_direction * deg_to_rad(get_sensitivity() / 10.0))
|
|
|
|
|
|
func _process_controller(delta: float) -> void:
|
|
rotational_direction = Input.get_vector(ACTION_CAMERA_LEFT, ACTION_CAMERA_RIGHT, ACTION_CAMERA_UP, ACTION_CAMERA_DOWN)
|
|
|
|
if controller_invert_x:
|
|
rotational_direction.x = -rotational_direction.x
|
|
|
|
if controller_invert_y:
|
|
rotational_direction.y = -rotational_direction.y
|
|
|
|
if controller_acceleration:
|
|
rotational_velocity = _lerp_rotational_velocity(deg_to_rad(get_sensitivity()), controller_friction, delta)
|
|
apply_rotation(rotational_velocity)
|
|
else:
|
|
apply_rotation(rotational_direction * deg_to_rad(get_sensitivity()))
|
|
|
|
|
|
func _lerp_rotational_velocity(sensitivity: float, friction: float, delta: float) -> Vector2:
|
|
return rotational_velocity.lerp(rotational_direction * sensitivity, friction * delta)
|