Course contentsShow
← Unity Game Development
Lesson 187 of 8283. Physics and InteractionFree lesson

Creating Slope-Aware Movement Logic

Learners will calculate surface normals to prevent the character from sliding down steep inclines or getting stuck on geometry.

In this lesson, you will learn how to calculate the surface normal beneath your character to prevent them from sliding uncontrollably down steep hills or getting stuck on uneven geometry.

Understanding Surface Normals

When your character moves, they don't just exist on a flat plane. They interact with slopes of varying angles. To handle this, we use the RaycastHit information we covered in our Grounded State lesson. When our ground-detection ray hits a surface, it returns a normal vector.

The normal is a direction vector pointing perfectly perpendicular (at a 90-degree angle) away from the surface. By comparing this normal to Vector3.up (which points straight toward the sky), we can determine how steep a slope is using Vector3.Angle.

Implementing the Slope Check

If the angle between the ground normal and Vector3.up is greater than a threshold you define, you know the slope is too steep to climb.

Here is how you can perform this check within your movement logic:

if (Physics.Raycast(transform.position, Vector3.down, out RaycastHit hit, rayDistance))
{
    float slopeAngle = Vector3.Angle(Vector3.up, hit.normal);

    if (slopeAngle <= maxSlopeAngle)
    {
        // Slope is walkable; apply your velocity-based movement
        MoveCharacter(inputVector);
    }
    else
    {
        // Slope is too steep; stop horizontal movement to prevent sliding
        StopMovement();
    }
}

Why This Matters

If you don't account for the slope angle, your character might try to "climb" a vertical wall by applying horizontal velocity, leading to jittery behavior as the physics engine fights against the geometry. By checking the hit.normal before applying your movement force, you create a natural-feeling constraint that keeps your character grounded only on surfaces where movement is logically valid. This also prevents the character from "getting stuck" on small geometric seams, as you can treat steep, unwanted edges as obstacles rather than traversable terrain.

Key Takeaway: By comparing the surface normal vector to the world-up vector, you can dynamically restrict movement to walkable slopes, ensuring stable and predictable character traversal.