Godot Version
Godot 4.6
Question
I’ve been banging my head on the wall over this issue for literal months now, dropped my project temporarily because of it, and now that I got a little spare time, I’m picking this up again.
My question is pretty simple. I’m making a 2D platformer with slope physics, and I want my player to 1- slide on a slope when standing on it, and 2- be able to launch themselves from a slope when running fast enough. The player is a CharacterBody2D.
For slope sliding, just setting floor_stop_on_slope to false doesn’t make it slide fast enough, so I decided to apply a slope force after the gravity manually:
# This is called on _physics_process().
# _body_on_floor stores body.is_on_floor() for the current frame,
# _gravity_vector stores body.get_gravity().
func _apply_slope_slide(delta : float) -> void:
if _body_on_floor:
var floor_normal = body.get_floor_normal()
body.velocity += floor_normal * _gravity_vector.length() * delta
Not sure if this is the right way to go, but it if works, it works, I guess.
Now here’s the annoying part: launch the player from the slope. Nothing I do ever works. For some reason, if the player run towards the edge of a platform, instead of keeping the same velocity in both axes, the vertical velocity always get set to 0 for some reason. This happens when running either up or down the slope. Here’s a video showing the issue:
I was having this other issue where the player would snap off the slope if running too fast on the horizontal axis, but turning up floor_snap_lengthseemed to make things better.
I really need some help here 
Okay, I think I did a workaround to the slope launching thing that got me almost there:
func _do_body_movement() -> void:
var body_was_on_floor := _on_floor
var last_real_velocity := body.get_real_velocity()
body.move_and_slide()
var body_is_on_floor := body.is_on_floor()
# If the player left the floor without jumping, keep previous real velocity
if body_was_on_floor and not body_is_on_floor and not _just_jumped:
print("Dropping down a platform!")
body.velocity = last_real_velocity
But it’s not really consistent yet, sometimes the character is launched off the slope just right, sometimes it sort of “trips” on the edge of the slope and gets launched in more of a downward angle instead. I’m also still having the other issue where the player would snap off the slope if running too fast. Here’s how it looks right now:
Tweaking the body’s floor_snap_length seems to fix one issue but make the the other one worse, or maybe I’m just going insane…
Could you maybe make a short video what is it looks like?
I did actually, there’s a link in my last post. I can’t post the link again for some reason.
When the body moves away from the floor, it prints a message on the console. You can see how it’s happening inconsistently in the video.
Be aware that Imgur stuff cannot be viewed in the UK, as Imgur refused to sign up to the UK legislation concerning child-friendly content. Just sayin’. 
Thanks for letting me know, I uploaded the videos to a different host.
EDIT: Nevermind, I managed to add the video files directly on my posts 
Okay, I think I found a solution. Since I really need more granular control over the character’s velocity and using move_and_slide() was causing so many issues, I decided to ditch it altogether and make my own body movement code using move_and_collide() instead (which is what move_and_slide() uses internally anyway).
I used this tutorial in the docs along with this video and the article linked in its description as the basis for this new movement code:
func _physics_process(delta: float) -> void:
_handle_movement(delta)
func _handle_movement(delta : float) -> void:
# Add gravity to the body
body.velocity += body.get_gravity() * delta
# Do whatever else you want here, player movement, jumping and whatnot
# Apply final movement
_collide_and_slide(delta)
func _collide_and_slide(delta : float) -> void:
# Make sure you don't divide by zero
# Can't have any movement while delta is zero anyway
if delta == 0:
return
# We'll use the CharacterBody2D's own properties for calculations
# The body's movement in this frame will be its velocity vector times delta
var remainder := body.velocity * delta
# Also count the number of slides occurred
# so we can limit how many of them can happen
var slides : int = 0
# Repeat this as long as we haven't reached the max number of slides
while slides < body.max_slides:
# Apply remaining movement
var collision := body.move_and_collide(remainder)
# If no collision happened, wrap it up
if not collision:
body.velocity = remainder / delta
return
# Otherwise, "slide" the remaining movement vector along the surface
remainder = remainder.slide(collision.get_normal())
slides += 1
# Max number of slides reached, so this is our final velocity
body.velocity = remainder / delta
With this code I managed to get both the slope sliding and launching working properly, so that’s two birds killed with one stone.
If you follow this method, keep in mind you’ll have to reimplement other CharacterBody2D functionalities that rely on move_and_slide() such as is_on_floor() and get_platform_velocity(). Honestly after all I went through, this is a fair trade-off.
So far I only needed to check for floor collision so this is what I did:
func _update_floor_state() -> void:
# Make a "test" movement downward (or whichever direction "down" is to you)
# to check if the player is on the floor
var collision := body.move_and_collide(
-body.up_direction * body.floor_snap_length,
true,
body.safe_margin,
true
)
# No collision, we are definitely in the air
if not collision:
_body_on_floor = false
return
# We consider the surface a floor if its inclination is within the max angle
var angle_diff := absf(body.up_direction.angle_to(collision.get_normal()))
_body_on_floor = (angle_diff <= body.floor_max_angle)
Hope this helps anyone with the same trouble as me 