Unexpected ScreenPointToRay return behaviour

I have a simple script copied from the documentation:

    void OnMouseDown()
    {
        Ray ray = cam.ScreenPointToRay(Input.mousePosition);
        Debug.DrawRay(ray.origin, ray.direction * 100, Color.red, 2f);

        if (Physics.Raycast(ray))
        {
            Debug.Log("hit collider");
            cam.backgroundColor = Color.grey;
        }
        else
        {
            Debug.Log("missed collider");
            cam.backgroundColor = Color.black;
        }
    }

In the scene I have a sprite (position 0,0,0) with a collider, and a camera (position 0,0,-10) set to orthographic view.

When I click on the sprite from game view it triggers the “missed collider” message, which means it has returned false even though the collider was hit. If I click elsewhere on the screen, apparently no ray is cast (debugging in scene shows no ray). I’m confused by this, how can a ray return false if it hits something? And shouldn’t the else block be triggered when the ray doesn’t hit anything? I never get the “hit collider” message. If a ray is cast every click, why isn’t the ray that doesn’t hit a collider visible through debug.drawRay?

Things I’ve tried:

  • Updating Unity
  • Trying different collider types
  • Changing the camera to perspective
  • Repeating the setup in a new scene
  • Repeating the setup in a different project
  • Running on an android device (using touch.position instead of Input.mousePosition, same results)

I’m scratching my head over this, how can I get true from a hit and false from a miss in a simple 2D setup intended for mobile?

You won’t detect 2D colliders with the 3D Physics.Raycast call. You need to use the 2D physics queries.

Also, in 2D there is clearly no 3rd dimension so you should use Physics2D.OverlapPoint to detect overlap and use Camera.ScreenToWorldPoint instead.