Unity中如何通过GraphicRaycaster对多个Canvas共同执行Raycast检测
多Canvas批量Raycast检测解决方案
有两种成熟的实现方式,均可覆盖所有挂载了GraphicRaycaster的Canvas检测需求:
方案1:手动遍历所有GraphicRaycaster实现批量检测
核心逻辑是主动获取场景内所有激活的GraphicRaycaster实例,逐个执行检测后汇总结果:
示例代码
using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.UI; public static class UIRaycastHelper { public static List<RaycastResult> GetAllUIRaycastResults(Vector2 screenPosition) { var allResults = new List<RaycastResult>(); // 获取场景内所有GraphicRaycaster,Unity 2020+可加第二个bool参数控制是否包含未激活对象 var allRaycasters = Object.FindObjectsOfType<GraphicRaycaster>(); var pointerData = new PointerEventData(EventSystem.current) { position = screenPosition }; foreach (var raycaster in allRaycasters) { var singleCanvasResults = new List<RaycastResult>(); raycaster.Raycast(pointerData, singleCanvasResults); allResults.AddRange(singleCanvasResults); } // 按UI层级深度排序,和Unity默认点击优先级保持一致:层级越高的元素排在列表越前面 allResults.Sort((a, b) => b.depth.CompareTo(a.depth)); return allResults; } }
调用方式
- PC端传
Input.mousePosition作为入参即可检测鼠标位置下的所有UI - 移动端传
Input.GetTouch(0).position即可检测手指触摸位置下的所有UI
方案2:使用EventSystem原生封装的RaycastAll接口
Unity已经内置了跨所有射线检测组件的批量检测逻辑,无需自己遍历,可直接调用:
示例代码
using System.Collections.Generic; using UnityEngine; using UnityEngine.EventSystems; public static class UIRaycastHelper { public static List<RaycastResult> GetAllRaycastResults(Vector2 screenPosition) { var pointerData = new PointerEventData(EventSystem.current) { position = screenPosition }; var results = new List<RaycastResult>(); // 原生方法会自动检测所有激活的GraphicRaycaster、PhysicsRaycaster、Physics2DRaycaster EventSystem.current.RaycastAll(pointerData, results); return results; } // 扩展方法:仅过滤UI检测结果,排除3D/2D物理碰撞体的检测结果 public static List<RaycastResult> FilterUIOnlyResults(this List<RaycastResult> allResults) { return allResults.FindAll(res => res.gameObject.GetComponentInParent<Graphic>() != null); } }
特性说明
- 原生返回的结果已经按深度排好序,无需手动排序
- 兼容3D、2D、UI的混合检测,按需过滤结果即可
- 性能优于手动调用
FindObjectsOfType遍历的实现
优化建议
- 若场景内Canvas数量较多,建议初始化时缓存所有GraphicRaycaster的引用,Canvas增减时再更新缓存,避免重复执行
FindObjectsOfType带来的性能消耗 - 不需要响应触摸/点击的Canvas可以直接禁用GraphicRaycaster组件,减少不必要的检测开销
- 注意入参的坐标必须是屏幕坐标系(左下角为原点(0,0)),不要传入UGUI局部坐标或者世界坐标
内容的提问来源于stack exchange,提问作者ArtS
相关产品推荐
相关产品推荐

