Adjust velocity according to slope angle

I’d like to adjust the Rigidbody2d.velocity.x of the player according to the angle of the slope, that is, if the slope is, for example, 45º, the player should move slower, and if it is above 60º, the player shouldn’t be able to climb it.

I tried lot of things with raycasts but I just can’t find the right way to deal with it. What approach should I use?

I’m couldn’t find out where to place the rays nor how to deal with them

Just using the basic physics system should be enough to do this in a very basic way. If your horizontal force is not strong enough to push you up the slope, gravity will bring you back down.

Now if you want deeper control using raycasting to figure out what the slope angle is, you can start with a raycast straight down, either world-down or down relative to your character’s orientation. The result of a raycast can give you the surface normal, which is the direction the face that was hit is pointing, perpendicular to the surface. You can compare that normal with the vertical plane (world Y axis i assume), to find the angle the ground normal is.

That sounds complicated but it’s not terrible. The hardest part is manipulating the float angle into the range you want.

Here’s an example of how you can get the ground angle between 0 and 90. I haven’t tested this, so forgive me if it doesn’t work straight away.

// class configurables
public LayerMask groundLayers; // the layers that should be hit by the ground check
public float groundCheckDistance = 5f; // the length of the raycast

// return a degree 0 to 90 for slope
private float getGroundAngle() {
    float groundAngle = -1;

    // define a ray starting at this object's position
    // in this object's local downward direction
    Ray2D ray = new Ray2D(transform.position, -transform.up);

    // shoot that ray and get the results
    RaycastHit2D hit = Physics2D.Raycast(ray.origin, ray.direction, groundCheckDistance, groundLayers);
    // something was hit
    if(hit.collider != null) {

        // get which direction the ground is facing
        Vector3 groundFacingDirection = hit.normal;

        // y axis (when ground is perfectly flat, the normal equals this)
        Vector3 verticalDirection = Vector3.up; // same as Vector3(0,1,0)

        // find the angle between the two directions
        // returns the acute angle (0 to 180)
        groundAngle = Vector3.Angle(verticalDirection, groundFacingDirection);

        // if the angle is greater than 90, make it go back towards 0 instead of up to 180
        if(groundAngle > 90) {
            groundAngle = 90 - (groundAngle - 90);
        }
    }

    return groundAngle;
}

Just keep in mind that this function will return 0 if the raycast fails. So there are some better ways to organize this code so that you do the raycast first, then only if it succeeds you can find the ground angle, etc.

2 Likes

@jefferyschoch i don’t know about dccoo but your code seems to work perfectly on my project. (I can’t test it as is on an angle that is higher than 89.9° or lower than -89.9° though).
You can directly check if the raycast fails to know if the player is touching the ground or not, and get rid of the script given by the platformercharacter standard assets if you’re using it.

1 Like

Additionally you can also check this 2D controller which works pretty well with slopes: GitHub - prime31/CharacterController2D

2 Likes