// ignorePassRay表示是否忽略窗口的isPassRay属性,true表示认为所有的都允许射线穿透 protected void raycastLayout(ref Ray ray, SortedDictionary <UIDepth, List <IMouseEventCollect> > windowOrderList, List <IMouseEventCollect> retList, ref bool continueRay, bool clearList = true, int maxCount = 0, bool ignorePassRay = false) { if (clearList) { retList.Clear(); } continueRay = true; RaycastHit hit; foreach (var box in windowOrderList) { int count = box.Value.Count; for (int i = 0; i < count; ++i) { IMouseEventCollect window = box.Value[i]; if (window.isActive() && window.isHandleInput() && window.getCollider().Raycast(ray, out hit, 10000.0f)) { // 点击了只允许部分穿透的背景 if (mPassOnlyArea.ContainsKey(window)) { IMouseEventCollect child = mPassOnlyArea[window]; //判断是否点到了背景中允许穿透的部分,如果是允许穿透的部分,则射线可以继续判断下层的窗口,否则不允许再继续穿透 continueRay = child.isActive() && child.isHandleInput() && child.getCollider().Raycast(ray, out hit, 10000.0f); if (!continueRay) { break; } } else { retList.Add(window); // 如果射线不能穿透当前按钮,或者已经达到最大数量,则不再继续 bool passRay = ignorePassRay || window.isPassRay(); bool countNotFull = maxCount <= 0 || retList.Count < maxCount; continueRay = passRay && countNotFull; if (!continueRay) { break; } } } } if (!continueRay) { break; } } }
protected void raycastMovableObject(ref Ray ray, List <IMouseEventCollect> moveObjectList, List <IMouseEventCollect> retList, ref bool continueRay, bool clearList = true) { if (clearList) { retList.Clear(); } continueRay = true; RaycastHit hit; LIST(out List <DistanceSortHelper> sortList); int objCount = moveObjectList.Count; for (int i = 0; i < objCount; ++i) { IMouseEventCollect box = moveObjectList[i]; // 将所有射线碰到的物体都放到列表中 if (box.isActive() && box.isHandleInput() && box.getCollider().Raycast(ray, out hit, 10000.0f)) { sortList.Add(new DistanceSortHelper(getSquaredLength(hit.point - ray.origin), box)); } } // 根据相交点由近到远的顺序排序 quickSort(sortList, DistanceSortHelper.mCompareAscend); int sortCount = sortList.Count; for (int i = 0; i < sortCount; ++i) { DistanceSortHelper item = sortList[i]; retList.Add(item.mObject); if (!item.mObject.isPassRay()) { continueRay = false; break; } } UN_LIST(sortList); }
// 注册碰撞器,只有注册了的碰撞器才会进行检测 public void registeBoxCollider(IMouseEventCollect button, ObjectClickCallback clickCallback = null, ObjectPressCallback pressCallback = null, ObjectHoverCallback hoverCallback = null, GameCamera camera = null) { if (!mUseGlobalTouch) { logError("Not Active Global Touch!"); return; } if (button.getCollider() == null) { logError("window must has collider that can registeBoxCollider! " + button.getName()); return; } button.setClickCallback(clickCallback); button.setPressCallback(pressCallback); button.setHoverCallback(hoverCallback); if (!mAllButtonSet.Contains(button)) { if (button is txUIObject) { // 寻找窗口对应的摄像机 if (WidgetUtility.isNGUI((button as txUIObject).getObject())) { ++mNGUICount; if (camera == null) { camera = mCameraManager.getUICamera(true); } } else { ++mUGUICount; if (camera == null) { camera = mCameraManager.getUICamera(false); } } if (camera == null) { logError("can not find ui camera for raycast!"); } // 将窗口加入到鼠标射线检测列表中 UIDepth depth = button.getUIDepth(); MouseCastWindowSet mouseCastSet = null; foreach (var item in mMouseCastWindowList) { if (item.mCamera == camera) { mouseCastSet = item; break; } } if (mouseCastSet == null) { mouseCastSet = new MouseCastWindowSet(camera); mMouseCastWindowList.Add(mouseCastSet); } mouseCastSet.addWindow(depth, button); mButtonDepthList.Add(button, depth); } else if (button is MovableObject) { MouseCastObjectSet mouseCastSet = null; foreach (var item in mMouseCastObjectList) { if (item.mCamera == camera) { mouseCastSet = item; break; } } if (mouseCastSet == null) { mouseCastSet = new MouseCastObjectSet(camera); mMouseCastObjectList.Add(mouseCastSet); } mouseCastSet.addObject(button); mMovableObjectList.Add(button); } mAllButtonList.Add(button); mAllButtonSet.Add(button); } }
// ignorePassRay表示是否忽略窗口的isPassRay属性,true表示认为所有的都允许射线穿透 // 但是ignorePassRay不会影响到PassOnlyArea和ParentPassOnly protected void raycastLayout(ref Ray ray, List <IMouseEventCollect> windowOrderList, List <IMouseEventCollect> retList, ref bool continueRay, bool clearList = true, bool ignorePassRay = false) { if (clearList) { retList.Clear(); } // mParentPassOnlyList需要重新整理,排除未启用的布局的窗口 LIST(out List <IMouseEventCollect> activeParentList); // 在只允许父节点穿透的列表中已成功穿透的父节点列表 LIST(out List <IMouseEventCollect> passParent); // 筛选出已激活的父节点穿透窗口 int allParentCount = mParentPassOnlyList.Count; for (int i = 0; i < allParentCount; ++i) { if (mParentPassOnlyList[i].isActiveInHierarchy()) { activeParentList.Add(mParentPassOnlyList[i]); } } // 射线检测 continueRay = true; int windowCount = windowOrderList.Count; for (int i = 0; i < windowCount; ++i) { IMouseEventCollect window = windowOrderList[i]; if (window.isActiveInHierarchy() && window.isHandleInput() && window.getCollider().Raycast(ray, out _, 10000.0f)) { // 点击到了只允许父节点穿透的窗口,记录到列表中 // 但是因为父节点一定是在子节点之后判断的,子节点可能已经拦截了射线,从而导致无法检测到父节点 if (activeParentList.Contains(window)) { passParent.Add(window); // 特殊窗口暂时不能接收输入事件,所以不放入相交窗口列表中 continue; } // 点击了只允许部分穿透的背景 if (mPassOnlyArea.TryGetValue(window, out IMouseEventCollect passOnlyArea)) { //判断是否点到了背景中允许穿透的部分,如果是允许穿透的部分,则射线可以继续判断下层的窗口,否则不允许再继续穿透 continueRay = passOnlyArea.isActiveInHierarchy() && passOnlyArea.isHandleInput() && passOnlyArea.getCollider().Raycast(ray, out _, 10000.0f); if (!continueRay) { break; } // 特殊窗口暂时不能接收输入事件,所以不放入相交窗口列表中 continue; } // 如果父节点不允许穿透 if (!isParentPassed(window, activeParentList, passParent)) { continue; } // 射线成功与窗口相交,放入列表 retList.Add(window); // 如果射线不能穿透当前按钮,则不再继续 continueRay = ignorePassRay || window.isPassRay(); } if (!continueRay) { break; } } UN_LIST(passParent); UN_LIST(activeParentList); }
// 注册碰撞器,只有注册了的碰撞器才会进行检测 public void registeCollider(IMouseEventCollect obj, GameCamera camera = null) { if (!mUseGlobalTouch) { logError("Not Active Global Touch!"); return; } if (obj.getCollider() == null) { logError("window must has collider that can registeCollider! " + obj.getName()); return; } if (mAllObjectSet.Contains(obj)) { logError("不能重复注册窗口碰撞体: " + obj.getName()); return; } if (obj is myUIObject) { // 寻找窗口对应的摄像机 ++mUGUICount; if (camera == null) { camera = mCameraManager.getUICamera(); } if (camera == null) { logError("can not find ui camera for raycast!"); } // 将窗口加入到鼠标射线检测列表中 MouseCastWindowSet mouseCastSet = null; int count = mMouseCastWindowList.Count; for (int i = 0; i < count; ++i) { MouseCastWindowSet item = mMouseCastWindowList[i]; if (item.getCamera() == camera) { mouseCastSet = item; break; } } if (mouseCastSet == null) { mouseCastSet = new MouseCastWindowSet(camera); mMouseCastWindowList.Add(mouseCastSet); } mouseCastSet.addWindow(obj); } else if (obj is MovableObject) { MouseCastObjectSet mouseCastSet = null; int count = mMouseCastObjectList.Count; for (int i = 0; i < count; ++i) { MouseCastObjectSet item = mMouseCastObjectList[i]; if (item.mCamera == camera) { mouseCastSet = item; break; } } if (mouseCastSet == null) { mouseCastSet = new MouseCastObjectSet(camera); mMouseCastObjectList.Add(mouseCastSet); } mouseCastSet.addObject(obj); mMovableObjectList.Add(obj); } mAllObjectSet.Add(obj); }