检查 UI 元素/RectTransform 是不是重叠

Posted

技术标签:

【中文标题】检查 UI 元素/RectTransform 是不是重叠【英文标题】:Check if UI elements/RectTransform are overlapping检查 UI 元素/RectTransform 是否重叠 【发布时间】:2017-02-04 16:58:32 【问题描述】:

我想知道如何检查 Unity Canvas 上的两个 UI 面板是否相互重叠。

目前我通过比较画布元素 Rects 来做到这一点

画布设置

渲染模式:屏幕空间 - 相机 像素完美:[是] 渲染相机:主相机 平面距离:100 排序层:默认 层内顺序:0

画布缩放器设置

UI 缩放模式:恒定像素大小 比例因子:1 每单位参考像素数:100

我用来检查的代码

[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);

会发生什么

'Overlapping' bool 立即变为 true。

矩形返回为(示例)

X -7.5,Y 2.5 W 98.5,H 164.1667

【问题讨论】:

【参考方案1】:

考虑到 rectTransform 的规模的更新版本。

public static class RectTransformExtensions


    public static bool Overlaps(this RectTransform a, RectTransform b) 
        return a.WorldRect().Overlaps(b.WorldRect());
    
    public static bool Overlaps(this RectTransform a, RectTransform b, bool allowInverse) 
        return a.WorldRect().Overlaps(b.WorldRect(), allowInverse);
    

    public static Rect WorldRect(this RectTransform rectTransform) 
        Vector2 sizeDelta = rectTransform.sizeDelta;
        float rectTransformWidth = sizeDelta.x * rectTransform.lossyScale.x;
        float rectTransformHeight = sizeDelta.y * rectTransform.lossyScale.y;

        Vector3 position = rectTransform.position;
        return new Rect(position.x - rectTransformWidth / 2f, position.y - rectTransformHeight / 2f, rectTransformWidth, rectTransformHeight);
    

【讨论】:

这个脚本在我的测试中要好得多。它检测得很好。谢谢。 这在锚点不在同一位置时不起作用,因为sizeDelta 将为零。【参考方案2】:

RectTransform 转换为Rect,然后检查它是否重叠。

这是一个可以做到这一点的简单函数:

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);

用法

public RectTransform uiRect1;
public RectTransform uiRect2;

void Update()

    if (rectOverlaps(uiRect1, uiRect2))
    
        Debug.Log("Overlaps");
    else
    
        Debug.Log("Does not Overlap");
    

更好的是,让它成为一个扩展方法:

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);
    

现在,你可以做

public RectTransform uiRect1;
public RectTransform uiRect2;

void Update()

    if (uiRect1.rectOverlaps(uiRect2))
    

    

    //OR

    if (uiRect2.rectOverlaps(uiRect1))
    

    

【讨论】:

非常感谢,这真的很有用。特别是为扩展方法添加的提示 RectTransform 已经有rect 对象,使用它不是更便宜吗? 这仅适用于两个对象具有相同父对象的情况。如果这不是保证,你会怎么做? 我在屏幕坐标中看不到任何投影 - 您只是忽略了 z 坐标。这应该首先投影到屏幕坐标。

以上是关于检查 UI 元素/RectTransform 是不是重叠的主要内容,如果未能解决你的问题,请参考以下文章

基础组件RectTransform

Unity——RectTransform详解

检查 ui 元素的值是不是已更改

查找 Unity UI 元素的世界空间坐标

统一3d。如何获取ui元素的屏幕或世界位置

Selenium Webdriver:如何检查特定屏幕上是不是存在 ui 元素,无论它当前是不是可见/可点击