Reputation: 19578
I'm trying to use Physics2D.Raycast
in order to check if the player is on the ground (I know that there are other approaches to check if the player is on the ground but I think that the raycast is the most reliable).
The problem is that in my scenario it returns the player itself as hit and I really don't understand why and what should I do.
My code (in PlayerController
) is the following:
public bool IsGrounded () {
Bounds bounds = this.playerCollider.bounds;
Vector3 rayOrigin = bounds.center;
rayOrigin.y -= bounds.extents.y;
RaycastHit2D hit = Physics2D.Raycast (rayOrigin, Vector2.down, 0.1f);
if (hit.collider != null) {
Debug.Log ("Collider is: " + hit.collider.name);
}
return hit.collider != null;
}
And I can debug the casted ray using:
Debug.DrawLine (rayOrigin, new Vector3 (rayOrigin.x, rayOrigin.y - 0.1f, rayOrigin.z), Color.magenta);
...and it gets casted as expected, while the Debug.Log
always reports "Player" which is itself and I don't know how it's possible. So what's wrong?
ps. I'm using Unity 5.3
Upvotes: 2
Views: 10294
Reputation: 31
if anyone encounters this problem this might help. OverlapBox and Raycast hits if the gameobject intersects its own collider. ^^
Upvotes: 0
Reputation: 31
The thing makes problem is its ray hits its own collider. At least i have met with this problem many times. You can pass this problem making group itself or related gameobjects then you can code it as below. This ~ tilde is layer inverter in the code.
public void CheckRay(float rayLength)
{
Ray directionRay = new Ray(transform.position, transform.forward);
Debug.DrawRay(transform.position, transform.forward * rayLength, Color.cyan, 5f);
int xRayedTriggers = Physics.RaycastNonAlloc(directionRay, _hits, rayLength, ~ignoredItselfLayerMask);
Debug.LogAssertion("Layer Total > " + xRayedTriggers);
for (int i = 0; i < xRayedTriggers; i++)
{
Debug.LogAssertion(_hits[i].transform.tag);
}
}
Upvotes: 0
Reputation: 125245
The problem is occurring because your Player is overlapping at the start of the raycast. There are few ways to fix this:
1.Disable Queries Start In Colliders.
Go to Edit->Project Settings->Physics 2D then make sure that Queries Start In Colliders is NOT checked. Your code ran fine after changing that. Here is a screenshot:
2.Another solution is to use layers.Raycasting but ignoring the Player
layer.Before you do that, make sure to create a layer called Ground
and put your ground GameObject to the Ground
layer then create another layer called Player and put your player in the Player
layer. We can now use bitwise
operator to exclude Player
layer from the raycast.
Now, lets assume that Player layer number is 9
. The code below should fix your problem.
public int playerLayer = 9;
int layerMask = ~(1 << playerLayer); //Exclude layer 9
RaycastHit2D hit = Physics2D.Raycast(rayOrigin, Vector2.down, 0.1f, layerMask);
That's it. Both of these were able to solve your problem.
For other people reading, below are other ways to easily detect when Player
is touching the floor without using Physics2D.Raycast
or doing all those things above.
Simply attach to the Player
.
public class Player : MonoBehaviour
{
public LayerMask groundLayer;
Collider2D playerCollider;
bool grounded;
void Start()
{
playerCollider = gameObject.GetComponent<Collider2D>();
}
public bool IsGrounded()
{
grounded = Physics2D.OverlapCircle(playerCollider.transform.position, 1, groundLayer);
return grounded;
}
}
Or you can use IsTouchingLayers
.
public bool IsGrounded()
{
grounded = grounded = playerCollider.IsTouchingLayers(groundLayer.value);
return grounded;
}
Upvotes: 14
Reputation: 156
Vector2.down vector does not present the object space's down vector all the time. You can use -transform.up
.
Also, if it is acceptable you can add some padding to start point of the ray, like rayOrigin.y += 0.0001f;
.
Upvotes: -1