Check if 2 RectTransforms overlapping?

I struggled to find a fairly decent “are 2 rectTransforms overlapping” post, so here is the code I came up with.

It requires your canvas to be in the Camera-space.
The nice thing about it, is the camera doesn’t have to be aligned with coordinate axis, and the script will still detect overlap of Rect transforms.

However, rect transforms shouldn’t be rotated within the canvas itself.

Also, you could use it to check if the UI element goes offscreen.

  //if your viewport is screen, then keep it as 'null'
    // NOTICE - doesn't consider if the rectangles are rotating,
    //
    // but shoudl work even if canvas's camera ISN'T aligned with world axis :)
    public static bool is_rectTransformsOverlap( Camera cam,
                                                 RectTransform elem,
                                                 RectTransform viewport = null ){
        Vector2 viewportMinCorner;
        Vector2 viewportMaxCorner;

        if(viewport != null) {
            //so that we don't have to traverse the entire parent hierarchy (just to get screen coords relative to screen),
            //ask the camera to do it for us.
            //first get world corners of our rect:
            Vector3[] v_wcorners = new Vector3[4];
            viewport.GetWorldCorners(v_wcorners); //bot left, top left, top right, bot right

            //+ow shove it back into screen space. Now the rect is relative to the bottom left corner of screen:
            viewportMinCorner = cam.WorldToScreenPoint(v_wcorners[0]);
            viewportMaxCorner = cam.WorldToScreenPoint(v_wcorners[2]);
        }
        else {
            //just use the scren as the viewport
            viewportMinCorner = new Vector2( 0, 0 );
            viewportMaxCorner = new Vector2( Screen.width, Screen.height);
        }

        //give 1 pixel border to avoid numeric issues:
        viewportMinCorner += Vector2.one;
        viewportMaxCorner -= Vector2.one;

        //do a similar procedure, to get the "element's" corners relative to screen:
        Vector3[] e_wcorners = new Vector3[4];
        elem.GetWorldCorners(e_wcorners);

        Vector2 elem_minCorner = cam.WorldToScreenPoint(e_wcorners[0]);
        Vector2 elem_maxCorner = cam.WorldToScreenPoint(e_wcorners[2]);

        //perform comparison:
        if(elem_minCorner.x > viewportMaxCorner.x) { return false; }//completelly outside (to the right)
        if(elem_minCorner.y > viewportMaxCorner.y) { return false; }//completelly outside (is above)

        if(elem_maxCorner.x < viewportMinCorner.x) {  return false;  }//completelly outside (to the left)
        if(elem_maxCorner.y < viewportMinCorner.y) {  return false;  }//completelly outside (is below)

        /*
             commented out, but use it if need to check if element is completely inside:
            Vector2 minDif = viewportMinCorner - elem_minCorner;
            Vector2 maxDif = viewportMaxCorner - elem_maxCorner;
            if(minDif.x < 0  &&  minDif.y < 0  &&  maxDif.x > 0  &&maxDif.y > 0) { //return "is completely inside" }
        */
      
        return true;//passed all checks, is inside (at least partially)
    }
4 Likes

you could use RectTransform.GetLocalCorners() instead of the camera trickery I think.

The result will be 4 coordinates but relative to the parent an the hierarchy might be very deep.
My code allows to compare RectTransform that don’t share the same parent.

1 Like

Your code is working fine. Thanks!

Thank you so much for this!! I tried like 4 implementations for a drag and drop based on RectTransforms that ALMOST worked, before your type of approach worked perfectly. Seems ridiculous that comparing Rect world position values is still such a PITA, this should be encapsulated inside a standard RectTransform static method!

1 Like