Decrease in speed causes weird character movement

Godot Version

Godot 4


Hi all,

I’m trying to implement a slow decrease in speed for my CharacterBody2D. The goal is to let my character slide over slippery surfaces and to just have a feeling of the body having some weight to it. I can get it to work, but only when i’m not normalizing my velocity. Otherwise, my character is showing some weird movement behaviour.

For example, when i move left and right using button presses in a fast sequence, i can move left by keeping the right key pressed. It also spawns to different locations.

I suspect this is because for the physics engine there is a brief moment where the speed of one button press is applied to the speed of a different button press. And the change of direction is not proccessed yet or something alone those lines.

But i cannot figure out why this is happening. I have googled extensively and i have implemented multiple systems to handle the decrease in speed, based of internet examples. But what i currently have is the most basic system and i feel that it should work.

Here is my current code (i left it in a subpar state, don’t hate me. I’ve gone through dozens of iterations and am just experimenting at this point before i tidy anything up):

extends CharacterBody2D

@export var maxSpeed = 115
@export var runSpeed = 1.5 # multiplier
@export var acceleration:float = 10 # Lower is faster acceleration
@export var decceleration:float = 1.5 # Lower is faster decceleration

var currentSpeed = 0
var direction

func get_desiredSpeed(maxSpeed):
	if currentSpeed < maxSpeed:
		var accelSteps:float = maxSpeed / acceleration
		#print('accelerating: ', currentSpeed, ' ', maxSpeed, ' ', acceleration, ' ', accelSteps)
		currentSpeed = currentSpeed + accelSteps
		#print('desiredSpeed_accel: ', currentSpeed)
		return currentSpeed
	elif currentSpeed >= maxSpeed and !Input.is_action_pressed("run"):
		#print('desiredSpeed_max: ', currentSpeed)
		currentSpeed = maxSpeed
		return currentSpeed
	elif currentSpeed >= maxSpeed and Input.is_action_pressed("run"):
		#print('desiredSpeed_run: ', currentSpeed)
		currentSpeed = maxSpeed * runSpeed
		return currentSpeed
func read_input():
	var directionX = Input.get_axis("left", "right")
	var directionY = Input.get_axis("up", "down")

	if directionX:
		currentSpeed = get_desiredSpeed(maxSpeed)
		velocity.x = directionX
		#currentSpeed = 0
		velocity.x = move_toward(velocity.x, 0, decceleration)
	if directionY:
		currentSpeed = get_desiredSpeed(maxSpeed)
		velocity.y = directionY
		#currentSpeed = 0
		velocity.y = move_toward(velocity.y, 0, decceleration)
	if !directionY and !directionX:
		currentSpeed = 0
	velocity = velocity.normalized() * currentSpeed

func _physics_process(delta):