Godot Version
4.3
Question
Hi! I have an issue with character movement that’s got me at a complete loss. I’m making a game in 3D, however the camera is orthographic and up in the sky at a 45 degree angle to give the feel of a 2D isometric game. Everything works as expected with regards to character movement except one issue. When I rotate the camera, I rotate the character as well, however the direction the character moves doesn’t update to match their rotation.
For instance, if I rotate the camera 90 degrees to the left, the character rotates along with it (so you’re still looking at their back), but when pressing the “up” input action, the character is now moving right. I’d expect the character to move away from the camera as they would with the default transform. Hope this is clear enough. Here’s a screenshot of the game currently:
The parent of the camera is a Node3D called CameraPivot that handles rotation. Here’s its attached script:
extends Node3D
@onready var player: CharacterBody3D = get_tree().get_nodes_in_group("PlayerCharacter")[0]
@onready var sky_camera: Camera3D = $SkyCamera
# Called when the node enters the scene tree for the first time.
func _ready() -> void:
pass # Replace with function body.
# Called every frame. 'delta' is the elapsed time since the previous frame.
func _process(delta: float) -> void:
# Handle camera rotation
if Input.is_action_pressed("rotate_camera_left"):
rotation_degrees.y -= 1
player.rotation_degrees.y -= 1
if Input.is_action_pressed("rotate_camera_right"):
rotation_degrees.y += 1
player.rotation_degrees.y += 1
func _input(event: InputEvent) -> void:
if Input.is_action_just_pressed("zoom_in"):
if sky_camera.size > 5:
sky_camera.size -= 1
if Input.is_action_just_pressed("zoom_out"):
if sky_camera.size < 100:
sky_camera.size += 1
`
And then the script for the player character:
`
extends CharacterBody3D
@onready var camera_pivot = get_tree().get_nodes_in_group("PlayerCharacter")[1]
@export var _rotation_speed : float = TAU
const SPEED = 5.0
const JUMP_VELOCITY = 4.5
var _theta : float
func _physics_process(delta: float) -> void:
# Add the gravity.
if not is_on_floor():
velocity += get_gravity() * delta
# Handle jump.
if Input.is_action_just_pressed("jump") and is_on_floor():
velocity.y = JUMP_VELOCITY
# Get the input direction and handle the movement/deceleration.
# As good practice, you should replace UI actions with custom gameplay actions.
var input_dir := Input.get_vector("move_right", "move_left", "move_down", "move_up")
var direction := (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
if direction:
# Handle character rotation to look in the direction of movement
_theta = wrapf(atan2(input_dir.x, input_dir.y) - rotation.y, -PI, PI)
rotation.y += clamp(_rotation_speed * delta, 0, abs(_theta)) * sign(_theta)
# Movement is 3D, sure, but we treat it as if it's 2D so as not to bork rotation etc.
# Otherwise, when character rotates, velocity is relative to how they're facing
velocity.x = input_dir.x * SPEED
velocity.z = input_dir.y * SPEED
else:
velocity.x = move_toward(velocity.x, 0, SPEED)
velocity.z = move_toward(velocity.z, 0, SPEED)
move_and_slide()
I guess my question boils down to:
How can I update the direction that my character sees as “up” when rotating the camera?
Any help is massively appreciated, thanks for reading!