Vertical velocity incorrectly reset moving down slopes while grounded.

Godot Version

Godot 4.4.1

Question

I have a particular issue when trying to work on 2D slope physics, which seems to be a huge limitation when attempting to interact with more complicated movement physics. I would like to know if this behavior has a specific workaround.

The issue is that when setting downwards floor velocities on slopes (example here is using 45 degree slopes), move_and_slide will always completely negate the velocity.y component and reset that to 0. What happens is an incorrect velocity length, about only 0.707 of the original set velocity.

Here is a dummy script that exemplifies this issue. In theory the SPEED of the character should be 800 always when moving up and down slopes, but it is actually outputting ~565 on downward slopes, due to velocity being reset to Vector2(800, 0) every frame, then adjusting the velocity angle.

Here is the actual source code I am working with:

Setting floor_stop_on_slope and floor_constant_speed as below and floor_snap_length to 0 will occasionally fix this issue, but it isn’t consistent when it decides to work or not… meaning it’s not a viable solution.

extends CharacterBody2D


const SPEED = 800.0
const JUMP_VELOCITY = -1000.0


func _init():
	self.floor_stop_on_slope = false
	self.floor_constant_speed = true
	self.floor_snap_length = 50
	self.set_floor_stop_on_slope_enabled(false)


func _physics_process(delta: float) -> void:
	# Add the gravity.
	if not is_on_floor():
		velocity += get_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/deceleration.
	var direction := Input.get_axis("ui_left", "ui_right")
	print(velocity.length())  # this is incorrectly 565 when moving down slopes
	if direction:
		if self.is_on_floor():
			velocity = direction * SPEED * self.get_floor_normal().orthogonal().normalized() * -1
		else:
			velocity.x = direction * SPEED
	else:
		if self.is_on_floor():
			velocity = Vector2(0, 0)
		else:
			velocity.x = 0
	
	move_and_slide()

I understand what your issue is but how does that affect how your character moves versus how it’s supposed to?

Can’t test ur game cuz im on my phone rn

In the case of the dummy script - it simply doesn’t move at the velocity i want it set to. It makes moving downwards clunkier because it’s slower than moving upwards or on flat ground.

For how I actually want it implemented - it completely kills any form of logic requiring acceleration. I want interesting ground slope interaction for sliding, running, and transferring falling momentum directly into slope sliding momentum. That simply isn’t possible at all with how the engine handles it currently.

Play with these settings on your CharacterBody2D. For example, it sounds like you want to turn stop_on_slope = false You also might consider changing the max_angle to a greater or lesser angle to see if that gives the feel you want.