Controller and Keyboard Input works differently

Godot Version

Godot 4.2.1

Question

I’ve been testing controller input in a 3d player movement test I’m doing, and I just realized that it doesn’t work as intended when the camera is on top of the character (kinda like a bird view). When looking from that view, the character moves to the right when pressing up and/or down. the right and left inputs still work fine with the controller. I’m just having this issue with my controller and I don’t understand why.

At first, I thought it was something I did in “project settings → inputs”, but I couldn’t find anything related to the mouse or the Joypad 2 (right joystick). I then looked around and decided to add some camera input related to the right joystick, but it still gave me the input error. What am I missing?

extends CharacterBody3D

const MAX_SPEED = 10.0
const ACCELERATION = 20.0
const DECELERATION = 20.0
const JUMP_VELOCITY = 4.5

var gravity = ProjectSettings.get_setting("physics/3d/default_gravity")
var phantomCamera: PhantomCamera3D
var mouseSensitivity: float = 0.05

var minYaw: float = -89.9
var maxYaw: float = 50
var minPitch: float = 0
var maxPitch: float = 360

var rightJoystickInput: Vector2 = Vector2.ZERO

func _ready():
	# Find the Phantom Camera node by its path
	phantomCamera = $%PhantomCamera3D  # Update this with the correct path to your Phantom Camera node

	# Set mouse mode to captured to hide the cursor and confine it within the game window
	Input.set_mouse_mode(Input.MOUSE_MODE_CAPTURED)

func _physics_process(delta):
	# Add the gravity.
	if not is_on_floor():
		velocity.y -= gravity * delta

	# Handle Jump.
	if Input.is_action_just_pressed("ui_accept") and is_on_floor():
		velocity.y = JUMP_VELOCITY

	# Get the input direction and handle the movement.
	var input_dir = Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
	var camera_direction = -phantomCamera.global_transform.basis.z.normalized()
	var move_direction = (phantomCamera.global_transform.basis.x * input_dir.x + phantomCamera.global_transform.basis.z * input_dir.y)

	# Zero out the y-component and normalize the move direction vector
	move_direction.y = 0
	move_direction = move_direction.normalized()

	if input_dir.length_squared() > 0:
		# Calculate the target rotation based on the input direction
		var targetRotation = atan2(move_direction.x, move_direction.z)

		# Apply acceleration towards the maximum speed
		var target_speed = MAX_SPEED
		velocity.x = lerp(velocity.x, move_direction.x * target_speed, ACCELERATION * delta)
		velocity.z = lerp(velocity.z, move_direction.z * target_speed, ACCELERATION * delta)

	else:
		# Apply deceleration if not moving
		velocity.x = move_toward(velocity.x, 0, DECELERATION * delta)
		velocity.z = move_toward(velocity.z, 0, DECELERATION * delta)

	# Clamp velocity to the maximum speed
	velocity.x = clamp(velocity.x, -MAX_SPEED, MAX_SPEED)
	velocity.z = clamp(velocity.z, -MAX_SPEED, MAX_SPEED)

	# Update character's rotation based on camera rotation when moving forward or backward
	if input_dir:
		$%Character.look_at(global_transform.origin + move_direction, Vector3.UP)

	# Update camera position to follow the player
	if phantomCamera != null:
		phantomCamera.global_transform.origin = global_transform.origin

	# Set animation parameters
	$AnimationTree.set("parameters/conditions/idle", input_dir == Vector2.ZERO && is_on_floor())
	$AnimationTree.set("parameters/conditions/walk", input_dir != Vector2.ZERO && is_on_floor())
	$AnimationTree.set("parameters/conditions/falling", !is_on_floor())
	$AnimationTree.set("parameters/conditions/landed", is_on_floor())

	move_and_slide()

func _unhandled_input(event: InputEvent) -> void:
	if event is InputEventMouseMotion:
		if phantomCamera != null && phantomCamera.global_transform != null:
			var pcamRotationDegrees = phantomCamera.get_third_person_rotation_degrees()

			# Change the X rotation
			pcamRotationDegrees.x -= event.relative.y * mouseSensitivity
			# Clamp the rotation in the X axis so it doesn't go over or under the target
			pcamRotationDegrees.x = clampf(pcamRotationDegrees.x, minYaw, maxYaw)

			# Change the Y rotation value
			pcamRotationDegrees.y -= event.relative.x * mouseSensitivity
			# Sets the rotation to fully loop around its target, but without going below or exceeding 0 and 360 degrees respectively
			pcamRotationDegrees.y = wrapf(pcamRotationDegrees.y, minPitch, maxPitch)

			# Change the Phantom Camera node's rotation and rotate around its target
			phantomCamera.set_third_person_rotation_degrees(pcamRotationDegrees)

	elif event is InputEventJoypadMotion:
		if event.device == 2:  # Assuming "joypad 2" is the right joystick
			if event.axis == 0:  # Assuming axis 0 is the X axis of the right joystick
				rightJoystickInput.x = event.axis_value
			elif event.axis == 1:  # Assuming axis 1 is the Y axis of the right joystick
				rightJoystickInput.y = event.axis_value

func _process(delta):
	if rightJoystickInput != Vector2.ZERO:
		var pcamRotationDegrees = phantomCamera.get_third_person_rotation_degrees()

		# Change the X rotation
		pcamRotationDegrees.x -= rightJoystickInput.y * mouseSensitivity
		# Clamp the rotation in the X axis so it doesn't go over or under the target
		pcamRotationDegrees.x = clampf(pcamRotationDegrees.x, minYaw, maxYaw)

		# Change the Y rotation value
		pcamRotationDegrees.y -= rightJoystickInput.x * mouseSensitivity
		# Sets the rotation to fully loop around its target, but without going below or exceeding 0 and 360 degrees respectively
		pcamRotationDegrees.y = wrapf(pcamRotationDegrees.y, minPitch, maxPitch)

		# Change the Phantom Camera node's rotation and rotate around its target
		phantomCamera.set_third_person_rotation_degrees(pcamRotationDegrees)

		# Reset the right joystick input
		rightJoystickInput = Vector2.ZERO