class_name FlyCamera extends Camera3D # WASD + QE + mouse look fly camera. No collision — you fly through walls # on purpose, so you can inspect the dungeon from any angle. @export var move_speed := 8.0 @export var boost_multiplier := 3.0 @export var mouse_sensitivity := 0.002 var _yaw := 0.0 var _pitch := 0.0 var _captured := false func _ready() -> void: _capture() _yaw = rotation.y _pitch = rotation.x func _capture() -> void: Input.mouse_mode = Input.MOUSE_MODE_CAPTURED _captured = true func _release() -> void: Input.mouse_mode = Input.MOUSE_MODE_VISIBLE _captured = false func _unhandled_input(event: InputEvent) -> void: if event is InputEventMouseMotion and _captured: var m := event as InputEventMouseMotion _yaw -= m.relative.x * mouse_sensitivity _pitch -= m.relative.y * mouse_sensitivity _pitch = clamp(_pitch, deg_to_rad(-85.0), deg_to_rad(85.0)) rotation = Vector3(_pitch, _yaw, 0.0) elif event is InputEventKey and event.pressed and event.keycode == KEY_ESCAPE: _release() elif event is InputEventMouseButton and event.pressed and not _captured: _capture() func _process(delta: float) -> void: var input := Vector3.ZERO if Input.is_key_pressed(KEY_W): input.z -= 1.0 if Input.is_key_pressed(KEY_S): input.z += 1.0 if Input.is_key_pressed(KEY_A): input.x -= 1.0 if Input.is_key_pressed(KEY_D): input.x += 1.0 if Input.is_key_pressed(KEY_E): input.y += 1.0 if Input.is_key_pressed(KEY_Q): input.y -= 1.0 var speed := move_speed if Input.is_key_pressed(KEY_SHIFT): speed *= boost_multiplier if input == Vector3.ZERO: return # Horizontal movement is yaw-relative; vertical stays in world space. var yaw_basis := Basis(Vector3.UP, _yaw) var dir := yaw_basis * Vector3(input.x, 0.0, input.z) dir.y = input.y dir = dir.normalized() position += dir * speed * delta