RaycastHit2D never contains a collider

I am trying to detect if a user is grounded. I have a GameObject on the screen with a BoxCollider2D component on it and is on the Ground Layer. I then have a character with a Rigidbody2D and CircleCollider2D on it along with this class:

public class CharacterEnvironment : MonoBehaviour {

    float distToGround;
    
    // Use this for initialization
    void Start() {
        var collider = GetComponent<CircleCollider2D>();
        distToGround = collider.bounds.extents.y;
    }

    // Update is called once per frame
    void Update() {
        RaycastHit2D hit = Physics2D.Raycast(transform.position, Vector2.down, distToGround + 0.1f, LayerMask.NameToLayer("Ground"));
        Debug.Log(hit.collider);
        if (hit && hit.collider != null) {
            Debug.Log(hit.collider);
        }
    }
}

When my raycast runs, hit.collider is always null, even when the object is resting on top of the Ground Object. Am I doing the calculations wrong?

Your problem: The last argument in a physics cast is supposed to be a layer mask; however, LayerMask.NameToLayer returns a layer index, not a layer mask. A layer index is the ID of the layer in the Tags and Layers window; a layer mask is represented by a 32-bit value where each binary digit is a 1 if the mask includes that layer, and a 0 if it does not (where layer index 0 is the least-significant bit).

To illustrate the difference:

A layer mask containing only layer index 0 has the value

00000000000000000000000000000001

A layer mask containing only layer index 5 has the value

00000000000000000000000000010000

A layer mask containing layer indices 6, 7, and 9 has the value

00000000000000000000000101100000


You could use bitshifting to convert a layer index to a layer mask containing only that layer, but a simpler solution is to declare a public LayerMask groundLayer; field in your script and define your ground layermask in the inspector (which has a reasonable layermask editor). You can then use this layermask in your raycasts. This is also more efficient than using a string to find your layer.

You may need to start your raycast a bit up from the transform’s position so that it is not starting at the same point where the player contacts the ground.

RaycastHit2D hit = Physics2D.Raycast(transform.position + Vector2.up * 0.1f, Vector2.down, distToGround + 0.2f, LayerMask.NameToLayer("Ground"));

If that doesn’t work you can always toss a Debug.DrawRay() into your update so you can visualize the ray via the Scene window.

Debug.DrawRay(transform.position, Vector3.down * (distToGround + 0.1f), Color.red);