- Home /
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.
Answer by schaddem · Jan 26, 2013 at 06:53 PM
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.
Yeah the slope limit doesn't change anything. I'll look into a raycast now. Thanks.
Answer by Loius · Jan 26, 2013 at 07:07 PM
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 had to use <<= ins$$anonymous$$d of less-than-equals because less-than-equals breaks out of the code and formats down to my name as code -_-
I combined your answer and the other answer and came up with my own collision detection using a raycast. So now I have more control than just the standard "is.Grounded". While the distance to the ground is less than .5, there is a constant force being applied to the actor that keeps him grounded while walking down the slope.
This also allows me to keep falling separate, so when you fall off a ledge, you will move at the regular falling speed, until you get within .5 of the ground of course, which isn't noticeable.
Answer by schaddemm · Jan 29, 2013 at 09:51 PM
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;
}
}
Your answer
Follow this Question
Related Questions
Gravity for my AI 0 Answers
How reliable are isGrounded checks? 1 Answer
why does character controller accelerate off ledges? 1 Answer
Round Planets and Movement on them 2 Answers