146 lines
4.8 KiB
GDScript
146 lines
4.8 KiB
GDScript
extends Camera3D
|
|
|
|
## Camera with flying script attached to it.
|
|
class_name Freecam3D
|
|
|
|
##
|
|
## Camera with toggleable freecam mode for prototyping when creating levels, shaders, lighting, etc.
|
|
##
|
|
## Usage: Run your game, press <TAB> and fly around freely. Uses Minecraft-like controls.
|
|
##
|
|
|
|
## Customize your own toggle key to avoid collisions with your current mappings.
|
|
@export var toggle_key: Key = KEY_TAB
|
|
## Speed up / down by scrolling the mouse whell down / up
|
|
@export var invert_speed_controls: bool = false
|
|
|
|
@export var overlay_text: bool = true
|
|
|
|
## Pivot node for camera looking around
|
|
@onready var pivot := Node3D.new()
|
|
## Main parent for camera overlay.
|
|
@onready var screen_overlay := VBoxContainer.new()
|
|
## Container for the chat-like event log.
|
|
@onready var event_log := VBoxContainer.new()
|
|
|
|
const MAX_SPEED := 0.25
|
|
const MIN_SPEED := 0.01
|
|
const ACCELERATION := 0.1
|
|
const MOUSE_SENSITIVITY := 0.002
|
|
|
|
## Whether or not the camera can move.
|
|
var movement_active := false:
|
|
set(val):
|
|
movement_active = val
|
|
display_message("[Movement ON]" if movement_active else "[Movement OFF]")
|
|
|
|
## The current maximum speed. Lower or higher it by scrolling the mouse wheel.
|
|
var target_speed := MIN_SPEED
|
|
## Movement velocity.
|
|
var velocity := Vector3.ZERO
|
|
|
|
|
|
## Sets up pivot and UI overlay elements.
|
|
func _setup_nodes() -> void:
|
|
self.add_sibling(pivot)
|
|
pivot.position = position
|
|
pivot.rotation = rotation
|
|
pivot.name = "FreecamPivot"
|
|
self.reparent(pivot)
|
|
self.position = Vector3.ZERO
|
|
self.rotation = Vector3.ZERO
|
|
# UI stuff
|
|
screen_overlay.add_theme_constant_override("Separation", 8)
|
|
self.add_child(screen_overlay)
|
|
screen_overlay.add_child(_make_label("Debug Camera"))
|
|
screen_overlay.add_spacer(false)
|
|
|
|
screen_overlay.add_child(event_log)
|
|
screen_overlay.visible = overlay_text
|
|
|
|
|
|
func _ready() -> void:
|
|
_setup_nodes.call_deferred()
|
|
_add_keybindings()
|
|
movement_active = true
|
|
Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)
|
|
|
|
|
|
|
|
func _process(delta: float) -> void:
|
|
|
|
if Input.is_action_just_released("__debug_camera_toggle"):
|
|
movement_active = not movement_active
|
|
|
|
if movement_active:
|
|
var dir = Vector3.ZERO
|
|
if Input.is_action_pressed("__debug_camera_forward"): dir.z -= 1
|
|
if Input.is_action_pressed("__debug_camera_back"): dir.z += 1
|
|
if Input.is_action_pressed("__debug_camera_left"): dir.x -= 1
|
|
if Input.is_action_pressed("__debug_camera_right"): dir.x += 1
|
|
if Input.is_action_pressed("__debug_camera_up"): dir.y += 1
|
|
if Input.is_action_pressed("__debug_camera_down"): dir.y -= 1
|
|
|
|
dir = dir.normalized()
|
|
dir = dir.rotated(Vector3.UP, pivot.rotation.y)
|
|
|
|
velocity = lerp(velocity, dir * target_speed, ACCELERATION)
|
|
pivot.position += velocity
|
|
|
|
|
|
func _input(event: InputEvent) -> void:
|
|
if movement_active:
|
|
# Turn around
|
|
if event is InputEventMouseMotion:
|
|
pivot.rotate_y(-event.relative.x * MOUSE_SENSITIVITY)
|
|
rotate_x(-event.relative.y * MOUSE_SENSITIVITY)
|
|
rotation.x = clamp(rotation.x, -PI/2, PI/2)
|
|
|
|
var speed_up = func():
|
|
target_speed = clamp(target_speed + 0.015, MIN_SPEED, MAX_SPEED)
|
|
display_message("[Speed up] " + str(target_speed))
|
|
|
|
var slow_down = func():
|
|
target_speed = clamp(target_speed - 0.015, MIN_SPEED, MAX_SPEED)
|
|
display_message("[Slow down] " + str(target_speed))
|
|
|
|
# Speed up and down with the mouse wheel
|
|
if event is InputEventMouseButton:
|
|
if event.button_index == MOUSE_BUTTON_WHEEL_UP and event.pressed:
|
|
slow_down.call() if invert_speed_controls else speed_up.call()
|
|
|
|
if event.button_index == MOUSE_BUTTON_WHEEL_DOWN and event.pressed:
|
|
speed_up.call() if invert_speed_controls else slow_down.call()
|
|
|
|
|
|
## Pushes new message label into "chat" and removes the old ones if necessary
|
|
func display_message(text: String) -> void:
|
|
while event_log.get_child_count() >= 3:
|
|
event_log.remove_child(event_log.get_child(0))
|
|
|
|
event_log.add_child(_make_label(text))
|
|
|
|
|
|
func _make_label(text: String) -> Label:
|
|
var l = Label.new()
|
|
l.text = text
|
|
return l
|
|
|
|
|
|
func _add_keybindings() -> void:
|
|
var actions = InputMap.get_actions()
|
|
if "__debug_camera_forward" not in actions: _add_key_input_action("__debug_camera_forward", KEY_W)
|
|
if "__debug_camera_back" not in actions: _add_key_input_action("__debug_camera_back", KEY_S)
|
|
if "__debug_camera_left" not in actions: _add_key_input_action("__debug_camera_left", KEY_A)
|
|
if "__debug_camera_right" not in actions: _add_key_input_action("__debug_camera_right", KEY_D)
|
|
if "__debug_camera_up" not in actions: _add_key_input_action("__debug_camera_up", KEY_E)
|
|
if "__debug_camera_down" not in actions: _add_key_input_action("__debug_camera_down", KEY_Q)
|
|
if "__debug_camera_toggle" not in actions: _add_key_input_action("__debug_camera_toggle", toggle_key)
|
|
|
|
|
|
func _add_key_input_action(name: String, key: Key) -> void:
|
|
var ev = InputEventKey.new()
|
|
ev.physical_keycode = key
|
|
|
|
InputMap.add_action(name)
|
|
InputMap.action_add_event(name, ev)
|