Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

How can I detect if UI elements are overlapping without colliders? Rect.Overlap is not working.

Discussion in 'Scripting' started by Yukiarashi, Jan 8, 2021.

  1. Yukiarashi

    Yukiarashi

    Joined:
    Dec 31, 2019
    Posts:
    2
    Hello,

    I want to detect if two or more UI elements are overlapping each other. I tried this with box colliders2D and rigidbody2D but on runtime when I access my menu I set the timescale to 0, so colliders didn't work, realized after I finished all my work :'(.

    I also tried Rect.Overlap() and for test purpose I set a variable to true if two rect are overlapping, but I always get true back and never false.

    Then I found this: https://developer.mozilla.org/en-US/docs/Games/Techniques/2D_collision_detection and tried to make it work, but same result as the Rect.Overlap(). Here is my code:
    Code (CSharp):
    1. public class Rect_Test : MonoBehaviour
    2. {
    3.      public GameObject image2;
    4.      Rect image1rect;
    5.      Rect image2rect;
    6.      public bool col;
    7.    
    8.      // Start is called before the first frame update
    9.      void Start()
    10.      {
    11.          image1rect = transform.GetComponent<RectTransform>().rect;
    12.          image2rect = image2.transform.GetComponent<RectTransform>().rect;
    13.      }
    14.      // Update is called once per frame
    15.      void Update()
    16.      {
    17.          if (image1rect.x < image2rect.x + image2rect.width &&
    18.              image1rect.x + image1rect.width > image2rect.x &&
    19.              image1rect.y < image2rect.y + image2rect.height &&
    20.              image1rect.y + image1rect.height > image2rect.y)
    21.          {
    22.              col = true;
    23.          }
    24.          else
    25.          {
    26.              col = false;
    27.          }
    28.      }
    29. }
    Can someone explain me what I did wrong? Is this the best solution to detect "collision" of UI or should I use Raycast for it? My Canvas is set to Render Mode: Screen Space - Overlay and UI Scale Mode: Scale with Screen Size if that matters.
     
  2. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,833
    You should really take a look at the actual rect coordinates you are comparing, and see whether they're what you expected.

    First, let me point out that you are testing the coordinates of your rectangles every frame in Update, but you are only getting those coordinates in Start. A Rect is just a collection of numbers; it won't update if the object moves later on. So at best you are only testing whether they overlapped at Start() time, not at any other time. If you want to check based on the current positions, you should only cache references to the RectTransforms (not the Rects), and then get their current rects every time you want to do the check.

    I suspect you've also got a problem with different coordinate spaces. RectTransform.rect gives you coordinates in the local space of the transform. That's probably fine if the transforms you are comparing are siblings in the object hierarchy, but otherwise you probably need to convert everything to global coordinates using something like TransformPoint. (I don't think there's an existing function to transform the entire rect at once, so you'd need to either convert opposite corners, or convert one corner and then use Transform Vector to convert the dimensions.)

    (And even that might not do what you want unless the objects are at least in the same canvas--if you have worldspace canvases at different locations, then the problem isn't strictly 2D anymore.)
     
  3. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,768
  4. Antistone

    Antistone

    Joined:
    Feb 22, 2014
    Posts:
    2,833
    It's actually the Holy Ground card image from my least-successful board game.
     
    Kurt-Dekker and eisenpony like this.
  5. Yukiarashi

    Yukiarashi

    Joined:
    Dec 31, 2019
    Posts:
    2
    Thank you Antistone and Kurt-Dekker for your quick answers.
    I got it working by now by taking also the RectTransform of the images and use their localPosition in the formula.
    That should work for what I was planning. Now I will implement this for different shapes of objects.
    Code (CSharp):
    1. public class Rect_Test : MonoBehaviour
    2. {
    3.     public GameObject image2;
    4.     Rect image1rect;
    5.     Rect image2rect;
    6.     public bool col;
    7.     RectTransform image1rt;
    8.     RectTransform image2rt;
    9.    
    10.     // Start is called before the first frame update
    11.     void Start()
    12.     {
    13.         image1rect = transform.GetComponent<RectTransform>().rect;
    14.         image2rect = image2.transform.GetComponent<RectTransform>().rect;
    15.  
    16.         image1rt = transform.GetComponent<RectTransform>();
    17.         image2rt = image2.transform.GetComponent<RectTransform>();
    18.     }
    19.  
    20.     // Update is called once per frame
    21.     void Update()
    22.     {
    23.         if (image1rt.localPosition.x < image2rt.localPosition.x + image2rect.width &&
    24.             image1rt.localPosition.x + image1rect.width > image2rt.localPosition.x &&
    25.             image1rt.localPosition.y < image2rt.localPosition.y + image2rect.height &&
    26.             image1rt.localPosition.y + image1rect.height > image2rt.localPosition.y)
    27.         {
    28.             col = true;
    29.         }
    30.         else
    31.         {
    32.             col = false;
    33.         }
    34.     }
    35. }