How do I get my player controller to move straight?

Godot Version

4.3.stable

Context

I’m creating a physics-based character controller. The character is a Rigidbody3D that hovers a bit above the ground using forces to avoid getting stuck on rough surfaces. The body is moved by using apply_central_force, rotated with a node controlled by camera movement.

Question

The problem is that the body doesn’t move exactly as it should, unless the camera is facing a cardinal direction or 45 degrees from one. It will be slightly off. Is there something I’m missing, or a different function I should use? Or is my whole controller wrong? I’m afraid that apply_central_force may just be the wrong function to use.

Here’s a video of the problem

This is the relevant hierarchy:

  • Rigidbody
    • Collider
    • CameraHolder
      • Camera

Here’s the relevant movement code (done in physics_process):

move_input = Input.get_vector("Left", "Right", "Forward", "Backward")
	var dir = Vector3(move_input.x, 0, move_input.y)
	velocity = dir * acceleration 
	if move_input.length() > 0.2:
		apply_central_force(velocity.rotated(Vector3.UP, deg_to_rad(head.rotation_degrees.y))) # add equation to "rotate" velocity with camera view
		print(dir)
		var speed: float
		if sprinting:
			speed = run_speed
		else:
			speed = walk_speed
		
		linear_velocity.x = clamp(linear_velocity.x, -speed, speed)
		linear_velocity.z = clamp(linear_velocity.z, -speed, speed)

And relevant camera code (done in process):

camera.rotation_degrees.x -= mouse_input.y * view_sensitivity * delta
camera.rotation_degrees.x = clamp(camera.rotation_degrees.x, -85, 85)
head.rotation_degrees.y -= mouse_input.x * view_sensitivity * delta
mouse_input = Vector2.ZERO

I’d guess the issue is that you are clamping linear_velocity.x and linear_velocity.z separatly. For 45° directions this only affects the length of the velocity vector, but for other angles it also changes the velocity’s direction. You can try if doing this instead prevents the issue:

var horizontal_velocity := Vector2(linear_velocity.x, linear_velocity.z)
var clamped_velocity := horizontal_velocity.limit_length(speed)
linear_velocity.x = clamped_velocity.x
linear_velocity.z = clamped_velocity.y
1 Like