public List <QuadTreeObj> GetColliObjs(QuadTreeObj obj) { _findCollObjLists.Clear(); _rootNode.FindObjInQuadNode(obj, _rootNode, _findCollObjLists); Debug.Log("查询结果对象数量=" + _findCollObjLists.Count); return(_findCollObjLists); }
/// <summary> /// 对象 添加到子节点中, 如果仅在一个子节点区域中直接加入, 如果跨子节点区域加到 父节点中 /// </summary> /// <param name="rect"></param> private void AddRectToChildNode(QuadTreeObj quadObj) { if (ChildNodes == null || ChildNodes.Count <= 0) { return; } int tInserId = -1; int tInsertCount = 0; for (int j = 0; j < 4; j++) { if (ChildNodes[j].IsRectInArea(quadObj.Rect)) // 对象加入对应区域的节点内 { tInserId = j; tInsertCount++; } } if (tInsertCount == 1) { ChildNodes[tInserId].AddRectToNode(quadObj); // 仅在一个子区域内时直接 加入该子区域 } else { ManageObjs.Add(quadObj); // 对象不在子节点区域内 或者对象在两个子区域内 直接加入到本区域内 } }
/// <summary> /// 将对象添加到区域内, 如果 当前节点深度等级已达到最大值 则直接加入, 否则 如果区域管理对象数量已达到最大 则分割区域为四块并调整各块管理对象, 其他情况直接加入 /// 防止树的深度太大影响检索效率 /// </summary> /// <param name="quadObj"></param> public void AddRectToNode(QuadTreeObj quadObj) { if (DeepLevel >= MaxDeepLevel) { ManageObjs.Add(quadObj); // 直接加入 } else { if (ChildNodes == null || ChildNodes.Count <= 0) // 不存在子区域, 检测管理数量上限 { if (ManageObjCount >= MaxObjCount) // 超过管理上限 必须加入子节点中 { SplitToFourNode(); // 细分出子节点 AddRectToChildNode(quadObj); // 将对象加入子节点中 } else { ManageObjs.Add(quadObj); // 直接加入 } } else { AddRectToChildNode(quadObj); // 将对象加入子节点中 } } }
/// <summary> /// 根据 节点内的区域边界线 将对象切割成 子区域内的对象, 由于都是矩形 所以结果就 一个或两个或四个 /// </summary> /// <param name="obj"></param> /// <param name="rootNode"></param> /// <returns></returns> public List <QuadTreeObj> SplitObjWithNodeBound(QuadTreeObj obj, QuadTreeNode node) { List <QuadTreeObj> tList = null; if (node.ChildNodes != null && node.ChildNodes.Count > 0) { float tMidX = node.Rect.Right - node.Rect.W * 0.5f; // 四分象限 中间竖线 float tMidY = node.Rect.Up - node.Rect.H * 0.5f; // 四分象限 中间横线 tList = obj.SplitObjRectWithTwoLine(tMidY, tMidX); } return(tList); }
/// <summary> /// 获取给定对象所在的 四叉树节点, 用于从中获取要检测碰撞的对象 /// 全部用矩阵碰撞盒子筛选碰撞数据 /// 如果对象跨区域, 则分割对象, 然后分别在子区域内检测. 跨区域只可能是 两个或四个 /// </summary> /// <param name="obj"></param> /// <returns></returns> public void FindObjInQuadNode(QuadTreeObj obj, QuadTreeNode rootNode, List <QuadTreeObj> objList) { //Debug.Log("对象矩阵: X=" + obj.Rect.X + ", Y=" + obj.Rect.Y + ", W=" + obj.Rect.W + ", H=" + obj.Rect.H); //Debug.Log("节点矩阵: X=" + rootNode.Rect.X + ", Y=" + rootNode.Rect.Y + ", W=" + rootNode.Rect.W + ", H=" + rootNode.Rect.H); if (rootNode.IsRectInArea(obj.Rect)) { if (rootNode.ChildNodes != null) { int childCount = rootNode.ChildNodes.Count; List <int> tInChildNodeId = new List <int>(4); for (int i = 0; i < childCount; i++) { if (rootNode.ChildNodes[i].IsRectInArea(obj.Rect)) { tInChildNodeId.Add(i); //FindObjInQuadNode(obj, rootNode.ChildNodes[i], objList); } } switch (tInChildNodeId.Count) { case 1: // 仅在一个子区域内, 直接递归检测该子节点 FindObjInQuadNode(obj, rootNode.ChildNodes[tInChildNodeId[0]], objList); break; case 2: // 跨两个区域 case 4: // 跨四个区域 var objSplitList = SplitObjWithNodeBound(obj, rootNode); // 分割对象 int tCount = objSplitList.Count; for (int i = 0; i < tCount; i++) { FindObjInQuadNode(objSplitList[i], rootNode, objList); // 每个子对象分别检测 } break; default: break; } objList.AddRange(rootNode.ManageObjs); } else { objList.AddRange(rootNode.ManageObjs); //没有子区域 又在本区域内, 直接加入本节点区域内的全部对象 } } }