Search code examples
c#user-interfaceunity-game-enginerect

Check if UI elements/RectTransform are overlapping


I'd like to know how I check whether two UI Panels on my Unity Canvas are overlapping each other.

Currently I am doing this by comparing the canvas elements Rects

Canvas Settings

  • Render Mode: Screen Space - Camera
  • Pixel Perfect: [Yes]
  • Render Camera: Main Camera
  • Plane Distance: 100
  • Sorting Layer: Default
  • Order In Layer: 0

Canvas Scaler Settings

  • UI Scale Mode: Constant Pixel Size
  • Scale Factor: 1
  • Reference Pixels Per Unit: 100

Code I am using to check

[Header("Check For Overlap")]
public RectTransform PlayerBar;
public RectTransform LeftBar;
public Rect RectOne;
public Rect RectTwo;
public bool overlapping;

//Check if the two canvas element Rects overlap each other

public void CheckForOverlap()
{
    overlapping = false;
    // Convert Canvas RectTransforms to World Rects
    RectOne = GetWorldRect(LeftBar);
    RectTwo = GetWorldRect(PlayerBar);

    if (RectOne.Overlaps(RectTwo))
    {
        overlapping = true;
    }
}


public Rect GetWorldRect(RectTransform rt)
{
    //  Get World corners, take top left
    Vector3[] corners = new Vector3[4];
    rt.GetWorldCorners(corners);
    Vector3 topLeft = corners[0];

    // Rect Size ... I'm not sure if this is working correctly?
    Vector2 size = new Vector2(rt.rect.size.x, rt.rect.size.y);
    return new Rect(topLeft, size);
}

What happens

'Overlapping' bool instantly changes to true.

The Rect One returns as (example)

X -7.5, Y 2.5 W 98.5, H 164.1667


Solution

  • Convert the RectTransform to Rect then check if it overlaps.

    Here is a simple function that can do that:

    bool rectOverlaps(RectTransform rectTrans1, RectTransform rectTrans2)
    {
        Rect rect1 = new Rect(rectTrans1.localPosition.x, rectTrans1.localPosition.y, rectTrans1.rect.width, rectTrans1.rect.height);
        Rect rect2 = new Rect(rectTrans2.localPosition.x, rectTrans2.localPosition.y, rectTrans2.rect.width, rectTrans2.rect.height);
    
        return rect1.Overlaps(rect2);
    }
    

    Usage:

    public RectTransform uiRect1;
    public RectTransform uiRect2;
    
    void Update()
    {
        if (rectOverlaps(uiRect1, uiRect2))
        {
            Debug.Log("Overlaps");
        }else
        {
            Debug.Log("Does not Overlap");
        }
    }
    

    Even better, make it an extension method:

    public static class ExtensionMethod
    {
        public static bool rectOverlaps(this RectTransform rectTrans1, RectTransform rectTrans2)
        {
            Rect rect1 = new Rect(rectTrans1.localPosition.x, rectTrans1.localPosition.y, rectTrans1.rect.width, rectTrans1.rect.height);
            Rect rect2 = new Rect(rectTrans2.localPosition.x, rectTrans2.localPosition.y, rectTrans2.rect.width, rectTrans2.rect.height);
    
            return rect1.Overlaps(rect2);
        }
    }
    

    Now, you can do

    public RectTransform uiRect1;
    public RectTransform uiRect2;
    
    void Update()
    {
        if (uiRect1.rectOverlaps(uiRect2))
        {
    
        }
    
        //OR
    
        if (uiRect2.rectOverlaps(uiRect1))
        {
    
        }
    }