Making player move relative to camera

Godot Version

4.4.1

Question

Hello! I scraped together a player controller, but I am having a hard time figuring out:

How to make the player’s “forward” be the direction the camera is facing?

I am using an orthogonal camera for a 3D isometric game.
I plan to add camera rotation along the Y axis in respect to the player origin.

Right now the player goes in an unnatural direction. I want the player character to move diagonal up when “move_up” as if you pressed “move_up” and “move_left”. Same for “move_down”. And the left and right controls.

Player Node

> CharacterBody3D
>> Node3D (camera_pivot)
>>> Camera3D (orthogonal)

>> CollisionShape3D
>> misc nodes for visuals

Character/Player Controller Script

extends CharacterBody3D

const FLOOR_NORMAL = Vector3(0.0, 1.0, 0.0)

@export var speed := 5
@export var gravity := 30.0
@export var jump_force := 8.5

var velocity_y := 0.0

func _physics_process(delta: float) -> void:
	var str_mr = Input.get_action_strength("move_right")
	var str_ml = Input.get_action_strength("move_left")
	var str_mu = Input.get_action_strength("move_up")
	var str_md = Input.get_action_strength("move_down")
	
	if str_mr > 0 or str_ml > 0 or str_mu > 0 or str_md > 0:
		# Solves quick glitched rotation bug, may have introduced another
		#if atan2(velocity.x,velocity.z) == 0 and str_md > 0:
			#$visuals.rotation.y = atan2(velocity.x,velocity.z)
		#elif atan2(velocity.x,velocity.z) != 0:
			#$visuals.rotation.y = atan2(velocity.x,velocity.z)
		$visuals.rotation.y = atan2(velocity.x,velocity.z)
		if is_on_floor():
			$visuals/bee2/AnimationPlayer.play("run")
		else:
			$visuals/bee2/AnimationPlayer.play("hovering")
	elif is_on_floor():
		$visuals/bee2/AnimationPlayer.play("idle")
	else:
		$visuals/bee2/AnimationPlayer.play("hovering")
	
	var direction_ground := Vector2(
		str_mr - str_ml,
		str_md - str_mu
	).normalized()
	
	if not is_on_floor():
		velocity_y -= gravity * delta
	
	velocity = Vector3(
		direction_ground.x * speed,
		velocity_y,
		direction_ground.y * speed
	)
	
	move_and_slide()
	
	if is_on_floor() or is_on_ceiling():
		velocity_y = 0.0

func _unhandled_input(event: InputEvent) -> void:
	if event.is_action_pressed("action_jump") and is_on_floor():
		velocity_y = jump_force

The full project will be open sourced so I don’t mind sharing anything. It’s just really messy since I started it a few hours ago. If you want a zip/tar of the project files for clarity, please reply!

Maybe it’s really simple and I stayed up too late. Thanks! Thank you, thank you!

Unfortunately I have only a C# example at the moment.
Maybe this helps you:

    public override Vector3 GetMoveDirection()
    {
        Vector2 inputDir = Input.GetVector("move_left", "move_right", "move_forward", "move_backward");

        Vector3 forward = _camera.Transform.Basis.Z;
        Vector3 right = _camera.Transform.Basis.X;

        forward.Y = 0f;
        right.Y = 0f;

        return forward.Normalized() * inputDir.Y + right.Normalized() * inputDir.X;
    }

Figured it out. Thanks for the reply!

var input_dir = Input.get_vector("move_left", "move_right", "move_up", "move_down")
var direction_ground = Vector3(input_dir.x, 0, input_dir.y).rotated(Vector3.UP, $camera_pivot/Camera3D.rotation.y)

Be sure to use the actual rotated node. So if you only rotated $camera_pivot/Camera3D at maybe 45deg for an orthogonal view, you must use the rotation.y of that node.
$camera_pivot/Camera3D.rotation.y

I wasn’t able to rotate $camera_pivot instead, it had position issues probably due to the camera being positioned differently as well. I will figure out the new correct position later.

and I found a way to make rotation smooth

velocity = lerp(velocity, direction_ground * speed, 4 * delta)
velocity.y = velocity_y

Right now I am just rotating the player model, but I can also rotate whatever I do need facing forward later.

$visuals.rotation.y = atan2(velocity.x,velocity.z)

What helped me:

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.