how do i check if my player is grounded?, because its kinda annoying how my player can jump in mid air. this is the script im using, its in javascript:
var jumpSpeed: float = 8;
function Update () {
if (Input.GetKeyDown (KeyCode.Space)){
rigidbody.velocity.y = jumpSpeed;
}
You could do a short Raycast in the down direction to check if the ground is there. “short” in this case means the distance from the player pivot to the ground (distToGround); in most cases, collider.bounds.extents.y is this distance (unless collider.bounds.center isn’t 0,0,0). It’s advisable to add a small margin (say, 0.1) to compensate for small ground irregularities or inclination:
var distToGround: float;
function Start(){
// get the distance to ground
distToGround = collider.bounds.extents.y;
}
function IsGrounded(): boolean {
return Physics.Raycast(transform.position, -Vector3.up, distToGround + 0.1);
}
function Update () {
if (Input.GetKeyDown(KeyCode.Space) && IsGrounded()){
rigidbody.velocity.y = jumpSpeed;
}
}
Aldo Naletto’s idea’s really good, I’ve been using this in my game for about 2 months.
But there’s one small flaw. If the ground is a bit uneven, it doesn’t really work. “I’ll cast the ray further then” was my first idea, but what if it’s a hole?
What is needed is a capsulecast instead of a raycast:
//collider.bounds are the bounds collider relative to the world. I wanted a 0.1 margin, and 0.18 is the radius of my collider.
Physics.CheckCapsule(collider.bounds.center,new Vector3(collider.bounds.center.x,collider.bounds.min.y-0.1f,collider.bounds.center.z),0.18f));
function Update()
{
if(isgrounded == true)
{
//Do your action Here...
}
}
//make sure u replace "floor" with your gameobject name.on which player is standing
function OnCollisionEnter(theCollision : Collision){
if(theCollision.gameObject.name == "floor")
{
isgrounded = true;
}
}
//consider when character is jumping .. it will exit collision.
function OnCollisionExit(theCollision : Collision){
if(theCollision.gameObject.name == "floor")
{
isgrounded = false;
}
}
I’ve used “Raycast down” method like aldonaletto suggested but it causes issue when player stand on an edge and the raycast miss the edge.
Understand how OnCollisionStay works
With OnCollisionStay, you can accurately detect the ground. Here is how OnCollisionStay works:
using UnityEngine;
using System.Collections;
public class ExampleClass : MonoBehaviour
{
void OnCollisionStay(Collision collisionInfo)
{
// Debug-draw all contact points and normals
foreach (ContactPoint contact in collisionInfo.contacts)
{
Debug.DrawRay(contact.point, contact.normal, Color.white);
}
}
}
Attach the script above to your character (your character has CapsuleCollider component), then run the game, look at your character in Scene widow instead of Game Window (because Debug.DrawRay only works in Scene window), you should see a white ray where the character touches things.
Implement the idea
//----------PlayerCollider.cs------------
public class PlayerCollider : MonoBehaviour
{
private bool m_IsOnGround;
public bool IsOnGround
{
get
{
if (m_IsOnGround)
{
m_IsOnGround = false;
return true;
}
else
{
return false;
}
}
}
void OnCollisionStay()
{
//If it touch things, then it's on ground, that's my rule
m_IsOnGround = true;
}
}
//----------Player.cs------------
public class Player : MonoBehaviour
{
PlayerCollider m_playerCollider;
void Start()
{
//...
m_playerCollider = GetComponent<PlayerCollider>();
}
void Update()
{
if (m_playerCollider.IsOnGround)
{
Debug.Log("On Ground");
}
else
{
Debug.Log("In air");
}
}
}
Want a working example out of the box?
Check this free asset: Ragdoll and Transition to Mecanim (the time I write this answer, the asset is free, guess it will still be free by the time you check it)
The character controller in the asset above uses OnCollisionStay to detect ground.
If your game is relatively simple, you could just check if rigidbody.velocity.y is 0 or very close to 0. While your character is in the air, he will usually be moving up or down. That should serve as a quick and hacky solution.
Of course, there is a moment at the top of every jump when your vertical speed component has no intensity, but it is unlikely to even occur in the engine. Plus, it could always be left there as a clever exploit for hardcore fans to play with.
I have a solution that should work even for detailed bodies like a sphere.
In my game, the player is a sphere. I want that sphere to be able to jump even when the center of the sphere is not in contact with the ground (say, if the ball rests in a hole).
Raycasting will not work, even when using a cone, in instances when this hole is larger than the cone.
The strategy is: create a collider without a mesh renderer, and make that collider a trigger. Then, on contact with the desired types of objects (in my case, I have a layer for “groundable” objects), have that invisible collider raise a “grounded” flag on OnTriggerEnter and lower it on OnTriggerExit.
Make the collider’s position the same as the object, minus a small y offset. In my case, I also diminish the radius of the collider to make sure it only sticks out from the very bottom. A custom mesh collider could be resized in the X/Z axis for similar results.
This effectively ensures that all collisions with the ground are only detected downward from the player since the hit box is only exposed under the object; all other collisions will be protected by the “solid” body of the player.
This technique is the most responsive for me. Just be careful that the collider does not rotate with the ball, though, or else jumping won’t work when the ball is facing up.
@bfbc2jb
This is what i use and it works very nicely. My player is a cube.
var end = new Vector3(CapsuleEnd.position.x, CapsuleEnd.position.y, CapsuleEnd.position.z); var start = new Vector3(transform.position.x, transform.position.y, transform.position.z); collisions.onGround = Physics.CheckCapsule(start, end, 0.1f, Ground);
CapsuleEnd is a transform which is parented to the Player gameobject.
I know this post is really old, but for those using C# I found a solution that works for me by adapting the provided javascript code! I’m using a variable to store the boolean, just so I can debug it in the editor. Not using it for anything else, currently. Here’s my code!
None of these are working
How would you implement a logic like this for a 3d level???
How to avoid that the player loops in “falling idle” when you move from one collision to the other. Like switching from a ground mesh to a stair mesh. All those skripts are bugged, becaurse the values are glitching out as long as I move from one collider to the other.
A working solution would be nice.
No idea why it is that hard to realise with unity.