You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
101 lines
2.8 KiB
GDScript
101 lines
2.8 KiB
GDScript
# Copyright © 2017 Hugo Locurcio and contributors - MIT license
|
|
# See LICENSE.md included in the source distribution for more information.
|
|
|
|
extends Camera3D
|
|
|
|
const MOVE_SPEED = 8
|
|
const MOUSE_SENSITIVITY = 0.002
|
|
const CAMERA_FAR_STEP = 200
|
|
var rot_target := Vector3(0, 0, 0)
|
|
@onready var speed := 1
|
|
@onready var velocity := Vector3()
|
|
@onready var initial_rotation: float = PI / 2.0
|
|
|
|
|
|
func _enter_tree():
|
|
# Capture the mouse (can be toggled by pressing F10)
|
|
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
|
|
|
|
|
|
func _input(event):
|
|
# Horizontal mouse look
|
|
if event is InputEventMouseMotion and Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:
|
|
rot_target.y -= event.relative.x * MOUSE_SENSITIVITY
|
|
|
|
# wrap horizontal mouselook
|
|
if rot_target.y > PI:
|
|
rot_target.y -= 2 * PI
|
|
if rot_target.y < -PI:
|
|
rot_target.y += 2 * PI
|
|
|
|
# Vertical mouse look, clamped to -90..90 degrees
|
|
if event is InputEventMouseMotion and Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:
|
|
rot_target.x = clamp(
|
|
rot_target.x - event.relative.y * MOUSE_SENSITIVITY, deg_to_rad(-90), deg_to_rad(90)
|
|
)
|
|
|
|
# Toggle mouse capture
|
|
if event.is_action_pressed("ui_accept"):
|
|
if Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:
|
|
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
|
|
else:
|
|
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
|
|
|
|
if Input.is_action_just_pressed("ui_cancel"):
|
|
get_tree().quit()
|
|
|
|
|
|
func _physics_process(delta):
|
|
# Apply rotation
|
|
rotation = slerp_euler_no_z(rotation, rot_target, 20 * delta)
|
|
|
|
# Movement
|
|
speed = MOVE_SPEED
|
|
if Input.is_action_pressed("ui_up"):
|
|
velocity.x -= speed * delta
|
|
|
|
if Input.is_action_pressed("ui_down"):
|
|
velocity.x += speed * delta
|
|
|
|
if Input.is_action_pressed("ui_left"):
|
|
velocity.z += speed * delta
|
|
|
|
if Input.is_action_pressed("ui_right"):
|
|
velocity.z -= speed * delta
|
|
|
|
if Input.is_action_just_pressed("ui_page_up"):
|
|
far += CAMERA_FAR_STEP
|
|
|
|
if Input.is_action_just_pressed("ui_page_down"):
|
|
far -= CAMERA_FAR_STEP
|
|
|
|
# Friction
|
|
velocity *= 0.875
|
|
|
|
# Apply velocity
|
|
position += (
|
|
velocity
|
|
. rotated(Vector3(0, 1, 0), rotation.y - initial_rotation)
|
|
. rotated(Vector3(1, 0, 0), cos(rotation.y) * rotation.x)
|
|
. rotated(Vector3(0, 0, 1), -sin(rotation.y) * rotation.x)
|
|
)
|
|
|
|
|
|
func _exit_tree():
|
|
# Restore the mouse cursor upon quitting
|
|
Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)
|
|
|
|
|
|
## Spherical linear interpolate between two rotations, removing any Z rotation
|
|
## Useful for lerping camera rotation with mouse movement
|
|
func slerp_euler_no_z(initial_rot, target_rot, weight):
|
|
var i_b = Basis.from_euler(initial_rot)
|
|
var t_b = Basis.from_euler(target_rot)
|
|
var init_trans = Transform3D(i_b, Vector3(0, 0, 0))
|
|
var target_trans = Transform3D(t_b, Vector3(0, 0, 0))
|
|
|
|
var final_trans = init_trans.interpolate_with(target_trans, weight)
|
|
var final_rot = final_trans.basis.get_euler()
|
|
final_rot.z = 0
|
|
return final_rot
|