Unity - Checking If the Player Is Grounded Not Working

Unity - Checking if the player is grounded not working

Do not use OnTriggerStay to do this. That's not guaranteed to be true very time.

Set isGrounded flag to true when OnCollisionEnter is called. Set it to false when OnCollisionExit is called.

bool isGrounded = true;

private float jumpForce = 2f;
private Rigidbody pRigidBody;

void Start()
{
pRigidBody = GetComponent<Rigidbody>();
}

private void Update()
{
if (Input.GetButtonDown("Jump") && isGrounded)
{
pRigidBody.AddForce(new Vector3(0, jumpForce, 0));
}
}

void OnCollisionEnter(Collision collision)
{
Debug.Log("Entered");
if (collision.gameObject.CompareTag("Ground"))
{
isGrounded = true;
}
}

void OnCollisionExit(Collision collision)
{
Debug.Log("Exited");
if (collision.gameObject.CompareTag("Ground"))
{
isGrounded = false;
}
}

Before you say it doesn't work, please check the following:

  • You must have Rigidbody or Rigidbody2D attached to the player.

  • If this Rigidbody2D, you must use OnCollisionEnter2D and
    OnCollisionExit2D.

  • You must have Collider attached to the player with IsTrigger
    disabled.

  • Make sure you are not moving the Rigidbody with the transform such
    as transform.position and transform.Translate. You must move
    Rigidbody with the MovePosition function.

Unity Can't Do Ground Check with Objected Generated at Start Time

The problem must be that your gravity resetting isn’t working. I suppose you are using the tutorial from Brackeys — I have used his tutorial before, so I know it works. The problem must be that your gravity resetting. So, I go through your code. I notice there is an if statement meant to reset the velocity when the player is grounded. So, I check the isGrounded variable. The only thing that could set that incorrectly is that the maze doesn’t have the right layer. Your code does set the layer right, so I rule that one out. I then look back at the if statement. The only thing that could set it off is the second term in it:

if (... && velocity.y > 0)

Notice how later in your code the velocity rapidly decreases.

velocity.y += gravity * Time.deltaTime;

Notice how gravity is a negative variable.

float gravity = -9.8f;

And Time.deltaTime is positive. When multiplying positive and negative values, if the number of negative values in the equation is odd the result is negative, and if it is even the result is positive. Therefore, velocity decreases instead of increases.

In the if statement, you check if velocity.y > 0, in other words: if the velocity is greater than 0, do something. But according to the math, velocity is always decreasing, not increasing. But you are detecting if the velocity is above 0, not under it.

Change the if statement to:

if (isGrounded && velocity.y < 0)

Notice how I change the > to a < to detect if it is less than zero.


That would solve your problem and you could go off here, but there is something else that is less important. Notice how after your if statement, you decrease the velocity.

...
if (isGrounded && velocity.y > 0)// «— if statement.
{
velocity.y = 0f;
}

float x = Input.GetAxis("Horizontal");
float z = Input.GetAxis("Vertical");

Vector3 move = transform.right * x + transform.forward * z;

controller.Move(move * speed * Time.deltaTime);

velocity.y += gravity * Time.deltaTime;// «—- change velocity.
...

Since after you call the if statement you change it, you won’t need to detect if the velocity is less than 0. This is because the velocity will always be slightly less than 0 at the end of each frame.

There are two things you could do here.

  1. You could remove the second part of the if statement.
  2. You could add the velocity change to the else of the if statement.

For 1:

if (isGrounded)
{
velocity.y = 0f;
}

For 2:

Add:

if (isGrounded)
{
velocity.y = 0f;
}
else
{
velocity.y += gravity * Time.deltaTime;
}

And remove:

controller.Move(move * speed * Time.deltaTime);

//removed this line «—-

controller.Move(velocity * Time.deltaTime);

unity isGrounded works crazy

The issue is that you're checking if an object is grounded via OnTriggerEnter and OnTriggerExit.

You have no possible way to determine that correctly using this method. Instead you should use https://docs.unity3d.com/ScriptReference/Physics.Raycast.html. You can throw the Raycast downwards, check if it hits anything that have a tag corresponding to your ground objects and if yes then you know you're on the ground.

For the second question. The difference between OnTriggerEnter and OnTriggerStay is that OnTriggerEnter is only invoked when one collider enters the other. OnTriggerStay on the other hand is invoked constantly if the colliders are overlapping each other.

Unity make player only jump when it's grounded

Instead of having the else { isGrounded = false;} inside of your collision check, add isGrounded = false; inside of your Jump() function so that you're guaranteed to only be able to jump while you're on the ground;
Additionally you could have Jump(); without the if statement in your Update() function and have it inside Jump() like this if (isGrounded && Input.GetKeyDown(KeyCode.Space))

Unity collision with ground doesnt work (noob)

OnCollisionEnter2D would be the right spelling of what you intented to write. So, change OncollisionEnter2D to OnCollisionEnter2D, because capitalization matters.

As we're already here and it won't harm, I'd also suggest you to use CompareTag instead of tag == string as it performs slightly better due to less memory allocation (as you can read here: https://learn.unity.com/tutorial/fixing-performance-problems#5c7f8528edbc2a002053b595), so it's a good habit to get used to CompareTag:

if(collision.gameObject.CompareTag("MyTag"))

To finish up this answer, I'd like to point out that you might want to consider fixing your auto-completion suggestions (in Visual Studio and Visual Studio Code: IntelliSense) in case it doesn't work. With the help of this tool, you'll never misspell something like this again, because the correct name will be suggested as soon as you start writing.

Checking if RigidBody is grounded?

Another option for checking if the rigidBody is grounded is using the OnTriggerStay function.

void OnTriggerStay(Collider other)
{
if (other.Transform.Tag == "Ground")
{
IsGrounded = true;
Debug.Log("Grounded");
}
else
{
IsGrounded = false;
Debug.Log("Not Grounded!");
}
}


Related Topics



Leave a reply



Submit