.isGrounded is not working reliably

New to Unity and C#, though, I got the code from the official doc page for Character Controller and thought that should work by default.

When pressing the Jump button here it doesn't always work. When checking if the player is grounded the variable groundedPlayer not always provides true when idle/not moving. Instead, the value is constantly changing between true and false.

Below is my current code which was modified a little:

public class PlayerController : MonoBehaviour
{
private CharacterController controller;
private Vector3 playerVelocity;
private bool groundedPlayer;
private float jumpHeight = 1.0f;
private float gravityValue = -9.81f;

private void Start()
{
}

void Update()
{
groundedPlayer = controller.isGrounded;
//this will constantly return both false and true while idle
print(groundedPlayer + ", " + playerVelocity + ", " + gameObject.transform.position.y.ToString("f8"));
if (groundedPlayer && playerVelocity.y < 0)
{
playerVelocity.y = 0f;
}

if (Input.GetButtonDown("Jump") && groundedPlayer)
{
playerVelocity.y += Mathf.Sqrt(jumpHeight * -3.0f * gravityValue);
}

playerVelocity.y += gravityValue * Time.deltaTime;

controller.Move(playerVelocity * Time.deltaTime);
}

}


It's just that I feel dumb since basic jumping is this difficult to implement for me. I feel like I'm missing something very obvious. I found 1 working solution for me which is implementing coyote time, but it looks like a workaround and might provide more glitches in the future. I also could try working on creating my own character controller, though that's a whole different field.

Anyone had this issue before? How did you fix it?

• I note that you're applying a downward velocity to your character even when they're already grounded. Is it possible this is causing miniature rebounds? – DMGregory Jan 13 at 17:57
• @DMGregory 2 consecutive updates: True, (0.0, -0.1, 0.0), 0,08000498 | False, (0.0, -0.1, 0.0), 0,08000498. Third one is Y-position. Also, it's 0.8 because Unity is applying colliding skin width, though from what I found online that shouldn't be a problem. I also altered the code a bit just for testing purposes, you can see the new version in the question. – Telion Jan 13 at 18:51
• Have you tried adjusting the skin width of the controller? – DMGregory Jan 13 at 18:52
• @Telion this is a common behavior for Character Controller. If your vertical velocity is 0, the isGrounded parameter is not reliably. You need to put a small negative value, so the collision is always happening. – Artur Nista Jan 13 at 19:29
• @ArturNista yea, the issue was that it has to be somewhat big actually. I was trying -0.1f prior to asking here and it just wasn't enough, though my thought was that it's just not the case here, until now when I noticed that it's switching to true somewhere around -0.4. – Telion Jan 13 at 19:33

Apparently the downforce vector was too small to make Unity recognize collision. I am not sure how big the vector has to be or if anything affects how big it has to be but in my case it is something around -0.45f. I've set the downforce vector to at least -0.5f when it first gets grounded and seems like it's working as intended now. The only issue is that I have to keep in mind that I have a fix of -0.5 now by default.

So playerVelocity.y = 0f changed to playerVelocity.y = -0.5f;:

  void Update()
{
// jumping mechanic
groundedPlayer = controller.isGrounded;
if (groundedPlayer && playerVelocity.y < 0)
{
playerVelocity.y = collisionFixForce;
}

if (Input.GetButtonDown("Jump") && groundedPlayer)
{
playerVelocity.y += Mathf.Sqrt(jumpHeight * -3.0f * gravityValue + -collisionFixForce);
}

playerVelocity.y += gravityValue * Time.deltaTime;

controller.Move(playerVelocity * Time.deltaTime);
}