Hi Everyone I tried to implement this Solution for jumping and I'm stuck and the distance to the ground. The code on my PlayerControls script I used is this: Code (CSharp): public Collider2D ground; void Start () { distToGround = ground.GetComponent<BoxCollider2D>().bounds.extents.y; } In my game I attached the GameObject ground to the script on my player: When I 'Debug.Log(distToGround);' I get always the same number: 0.1679988 Info: my player starts in the air and falls slowly to the ground so there should be a different number. Thanks for you help. Best Regards Dollique
You get always the same number because bounds.extents returns the extents of the box (that's always the half of the size). The guide's function creates a raycast that checks if you are grounded at position distToGround +0.1 Code (csharp): functionIsGrounded():boolean{ returnPhysics.Raycast(transform.position,-Vector3.up, distToGround +0.1); }
Okay, so there is something else that doesn't work. I have the function like this: Code (CSharp): bool IsGrounded() { var hit = Physics.Raycast(transform.position, -Vector3.up, distToGround + 0.1f); Debug.Log(hit); if (hit) { Debug.Log("grounded"); return true; } else return false; } In the debugger I always get 'false'. What did I do wrong?
What is the value of distToGround? Try Mathf.Infinity to be sure your distance isn't too small. You can also use Debug.DrawRay to visualize what's happening.
I visualized it with Code (CSharp): Debug.DrawRay(transform.position, -Vector3.up); and it shows me only a line from my players center to the lowest point of my player. The line stops there and doesn't go any further. This seems logic as I was not able to use the DistToGround variable in the DrawRay debug code. Can you explain me how I can debug.DrawRay the full 'hit' variable including the DistToGround + 0.1f?
Code (CSharp): Debug.DrawRay(transform.position, -Vector3.up * (distToGround + 0.1f)); Try something like this, to show green or red depending on if you got a hit result. Code (CSharp): bool IsGrounded() { RaycastHit hit; if(Physics.Raycast(transform.position, -Vector3.up, out hit, distToGround + 0.1f)) { Debug.Log(hit); Debug.Log("grounded"); Debug.DrawLine(transform.position, hit.point, Color.green); return true; } else { Debug.DrawRay(transform.position, -Vector3.up * (distToGround + 0.1f), Color.red); return false; } }
I've seen a couple of ways to do this, I've not done a platformer as of yet, the version I remember the most, is create another gameobject of a child of the player but move this below the player and put a collider on it, if this contacts(collided with it) the ground then your grounded else your not. it's simple, but it might not be as dynamic as you want, just an idea.
If you want to know the distance to the ground maybe this is what you were looking for: Code (csharp): using UnityEngine; public class floor_distance : MonoBehaviour { RaycastHit2D hit; void FixedUpdate () { hit = Physics2D.Raycast(new Vector2(0, transform.position.y - 0.5f), -Vector2.up); if (hit.collider != null) { Debug.Log(transform.position.y - hit.point.y - 0.5f); } } }
Try this: bool grounded = false; float halfHeight = GetComponent<BoxCollider2D>().size.y / 2; var hit = Physics2D.Raycast(transform.position, Vector2.down); if (hit && hit.collider) { grounded = Vector2.distance(transform.position, hit.collider.point) >= halfHeight; }
I'm pretty sure the code of jeffreyschoch should work. I see a red line going from the center of the player down to the bottom of the player (like before). Could it be that the issue is not on my script but on the parameters in my game? I'm a beginner in unity so it could be I forgot something. One important thing I forgot: My game is a 2D platformer (like WinCisky guessed correctly).
For 2D colliders, you need to use the 2D physics system for raycasts. You should also define a ground layer for anything that should be considered ground, and use a layermask with the raycast so that it will only collide with colliders on the ground layers. This will also keep the raycast from hitting your player. Code (CSharp): public LayerMask groundLayers; bool IsGrounded() { RaycastHit2D hit = Physics2D.Raycast(transform.position, -Vector2.up, distToGround + 0.1f, groundLayers); if(hit) { Debug.DrawLine(transform.position, hit.point, Color.green); return true; } else { Debug.DrawRay(transform.position, -Vector3.up * (distToGround + 0.1f), Color.red); return false; } }
Yes, with the groundLayer defined it worked. But now I'm a little confused about how I defined 'DistToGround' because I had to define the actual collider as ground for it to work as expected: Code (CSharp): public LayerMask groundLayers; public Collider2D ground; void Start () { player = GetComponent<Rigidbody2D>(); distToGround = ground.GetComponent<BoxCollider2D>().bounds.extents.y; // GROUND - distance to the ground } Like you see in the screenshot on my first post here, I defined the ground (Box Collider 2D) as 'Ground'. Can I get the 'DistToGround' using the groundLayers variable somehow, so I could add multiple grounds to the layer and it would still work?
You can put every gameobject that should be considered ground onto the ground layer. If Raycast is given a LayerMask, it will only detect colliders that are on the layers in the mask. That distance you're getting is the distance from your player's center to his feet. It's the half-height of the collider. You then add 0.1 so that you check a little bit below the player's feet. That will work fine for the raycast, but first make sure your raycast will work at all. This will fire a ray downward forever and let you know if it hit something. Once this is working, then replace Infinity with your original distance. Code (CSharp): public LayerMask groundLayers; bool IsGrounded() { RaycastHit2D hit = Physics2D.Raycast(transform.position, -Vector2.up, Mathf.Infinity, groundLayers); if(hit) { Debug.DrawLine(transform.position, hit.point, Color.green); float distanceToGround = Vector2.Distance(transform.position, hit.point); Debug.Log("Distance to ground: " + distanceToGround); return true; } else { Debug.DrawRay(transform.position, -Vector3.up * Mathf.Infinity, Color.red); return false; } } This should do what you expect: Code (CSharp): public LayerMask groundLayers; private float groundCheckDistance; private void Start() { // get the distance from the player's collider center, to the bottom of the collider, plus a little bit more groundCheckDistance = GetComponent<Collider2D>().bounds.extents.y + 0.1f; } private bool IsGrounded() { Ray2D ray = new Ray2D(transform.position, Vector2.down); RaycastHit2D hit = Physics2D.Raycast(ray.origin, ray.direction, groundCheckDistance, groundLayers); if(hit) { Debug.DrawLine(ray.origin, hit.point, Color.green); return true; } else { Debug.DrawRay(ray.origin, ray.direction * groundCheckDistance, Color.red); return false; } }
Ok, I see now how I can achieve the distance to the ground, but this somehow doesn't help me. I thought I need the distance to the ground to be able to tell when my player isGrounded(). I could now define something like 'if distance to ground is less than 0.814' I am grounded but this doesn't seem very accurate. To keep it short, I want my portion of code to run without to specify the 'ground' collider but only the groundLayer. Is there any other possibility to achieve this than with distanceToGround < 0.814 ? If I understand correctly a layer doesn't have a collider. Maybe is there a way to merge multiple colliders into one? Like this I could use I currently have (because with just one collider it works).
The layer is set on the GameObject, at the top of the inspector. You can have as many gameobjects per layer as you want. So one ground object would be a gameobject with a collider2D, and the gameobject is set to the Ground layer. Your player raycasts downward a specific distance. That distance is what you're talking about when you say "0.814". The guide you were reading is telling you how to calculate a good distance for that raycast. The second bit of code in my last post will do all of that for you, and "IsGrounded" will return true only if the player's feet are within 0.1 of a ground object. You don't have to specify any colliders here. The player's collider is the only one referenced directly in order to calculate an appropriate raycast distance.
Ah, I didn't see your Edit. Perfect this is exactly what I needed. I will tomorrow try to really understand all this code and then continue with the jumping code Thanks for the help, I'll write back here, if I have any further question!