Quick answer: Set floor_snap_length to e.g. 8 (pixels). floor_max_angle to 45 deg. Don’t manually reset velocity.y; let move_and_slide handle landing. Up direction = Vector2.UP.

Player walks down a slope and bounces every frame. CharacterBody2D becomes airborne briefly between physics ticks; gravity engages; lands again.

The Symptom

Visible vertical hops while moving down slopes. Sometimes the floor detection toggles in is_on_floor() reads.

The Fix

extends CharacterBody2D

@export var SPEED := 200.0
@export var GRAVITY := 980.0

func _ready() -> void:
    floor_snap_length = 8.0     # keep grounded over slopes
    floor_max_angle = deg_to_rad(45)
    floor_constant_speed = true
    up_direction = Vector2.UP

func _physics_process(delta: float) -> void:
    if not is_on_floor():
        velocity.y += GRAVITY * delta
    var input := Input.get_axis("move_left", "move_right")
    velocity.x = input * SPEED
    move_and_slide()

floor_snap_length lets the body ride the slope without becoming airborne. floor_constant_speed keeps horizontal speed unchanged on slopes.

Verifying

Walk down a slope. Smooth movement. is_on_floor stays true. Without snap: visible bounce.

“Snap length. Constant speed. Slopes glide.”

Related Issues

For CharacterBody3D stairs, see 3D stairs. For physics interpolation, see interpolation.

Snap. Constant. Slopes work.