上QQ阅读APP看书,第一时间看更新
4.3.5 射线碰撞检测模块源码
射线碰撞检测模块的主要工作是从摄像机的屏幕位置上进行射线碰撞检测并获取碰撞结果,将结果返回给事件处理逻辑类,交由事件处理模块处理。
射线碰撞检测模块主要包含三个类,分别作用于2D射线碰撞检测、3D射线碰撞检测和GraphicRaycaster图形射线碰撞检测。
2D射线碰撞检测、3D射线碰撞检测相对比较简单,采用射线的形式进行碰撞检测,区别在于2D射线碰撞检测结果里预留了2D的层级次序,以便在后面的碰撞结果排序时,以这个层级次序为依据进行排序,而3D射线碰撞检测结果则是以距离大小为依据进行排序的。
GraphicRaycaster类为UGUI元素点位检测的类,它被放在Core渲染块里。它主要针对ScreenSpaceOverlay模式下的输入点位进行碰撞检测,因为这个模式下的检测并不依赖于射线碰撞,而是通过遍历所有可点击的UGUI元素来进行检测比较,从而判断该响应哪个UI元素的。因此GraphicRaycaster类是比较特殊的。
GraphicRaycaster类的核心源码如下:
///<summary> /// 在屏幕上进行射线碰撞,并收集所有元素 ///</summary> [NonSerialized] static readonly List<Graphic>s_SortedGraphics = new List<Graphic>(); private static void Raycast(Canvas canvas, Camera eventCamera, Vector2 pointerPosition, List<Graphic>results) { // 事件系统所必需的 var foundGraphics = GraphicRegistry.GetGraphicsForCanvas(canvas); for (int i = 0; i<foundGraphics.Count; ++i) { Graphic graphic = foundGraphics[i]; // -1表示画布尚未对其进行处理,这意味着它实际上并未绘制 if (graphic.depth == -1 || !graphic.raycastTarget) continue; if (!RectTransformUtility.RectangleContainsScreenPoint(graphic. rectTransform, pointerPosition, eventCamera)) continue; if (graphic.Raycast(pointerPosition, eventCamera)) { s_SortedGraphics.Add(graphic); } } s_SortedGraphics.Sort((g1, g2) =>g2.depth.CompareTo(g1.depth)); for (int i = 0; i<s_SortedGraphics.Count; ++i) results.Add(s_SortedGraphics[i]); s_SortedGraphics.Clear(); }
上述代码中,GraphicRaycaster()对每个可以点击的元素(raycastTarget是否为true,并且depth不为-1,为可点击元素)进行计算,判断点位是否落在该元素上。再通过depth变量排序,判断最先落在哪个元素上,从而确定哪个元素响应输入事件。
所有检测碰撞结果的数据结构均为RaycastResult类,它承载了所有碰撞检测的结果,包括距离、世界点位、屏幕点位、2D层级次序和碰撞物体等,为后面的事件处理提供数据上的依据。