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
orRigidbody2D
attached to the player.If this
Rigidbody2D
, you must useOnCollisionEnter2D
andOnCollisionExit2D
.You must have Collider attached to the player with IsTrigger
disabled.Make sure you are not moving the
Rigidbody
with the transform such
astransform.position
andtransform.Translate
. You must moveRigidbody
with theMovePosition
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.
- You could remove the second part of the if statement.
- 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
How to Catch All Exceptions/Crashes in a .Net App
Is the C# Compiler Smart Enough to Optimize This Code
How to Take the Cartesian Join of Two Lists in C#
Refactoring Code to Avoid Anti-Pattern
Send Email via C# Through Google Apps Account
In C# Differencebetween a Destructor and a Finalize Method in a Class
Put Content in Httpresponsemessage Object
Sending Windows Key Using Sendkeys
Parent Control Mouse Enter/Leave Events with Child Controls
Task<> Does Not Contain a Definition for 'Getawaiter'
What Could Be Causing a System.Typeloadexception
C# Regular Expressions, String Between Single Quotes
Groupby on Complex Object (E.G. List<T>)
Preprocessor Directive in C# for Importing Based on Platform