「Unity3D」(2)射线检测与EventSystem判断UI点击

来源:互联网 发布:手机系统升级软件 编辑:程序博客网 时间:2024/05/20 12:47

按照传统的做法,EventSystem用做UI的事件处理,射线检测用做非UI碰撞的判断,但需要手动添加Collider。EventSystem使用了,GraphicRaycaster组件来检测UI元素的事件,其底层还是使用了射线来检测碰撞的。

虽然UI组件勾选Raycast Target能够按照层级关系阻挡穿透,但其阻挡的是UI组件之间的射线穿透。GraphicRaycaster的源码中有 var foundGraphics = GraphicRegistry.GetGraphicsForCanvas(canvas);只会判断Graphic对象,这是UI元素的父类。

那么,手动的射线就会有穿透UI的问题,所以我们需要一个能判断UI元素被点击的需求,看代码封装。

/// <summary>/// Whether touch down or mouse button down over UI GameObject./// </summary>public static bool IsClickDownOverUI(){    #if UNITY_EDITOR    if (Input.GetMouseButtonDown(0))    #else    if (Input.touchCount == 1 && Input.GetTouch(0).phase == TouchPhase.Began)    #endif    {        #if UNITY_EDITOR        if (EventSystem.current.IsPointerOverGameObject())        #else        if (EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId))        #endif        {            return true;        }    }    return false;}/// <summary>/// Whether touch up or mouse button up over UI GameObject./// </summary>public static bool IsClickUpOverUI(){    #if UNITY_EDITOR    if (Input.GetMouseButtonUp(0))    #else    if (Input.touchCount == 1 && Input.GetTouch(0).phase == TouchPhase.Ended)    #endif    {        #if UNITY_EDITOR        if (EventSystem.current.IsPointerOverGameObject())        #else        if (EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId))        #endif        {            return true;        }    }    return false;}
  • 这里给出了click down和up的分别判断。
  • 封装了鼠标和触摸的判断。
  • 函数返回true表明UI元素被点中。

射线检测

原理是,根据屏幕的点击,手动发射一条射线,然后获取碰撞的对象。

/// <summary>/// Raycast a ray from touch up or mouse button up and test whether hit transform,/// if hit transform return it or return null./// [isCheckHitUI] Whether check ray hit ui transform,/// if hit ui just return null./// </summary>public static Transform Raycast(bool isCheckHitUI = true){    #if UNITY_EDITOR    if (Input.GetMouseButtonUp(0))    {        if (isCheckHitUI)        {            if (EventSystem.current.IsPointerOverGameObject())            {                return null;            }        }        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);    #else    if (Input.touchCount == 1 && Input.GetTouch(0).phase == TouchPhase.Ended)    {        if (isCheckHitUI)        {            if (EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId))            {                return null;            }        }        Ray ray = Camera.main.ScreenPointToRay(Input.GetTouch(0).position);    #endif        RaycastHit hit;        if (Physics.Raycast(ray, out hit))        {            // or hit.collider.transform;            return hit.transform;         }    }    return null;}
  • isCheckHitUI 表示UI是否会阻挡射线的选择,点中UI直接返回null。
  • Camera.main 代表的是拥有Tag MainCamera的Camera。
  • 封装了鼠标和触摸的操作。
  • 射线点中了带有Collider的非UI元素,就会返回其Transform。

「老问题了,更好的实践,看后续」