Player movement slows down when switching from from cardinal direction to diagonal direction

Godot Version

4.2.1

Question

I’m trying to make a topdown racing game but the movement is a bit off.

	if direction:
		# Get the angle to the desired direction
		var target_angle = direction.angle()
		# Smoothly rotate towards that angle
		rotation = lerp_angle(rotation, target_angle, TURN_SPEED * delta)

	if direction.x: #move_toward() dosent work with vectors so its been split into x and y
		velocity.x = move_toward(velocity.x, max_speed*direction.x, 12.5)
	if direction.y:
		velocity.y = move_toward(velocity.y, max_speed*direction.y, 12.5)

#slowly move towards standing still
	velocity.x = move_toward(velocity.x, 0, 1)
	velocity.y = move_toward(velocity.y, 0, 1)

This works fine but it’s not exactly what i want and feels a bit off for a racing game.
right now when input is “Up” and switches to “Up + left” the player slows down. This is because the code does what its meant to do.

How can I make the movement more “drifty”
instead of immediately slowing down when changing directions it should happen more gradually? (if that makes sense)

Any and all help is appreciated :slight_smile:

First thing to do it to accelerate to your rotation instead of the input direction. That way the car accelerates down the forward axis like it would IRL.

This is a very accessible resource that goes in depth on top down car physics. TLDR, implement deceleration through friction (wheels and air) and implement variable traction based on speed.

1 Like

There is a move_toward() function on the Vector2 class.

So your code could be simplified to

	if direction:
		# Get the angle to the desired direction
		var target_angle = direction.angle()
		# Smoothly rotate towards that angle
		rotation = lerp_angle(rotation, target_angle, TURN_SPEED * delta)
		# Move towards desired direction and speed
		velocity = velocity.move_toward(max_speed*direction, 12.5)

	#slowly move towards standing still
	velocity = velocity.move_toward(Vector2.ZERO, 1)

But I would suggest making a couple more changes to the code, so that it goes towards the direction of the rotation, and not against it.

extends CharacterBody2D

const TURN_SPEED: float = 3.0
const MAX_SPEED: float = 200.0
const ACCELERATION: float = 3.0
const DECELERATION: float = 3.0

func _physics_process(delta: float) -> void:
	var direction: Vector2 = Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down").normalized()
	if direction:
		# Get the angle to the desired direction
		var target_angle: float = direction.angle()
		# Smoothly rotate towards that angle
		rotation = lerp_angle(rotation, target_angle, TURN_SPEED * delta)
		
		# Get the angle to the desired direction
		var target_velocity: Vector2 = transform.x * MAX_SPEED
		# Move towards desired direction and speed
		velocity = velocity.move_toward(target_velocity, ACCELERATION)
	
	else:
		#slowly move towards standing still
		velocity = velocity.move_toward(Vector2.ZERO, DECELERATION)
	move_and_slide()

See here a quick demo how it works.

2 Likes

I will definitely check this out! Thank you!

This is a lot smoother than what I had :slight_smile: Thank you!