Godot Orbital Camera Controller
I made an orbital camera controller for someone who wanted help on the Godot Discord channel. Here’s the source. When applied to a Camera Node it gives this kind of behavior:

This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extends Camera | |
export var follow_target_path:NodePath = "" | |
var follow_target:Node | |
export var follow_distance:float = 5.0 | |
export var follow_height:float = 1.0 | |
export var mouse_sensitivity_x:float = 0.005 | |
export var mouse_sensitivity_y:float = 0.005 | |
var last_mouse_delta:Vector2 = Vector2() | |
var mouse_accumulator:Vector2 = Vector2() # The reason we have this instead of using the mouse.position is 'cause when we capture the camera, this will always be 0. | |
func _ready(): | |
follow_target = get_node(follow_target_path) | |
func _process(delta): | |
# Looking. Rotate _this_. Tilt _camera_. | |
mouse_accumulator += last_mouse_delta # TODO: Cap the Y component. | |
last_mouse_delta = Vector2() # Reset after we process the mouse so we don't accumulate between events. | |
# Calculate our new position. | |
var look_target = follow_target.global_transform.origin + Vector3(0, follow_height, 0) | |
var target_position = look_target + \ | |
Vector3(cos(mouse_accumulator.x*mouse_sensitivity_x), sin(mouse_accumulator.y*mouse_sensitivity_y), sin(mouse_accumulator.x*mouse_sensitivity_x))*follow_distance | |
self.look_at_from_position(target_position, look_target, Vector3(0, 1, 0)) | |
# For mouse handling: | |
func _input(event): | |
if event is InputEventMouseMotion: | |
#event.position Will always be center when in capture mode. Same with event.speed. | |
last_mouse_delta = event.relative |
The player controller is fairly straightforward, so I’ve not included it as a separate gist. For a Kinematic Player, one can move relative to the camera direction like so:
extends KinematicBody
export var walk_speed:float = 5.0
func _process(delta):
# Walking in the direction the camera is pointing.
var camera = get_viewport().get_camera()
var dy = int(Input.is_action_pressed("move_forward")) - int(Input.is_action_pressed("move_backward"))
var dx = int(Input.is_action_pressed("move_left")) - int(Input.is_action_pressed("move_right"))
var move = (camera.global_transform.basis.x * -dx) + (camera.global_transform.basis.z * -dy)
move = Vector3(move.x, 0, move.z).normalized() # Take out the 'looking down' component.
self.move_and_slide(move*walk_speed)