Character movement slows down when camera on top

Godot Version

Godot 4.2.1

Question

This script I have is acceptable in almost every way for what I need, but the way it works makes it so that the character tilts in the camera’s direction when moving. For example, if I move the camera above the character, the character will tilt upwards. I assume it’s how I settled the camera rotation with the input, but it was the only way I found to give the character a free camera while facing the direction of the input.

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

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).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.y != 0:
		$%Character.look_at(global_transform.origin + move_direction, Vector3.UP)
	elif input_dir.x != 0:
		$%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)


I changed the “If input_dir:” line to

#Update the character's rotation based on camera rotation when moving forward or backward
	if input_dir:
		move_direction.y = 0  # Zero out the y-component
		$%Character.look_at(global_transform.origin + move_direction, Vector3.UP)

It fixed the tilting but I just realized that the movement speed reduces dramatically when the camera is facing up, looking at the top of the head of the character (kinda like a bird’s view).I assume it has to do with the “var move_direction” line but idk how. This is the entire script now:

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

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).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:
		move_direction.y = 0  # Zero out the y-component
		$%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)


It was an easy fix related to the move_direction lol

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