I've had great success by the following method. The idea is that, under the specific circumstance that the Rigidbody is in contact with a surface appropriately angled in relation to gravity(which is to say, 'a slope that isn't too steep'), it will be pulled toward the surface normal instead of in the direction of gravity.
As a bonus, this code will work regardless of what direction gravity happens to currently be.
bool isGrounded; // Handy to have for jumping, and we'll use it here too
Vector3 currentGravity; // Just holds some data for us...
ContactPoint cPoints; // ContactPoints are generated by Collision, and they hold lots of fun data.
public float maxGroundedAngle = 45f; //The steepest you want the character to be able to stand firmly on. Steeper than this and they'll slide.
Vector3 groundNormal; //The angle that will be perpendicular to the point of contact that our Rigidbody will be grounded on.
ourRigidBody = GetComponent<Rigidbody>();
ourRigidBody.useGravity = false; //we'll make our own!
/*Freezing rotation is not necessary, but highly recommended
if we're making a character rather than just some object
that happens to be on a slope.*/
void OnCollisionStay(Collision ourCollision)
isGrounded = CheckGrounded(ourCollision);
void OnCollisionExit(Collision ourCollision)
/*It's okay to not have to check whether or not
the Collision we're exiting is one we're grounded on,
because it'll be reaffirmed next time OnCollisionStay runs.*/
isGrounded = false;
groundNormal = new Vector3(); //Probably not necessary, but a good habit, in my opinion
bool CheckGrounded(Collision newCol)
cPoints = new ContactPoint[newCol.contactCount];
foreach(ContactPoint cP in cPoints)
/*If the difference in angle between the direction of gravity
(usually, downward) and the current surface contacted is
less than our chosen maximum angle, we've found an
acceptable place to be grounded.*/
if(maxGroundedAngle > Vector3.Angle(cP.normal, -Physics.gravity.normalized))
groundNormal = cP.normal;
if(isGrounded == false)
//normal gravity, active when not grounded.
currentGravity = Physics.gravity;
else if(isGrounded == true)
/*Not normal gravity. Instead of going down, we go in the
direction perpendicular to the angle of where we're standing.
This means whatever surface we're grounded on will be
effectively the same as standing on a perfectly horizontal
surface. Ergo, no sliding will occur. */
currentGravity = -groundNormal * Physics.gravity.magnitude;