Godot Version
4.4.1
Question
I tried to do a 3rd person character controller and it works fine if i use the camera's global_basis for the rotation, but when i changed it to work with the mesh's global_basis it doesn't work while i move forward, (AND ONLY FORWARD). I tried to debug it, but got nowhere, (I'm new to godot). I think i need some help with debugging/figuring this one out.
The code in question:
extends CharacterBody3D
enum TRAVEL_MODE { ON_FOOT, ON_BROOM }
var travel_mode: TRAVEL_MODE = TRAVEL_MODE.ON_FOOT
@export_group("Movement")
@export_range(0.0, 100.0) var max_movement_speed: float = 5.0
@export_range(0.0, 100.0) var acceleration: float = 30.0
@export_range(0.0, 100.0) var sprint_multiplier: float = 2.0
@export_range(0.0, 100.0) var rotation_speed: float = 12.0
@export_range(0.0, 100.0) var jump_strength: float = 10.0
const GRAVITY: float = -30.0
@export_group("Camera")
@export_range(0.01, 10.0) var vertical_mouse_sensitivity: float = 0.25
@export_range(0.01, 10.0) var horizontal_mouse_sensitivity: float = 0.25
const TILT_UPPER_LIMIT: float = 30.0
const TILT_LOWER_LIMIT: float = -30.0
var camera_input_direction: Vector2 = Vector2.ZERO
var last_movement_direction: Vector3 = Vector3.BACK
@onready var player_mesh: Node3D = $PlayerMesh
@onready var camera_pivot: Marker3D = $CameraPivot
@onready var spring_arm: SpringArm3D = $CameraPivot/SpringArm3D
@onready var camera: Camera3D = $CameraPivot/SpringArm3D/Camera3D
func _input(event: InputEvent) -> void:
if event.is_action_pressed("ui_cancel"):
Input.mouse_mode = Input.MOUSE_MODE_VISIBLE
elif event.is_action_pressed("ui_open"):
Input.mouse_mode = Input.MOUSE_MODE_CAPTURED
if event.is_action_pressed("change_travel_mode"):
if travel_mode == TRAVEL_MODE.ON_FOOT:
travel_mode = TRAVEL_MODE.ON_BROOM
else:
travel_mode = TRAVEL_MODE.ON_FOOT
func _unhandled_input(event: InputEvent) -> void:
if event is InputEventMouseMotion and Input.get_mouse_mode() == Input.MOUSE_MODE_CAPTURED:
camera_input_direction = event.screen_relative * Vector2(vertical_mouse_sensitivity, horizontal_mouse_sensitivity)
func _physics_process(delta: float) -> void:
camera_pivot.rotation.x += camera_input_direction.y * delta
camera_pivot.rotation.x = clamp(camera_pivot.rotation.x, deg_to_rad(TILT_LOWER_LIMIT), deg_to_rad(TILT_UPPER_LIMIT))
camera_pivot.rotation.y -= camera_input_direction.x * delta
camera_input_direction = Vector2.ZERO
var raw_input: Vector2 = Input.get_vector("move_left", "move_right", "move_backward", "move_forward")
var move_direction: Vector3
match travel_mode:
TRAVEL_MODE.ON_FOOT:
var forward: Vector3
var right: Vector3
if Input.is_action_pressed("free_look"):
forward = -player_mesh.global_basis.z
right = player_mesh.global_basis.x
else:
forward = -camera.global_basis.z
right = camera.global_basis.x
move_direction = forward * raw_input.y + right * raw_input.x
move_direction.y = 0.0
move_direction = move_direction.normalized()
var y_velocity: float = velocity.y
velocity.y = 0.0
var final_speed_max_speed: float = max_movement_speed
if Input.is_action_pressed("run"):
final_speed_max_speed *= sprint_multiplier
velocity = velocity.move_toward(move_direction * final_speed_max_speed, acceleration * delta)
if Input.is_action_just_pressed("jump") and is_on_floor():
velocity.y += jump_strength
else:
velocity.y = y_velocity + GRAVITY * delta
TRAVEL_MODE.ON_BROOM:
pass
move_and_slide()
if move_direction.length() > 0.2:
last_movement_direction = move_direction
var target_angle: float = Vector3.BACK.signed_angle_to(last_movement_direction, Vector3.UP)
player_mesh.global_rotation.y = lerp_angle(player_mesh.rotation.y, target_angle, rotation_speed * delta)