Search Unity

Raycast2D - Ray doesn't go below y: 0.

Discussion in '2D' started by plokkum, Nov 15, 2013.

  1. plokkum

    plokkum

    Joined:
    May 28, 2013
    Posts:
    90
    I'm trying to check the distance between my hero and the ground. I have 1 hero object and 1 ground object.
    The ground sprite has a box collider attached to it, to which the hero casts a Raycast2D.

    However, the ray never goes below the y 0 coordinates, while the ground's collider is probably at about y -2.

    Here's my simple code:

    Code (csharp):
    1.  
    2. void Update () {
    3.     RaycastHit2D hit = Physics2D.Raycast(transform.position, -Vector2.up);
    4.     if (hit != null) {
    5.         Debug.Log (hit.point);
    6.     }
    7. }
    8.  
    As soon as my hero falls below y 0, the hit.point coordinates return a negative y value, while there is nothing located there. I've been a way from Unity for a while, so maybe I'm missing something.
     
  2. Lovelock

    Lovelock

    Joined:
    Nov 6, 2013
    Posts:
    5
    In my experience with 2D Raycasts and Linecasts so far, the ray typically hit the player rigid body if it starts the cast from inside of it.

    I referenced the Unity 2D Platformer example project to see how they handle it. The exact statement is:

    Code (csharp):
    1. grounded = Physics2D.Linecast(transform.position, groundCheck.position, 1 << LayerMask.NameToLayer("Ground"));
    Anything the player can collide with is on a "Ground" layer and they use a mask to only detect a Linecast (or Raycast) with that layer.

    Instead of shifting bits for my masks, I just make it a public variable and handle it in the inspector. Seems cleaner to me:

    Code (csharp):
    1. public LayerMask groundMask;
    I hope this helps a little bit in answering your question.
     
  3. Lovelock

    Lovelock

    Joined:
    Nov 6, 2013
    Posts:
    5
    Another similar option that I've ended up using is to use Raycasts (not Linecasts) and ensure that they start at the very edge of the player collider extents.

    My code looks something like:

    Code (csharp):
    1.  
    2. Vector3 extents = GetComponent<BoxCollider2D>().size * 0.5f; // Guess we don't have collider.bounds for 2D :(
    3. Vector3 PlayerBottomLeft = new Vector3(-extents.x, -extents.y, 0f);
    4. Vector3 RaycastOrigin = transform.position + PlayerBottomLeft;
    5.  
    And use RaycastOrigin as the Raycast origin. I still mask it with a LayerMask and give it a cast distance of about 2.0f. Remember that there will be somewhat of a tolerance between that Raycast origin and the ground. It will be close to 0.0f, but not exactly. So give yourself some collision tolerance! :)
     
    Last edited: Nov 16, 2013
  4. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,450
    The 2D Raycast and Linecast methods take Vector2 for their position, not Vector3 as they are 2D geometry checks, not 3D.

    Also, RaycastHit2D is a struct and therefore is never null. If nothing is hit then its collider property of RaycastHit2D is null. To make this easier to check, the RaycastHit2D type has an implicit conversion operator to "bool" allowing you to perform the following:

    Code (csharp):
    1.  
    2. void Update ()
    3. {
    4.     RaycastHit2D hit = Physics2D.Raycast(transform.position, -Vector2.up);
    5.  
    6.     if (hit)
    7.     {
    8.         Debug.Log (hit.point);
    9.     }
    10. }
    11.  
    ... which is the equivalent of the more verbose ...

    Code (csharp):
    1.  
    2. void Update ()
    3. {
    4.     RaycastHit2D hit = Physics2D.Raycast(transform.position, -Vector2.up);
    5.  
    6.     if (hit.collider != null)
    7.     {
    8.         Debug.Log (hit.point);
    9.     }
    10. }
    11.  

    Finally, unless you're directly changing the position of the rigid-body each frame by changing the transform component (not recommended) then performing this check each frame is pointless. Physics is only updated each fixed-update so you should perform this check on "FixedUpdate" instead.

    Hope this helps.
     
  5. plokkum

    plokkum

    Joined:
    May 28, 2013
    Posts:
    90
    Sorry for the late response.

    The problem actually was like Lovelock says. The Raycast2D was actually hitting the hero's own rigidbody. I fixed it by using a mask, like you said:

    Code (csharp):
    1. RaycastHit2D hit = Physics2D.Raycast(transform.position, -Vector2.up, Mathf.Infinity, 1 << 8);
    Thanks, MelvMay - I forgot about that. Moved to FixedUpdate! :)

    Thank you all for your input!