Help with Physics.BoxCast (or maybe ray casts in general?)

I’ve been struggling with this issue for days. Please, someone help.

I’ve got a sphere whose movement I need to restrict when rolling up steep slopes. I’ve been able to make this work, sorta, but the last bit of fine-tuning is giving me trouble. Can anyone help?

I’m currently using a standard Physics.Raycast to check for when I’m on a steep slope. The follow code is attached to the sphere I need to restrict:

public class BallEntity : MonoBehaviour

//slope movement
    [Header("Slope Control")]
    [SerializeField] float _groundRayDistance;
    [SerializeField] private RaycastHit _slopeHit;
    [SerializeField] float _slopeLimit;

public bool OnSteepSlope()
        if (CheckIsGrounded() == false) return false;

        float scRadius = GetComponent<SphereCollider>().radius;
        if (Physics.Raycast(gameObject.transform.position, Vector3.down, out _slopeHit, scRadius + _groundRayDistance))
            float _slopeAngle = Vector3.Angle(_slopeHit.normal, Vector3.up);
            if (_slopeAngle > _slopeLimit)
                return true;
        return false;

This works (well enough), but as expected, given the shape of the sphere and the position of the raycast (center of the sphere), my method allows the sphere to move up the slope a bit before the steep slope is detected. See the image below, which uses OnDrawGizmos() to show the position of the raycast in red:

I tried:

  • Using Vector3.forward along with the sphere’s radius to place the origin of the RayCast at the front of the sphere. I got close with this method, but I couldn’t get it to work.
  • Using a SphereCast instead of a standard RayCast. I couldn’t get this to work.
  • Using a BoxCast instead of a standard RayCast. I couldn’t get this to work either.

Is one of the three methods above the best way to solve this issue? If so, I suppose I might be doing something wrong. Or, is there a simpler method that I haven’t considered?

Thank you so much for all your help!

Hey there,

If you have issues with Box/Spherecasts then please share your approach so that we may see what you tried. A spherecast may indeed solve this issue but i’d like to offer another approach:

Try using the OnCollision callbacks. They give you a Collision as argument. If you get a collision you can check the current contact point for its normal.

  if(Vector3.Angle(collision.GetContact(0).normal, Vector3.up) > 60)
        // we are on a steep slope.

This will need some fiddling around as well to get it to run but should solve your issues and give consistent results.
Only thing you have to watch out for: if you are in collision with multiple objects at once things can get confusing.