117 lines
3.4 KiB
GDScript
117 lines
3.4 KiB
GDScript
class_name FreeLookCamera extends Camera3D
|
|
|
|
# Modifier keys' speed multiplier
|
|
const SHIFT_MULTIPLIER = 2.5
|
|
const ALT_MULTIPLIER = 1.0 / SHIFT_MULTIPLIER
|
|
|
|
|
|
@export_range(0.0, 1.0) var sensitivity: float = 0.25
|
|
|
|
# Mouse state
|
|
var _mouse_position = Vector2(0.0, 0.0)
|
|
var _total_pitch = 0.0
|
|
|
|
# Movement state
|
|
var _direction = Vector3(0.0, 0.0, 0.0)
|
|
var _velocity = Vector3(0.0, 0.0, 0.0)
|
|
var _acceleration = 30
|
|
var _deceleration = -10
|
|
var _vel_multiplier = 4
|
|
|
|
# Keyboard state
|
|
var _w = false
|
|
var _s = false
|
|
var _a = false
|
|
var _d = false
|
|
var _q = false
|
|
var _e = false
|
|
var _shift = false
|
|
var _alt = false
|
|
|
|
func _unhandled_input(event):
|
|
# Receives mouse motion
|
|
if event is InputEventMouseMotion:
|
|
_mouse_position = event.relative
|
|
|
|
# Receives mouse button input
|
|
if event is InputEventMouseButton:
|
|
match event.button_index:
|
|
MOUSE_BUTTON_RIGHT: # Only allows rotation if right click down
|
|
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED if event.pressed else Input.MOUSE_MODE_VISIBLE)
|
|
MOUSE_BUTTON_WHEEL_UP: # Increases max velocity
|
|
_vel_multiplier = clamp(_vel_multiplier * 1.1, 0.2, 20)
|
|
MOUSE_BUTTON_WHEEL_DOWN: # Decereases max velocity
|
|
_vel_multiplier = clamp(_vel_multiplier / 1.1, 0.2, 20)
|
|
|
|
# Receives key input
|
|
if event is InputEventKey:
|
|
match event.keycode:
|
|
KEY_W:
|
|
_w = event.pressed
|
|
KEY_S:
|
|
_s = event.pressed
|
|
KEY_A:
|
|
_a = event.pressed
|
|
KEY_D:
|
|
_d = event.pressed
|
|
KEY_Q:
|
|
_q = event.pressed
|
|
KEY_E:
|
|
_e = event.pressed
|
|
KEY_SHIFT:
|
|
_shift = event.pressed
|
|
KEY_ALT:
|
|
_alt = event.pressed
|
|
|
|
# Updates mouselook and movement every frame
|
|
func _process(delta):
|
|
_update_mouselook()
|
|
_update_movement(delta)
|
|
|
|
# Updates camera movement
|
|
func _update_movement(delta):
|
|
# Computes desired direction from key states
|
|
_direction = Vector3(
|
|
(_d as float) - (_a as float),
|
|
(_e as float) - (_q as float),
|
|
(_s as float) - (_w as float)
|
|
)
|
|
|
|
# Computes the change in velocity due to desired direction and "drag"
|
|
# The "drag" is a constant acceleration on the camera to bring it's velocity to 0
|
|
var offset = _direction.normalized() * _acceleration * _vel_multiplier * delta \
|
|
+ _velocity.normalized() * _deceleration * _vel_multiplier * delta
|
|
|
|
# Compute modifiers' speed multiplier
|
|
var speed_multi = 1
|
|
if _shift: speed_multi *= SHIFT_MULTIPLIER
|
|
if _alt: speed_multi *= ALT_MULTIPLIER
|
|
|
|
# Checks if we should bother translating the camera
|
|
if _direction == Vector3.ZERO and offset.length_squared() > _velocity.length_squared():
|
|
# Sets the velocity to 0 to prevent jittering due to imperfect deceleration
|
|
_velocity = Vector3.ZERO
|
|
else:
|
|
# Clamps speed to stay within maximum value (_vel_multiplier)
|
|
_velocity.x = clamp(_velocity.x + offset.x, -_vel_multiplier, _vel_multiplier)
|
|
_velocity.y = clamp(_velocity.y + offset.y, -_vel_multiplier, _vel_multiplier)
|
|
_velocity.z = clamp(_velocity.z + offset.z, -_vel_multiplier, _vel_multiplier)
|
|
|
|
translate(_velocity * delta * speed_multi)
|
|
|
|
# Updates mouse look
|
|
func _update_mouselook():
|
|
# Only rotates mouse if the mouse is captured
|
|
if Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:
|
|
_mouse_position *= sensitivity
|
|
var yaw = _mouse_position.x
|
|
var pitch = _mouse_position.y
|
|
_mouse_position = Vector2(0, 0)
|
|
|
|
# Prevents looking up/down too far
|
|
pitch = clamp(pitch, -90 - _total_pitch, 90 - _total_pitch)
|
|
_total_pitch += pitch
|
|
|
|
rotate_y(deg_to_rad(-yaw))
|
|
rotate_object_local(Vector3(1,0,0), deg_to_rad(-pitch))
|