How to keep CharacterController grounded without constantly applying gravity?

Ok, this is seemingly an extremely simple question. Whenever I apply Y movement (gravity) to a charactercontroller, the expected behavior happens and the object falls down until it hits the ground. The issue is when I stop applying gravity, the CharacterController constantly fluctuates between isGrounded = false and isGroudned = true. I’ve stripped down literally everything except for a few lines of code to test with:

 void Update
{
    		Debug.Log( "is grounded: " + controller.isGrounded );
    		moveDirection.y -= gravity * Time.deltaTime;
    		controller.Move( moveDirection * Time.deltaTime );
}

In the code above, once the charactercontroller falls to the ground, isGrounded keeps returning true as expected. When I try this code…

		Debug.Log( "is grounded: " + controller.isGrounded );
		if( !controller.isGrounded ) 
		{
			moveDirection.y -= gravity * Time.deltaTime;
			if( moveDirection.y < -maxFallSpeed ) moveDirection.y = -maxFallSpeed;
		}
		else moveDirection.y = 0;
		controller.Move( moveDirection * Time.deltaTime );

…the controller fluctuates isGrounded values every few frames.

How do I keep the controller grounded without having to constantly apply gravity? Once it’s grounded, shouldn’t it stay grounded until I apply movement in the opposite direction? Thanks.

3 Answers

3

I suspect that isGrounded is set by collisions in the bottom side of the CharacterController. If you wait the CC (CharacterController) to become grounded, then remove the gravity and move it horizontally, isGrounded becomes false. In your code, gravity is applied as a downwards velocity whenever the isGrounded is false; when it becomes true, you cancel the vertical velocity, what makes isGrounded turn to false - gravity is applied again, isGrounded becomes true, gravity is suspended, and so on, creating a loop that flips isGrounded true/false continuously.

Why do you want to suspend gravity? Usually, the gravity is continuously applied in order to keep the CC grounded, and there’s nothing wrong with this.

I guess I just don't understand that in the above code, if the only way for gravity to be suspended is if it is grounded, how is it ever becoming ungrounded without every applying an upward force? I'm trying to suspend gravity because of issues related to the charactercontroller and moving platforms (this is a 2d game). It falls through a vertically moving platform if no horizontal movement is applied to the CC and I suspect the constant gravity coupled with the upwards movement of the platform is causing an issue sometimes.

Ah! I have no idea why this never occurred to me.. I'm just adding a very very slight displacement right before the main Move and all my troubles are gone. Thank you!

I've actually realized that this still fails if the platform is moving fast enough vertically and the character is falling down at the same time. Is there anything that can be done in situations like this? Thanks!

I encountered this and had a slightly different solve in my own code - instead of displacing in the X or Z directions I actually apply a very small amount of downward push (basically, instead of no gravity I add -0.1*Time.deltaTime gravity - very small). Seems to work perfectly fine for me.

It seems like gravity is the problem for me, though. The downward force on the player in combination with the upward force of the platform seems to have a breaking point. I just can't believe there isn't a real solution to this. Even the Unity 2D Lerp tutorials moving platforms break once they move fast enough.

Hi!
I solved this problem when added strange code “-= 0;”

 void Update()
    {
        isGrounded = controller.isGrounded;

        if (isGrounded)
        {
            verticalVelosity -= 0;
        }
        else
        {
            verticalVelosity -= 1;
        }

        moveVector = new Vector3(0, verticalVelosity, 0);
        controller.Move(moveVector);
    }

I dont understand why, but that somehow fixed my problem. Thank you.

This will keep the character on the ground. > _isGrounded = _myCharacterController.isGrounded; > _verticalVelocity -= _isGrounded ? 0 : 1; > _moveVector = new Vector3(0, _verticalVelocity, 0); > _myCharacterController.Move(_moveVector);

What if it collides with the ground when you apply downward force? Won’t it bounce up in the air?

Should it if there is no physics material?

A CharacterController isn't under physics control, thus it doesn't react to collisions like rigidbodies - nor accept forces or have physics material.