controller.Move doesn't stay grounded when walking down slope

public float gravity = 15.0f;

    ...

if (controller.isGrounded) {

    ... (this is where all of the movement happens) ...

    moveDirection.y -= gravity * Time.deltaTime;
    controller.Move(moveDirection * Time.deltaTime);

    ...

} else {
	print("ungrounded");
	moveDirection.y -= gravity * Time.deltaTime;
	controller.Move(moveDirection * Time.deltaTime);
}

When I use this code, I constantly get “ungrounded” popping up in my console whenever I move down any sort of slope. I tried to turn the gravity up to 100, and it fixed it for a 15 degree slope, but it still did it for steeper slopes.

My question is how do I get around this? I want to be able to jump while going down a hill but it’s just not possible in the current state since the character is always ungrounded when he is going down a slope.

If you share code, please do it in C#. Thanks.

Your Problem is that isgrounded returns false, so it’s a matter of how isgrounded works, which if the documentation doesn’t tell we can only guess at(as far as I know).

I’d imagine that it checks if controller has contact with another collider and then checks the angle. Since touching a wall should normally not qualify as being grounded. Changing the gravity to anything higher than 0 should have no effect at all. Slopelimit might be used for the grounded check, to define what passes as ground and what passes as wall.

1.this might fix it:

controller.slopeLimit = 90.0;

2.if it doesn’t you might want to replace isgrounded with your own function. In which I would do a raycast towards the ground and return true if the distance is small enough.

The way I fixed this was to have a ‘default gravity’ instead of zero gravity while the character’s grounded.

For instance:

if ( isGrounded ) {
  localGravity = baseGravity;
} else {
  localGravity -= Time.deltaTime * 9.81;
}

inputVector.y = localGravity;

controller.Move( inputVector ); 

Then the character will follow slopes downward if a movement amount of (baseGravity) keeps it attached to the slope.

Be aware that this does ‘snap’ the character down by that amount if they walk off a sheer cliff, so keep it low enough that it’s unnoticeable to the player.

Here’s the exact snippet I used. Note that the gravity check is to see if the player is jumping (‘positive gravity’):

			if ( onGround && curGravity <<= 0 ) {
				collisionFlags = controller.Move( (targetMovement*modSpeed+Vector3(0,-8,0) ) * Time.deltaTime );
			} else {
				collisionFlags = controller.Move( (targetMovement*modSpeed+Vector3(0,curGravity,0) ) * Time.deltaTime );
			}

I think it could be pretty helpful to have a look at the charactormotor script (it’s in java I think but there’s not that much difference in reading the languages). It also has examples of doing stuff like moving on platforms. (the fps controllor script uses the charactermotor).

As far as I understand the script they implement theyre own test:

private function IsGroundedTest () {
	return (groundNormal.y > 0.01);
}

groundNormal is the normal of the collider we hit:

function OnControllerColliderHit (hit : ControllerColliderHit) {
	if (hit.normal.y > 0 && hit.normal.y > groundNormal.y && hit.moveDirection.y < 0) {
		if ((hit.point - movement.lastHitPoint).sqrMagnitude > 0.001 || lastGroundNormal == Vector3.zero)
			groundNormal = hit.normal;
		else
			groundNormal = lastGroundNormal;
		
		movingPlatform.hitPlatform = hit.collider.transform;
		movement.hitPoint = hit.point;
		movement.frameVelocity = Vector3.zero;
	}
}