Quick answer: Cast down for slope normal. Project input vector along the perpendicular. Apply small snap-down when grounded.
Player walks horizontally on flat ground. Hits a 30° slope. Stops dead. Velocity points into the slope, collision blocks.
The Fix
void FixedUpdate() {
RaycastHit2D hit = Physics2D.Raycast(transform.position, Vector2.down,
1.1f, groundLayer);
bool grounded = hit.collider != null;
Vector2 input = new(inputAxis * speed, 0);
if (grounded) {
Vector2 slopeDir = Vector2.Perpendicular(hit.normal);
if (slopeDir.x < 0 != input.x < 0) slopeDir = -slopeDir;
rb.velocity = slopeDir * Mathf.Abs(input.x);
rb.velocity += Vector2.down * 5f; // snap-down
} else {
rb.velocity = new(input.x, rb.velocity.y);
}
}
Slope projection means input maps onto surface direction. Snap-down keeps contact through fast descents.
Verifying
Walk up 30° slope: smooth ascent. Walk down: stays planted. Without projection: stops at slope; without snap: bounces.
“Project. Snap. Slope walks.”
Related Issues
For BuoyancyEffector2D, see buoyancy. For trigger stay sleep, see stay sleep.
Project along slope. Stay grounded.