Player appears to get boost in velocity when leaving slope

Godot Version

4.2.2 stable

Question

This is a 2D side-view platformer. The player is a CharacterBody2D being moved with move_and_slide().

Gravity is applied to the player. When the player is sliding down a slope, its real velocity is very different to its velocity prop due to being pushed by the slope. If a slope ends without a floor, when the player is sliding down the slope and slides off the bottom, the player will appear to get a sudden boost of downward velocity. What is the best way to deal with this issue?

I have tried applying gravity parallel to the slope and setting velocity to the real velocity when leaving a platform. I have yet to get desirable results, though I may have not implemented those solutions properly. What is the best way to deal with this issue?

It would probably help to see your script (or even better: a minimal project containing the issue). I couldn’t reproduce your issue with the default 2D movement script.

Here is a minimal project with the issue. Issue Reproduction.zip - Google Drive
I exaggerated floor_max_angle to make it very noticeable. Notice how when the character body leaves the slope, it appears to gain a burst of speed. It is also printing the real velocity Y so you can see how much it changes.

Well, in your example project, you set the y velocity to 1000 at the beginning of each frame, and the only thing that might change this value after that is move_and_slide – so no surprise there!

But even if you applied the gravity gradually over time (e.g. gravity += 10), it would still behave that way, simply because gravity is still applied while your character is sliding down the slope. You could disable that, but that would also mean that your character won’t accelerate further while sliding down.

So here’s a quickly hacked together “solution” to your problem:

var was_on_wall := false
var velocity_memory := 0.0

func _physics_process(delta):
	velocity.y += 10 # apply gravity
	
	move_and_slide()
	
	var is_on_wall = is_on_wall()
	
	if not was_on_wall and is_on_wall:
		# slope entered, remember y velocity
		velocity_memory = velocity.y
		
	if was_on_wall and not is_on_wall:
		# slope exited, restore y velocity
		velocity.y = velocity_memory
	
	was_on_wall = is_on_wall