/// <summary> /// 判断圆形碰撞器和圆形碰撞器是否发生碰撞 /// </summary> /// <param name="colliderA"></param> /// <param name="colliderB"></param> /// <returns></returns> private static bool CircleToCircle(QuadtreeCollider colliderA, QuadtreeCollider colliderB) { CircleQuadtreeCollider circleColliderA = (CircleQuadtreeCollider)colliderA; CircleQuadtreeCollider circleColliderB = (CircleQuadtreeCollider)colliderB; return(Vector2.Distance(circleColliderA.Position, circleColliderB.Position) <= circleColliderA.Radius + circleColliderB.Radius); }
private void RemoveSelfColliderOnReset(QuadtreeCollider collider) { _colliders.Remove(collider); // TODO:可以通过添加字典使封装类具有直接从树梢移除碰撞器的能力,这个方法就可以提取到包装类去了 // TODO:移除不是完全从包装类进行,出现bug优先排查此处 }
/// <summary> /// 从树中移除碰撞器 /// </summary> /// <param name="collider"></param> internal void RemoveCollider(QuadtreeCollider collider) { if (!RemoveColliderByPosition(collider)) // 首先根据位置移除碰撞器,但有时候碰撞器移出了所在节点的范围,就会发生找不到节点无法移除的情况 { RemoveColliderFromAllNodes(collider); // 此时使用全节点遍历移除 } }
/// <summary> /// 根据碰撞器相对于节点的位置向四叉树中存入碰撞器 /// </summary> /// <param name="collider"></param> /// <returns></returns> private OperationResult AddColliderByDirection(QuadtreeCollider collider) { return(AddCollider(collider, (nodeParam, colliderParam) => { // 没有父节点的是根节点,根节点可以存入任何方向的碰撞器 if (nodeParam.parent == null) { return true; } // 如果检测的节点是发起这个方法的节点,无论碰撞器在什么位置,都可以存入到这个节点中 if (nodeParam == this) { return true; } // 当前节点相对于父节点的方向与碰撞器相对于父节点的方向,在 X 轴上是否一致 bool colliderAndNodeOnSameXSide = !((nodeParam.Area.center.x >= nodeParam.parent.Area.center.x) ^ (colliderParam.Position.x >= nodeParam.parent.Area.center.x)); // 当前节点相对于父节点的方向与碰撞器相对于父节点的方向,在 Y 轴上是否一致 bool colliderAndNodeOnSameYSide = !((nodeParam.Area.center.y >= nodeParam.parent.Area.center.y) ^ (colliderParam.Position.y >= nodeParam.parent.Area.center.y)); // 这里使用 >= 是因为 Rect 的范围是(包含左边和底边,不包含顶边和右边) // 两个方向都一致,说明碰撞器可以存入这个节点 return colliderAndNodeOnSameXSide && colliderAndNodeOnSameYSide; })); }
/// <summary> /// 添加检测器,只会添加进检测列表,不会添加碰撞器 /// </summary> /// <param name="detector"></param> internal static void AddDetector(QuadtreeCollider detector) { if (!instance._detectors.Contains(detector)) { instance._detectors.Add(detector); } }
/// <summary> /// 根据节点范围向四叉树中存入碰撞器,只当碰撞器在节点范围内时才存入 /// </summary> /// <param name="collider">存入的碰撞器</param> /// <returns> 如果成功存入,返回 true </returns> internal OperationResult AddColliderByArea(QuadtreeCollider collider) { return(AddCollider(collider, (nodeParam, colliderParam) => { // 如果碰撞器在节点范围内,说明碰撞器可以存入这个节点 return nodeParam.Area.Contains(colliderParam.Position); })); }
/// <summary> /// 判断圆形碰撞器和圆形碰撞器是否发生碰撞 /// </summary> /// <param name="colliderA"></param> /// <param name="colliderB"></param> /// <returns></returns> private static bool CircleToCircle(QuadtreeCollider colliderA, QuadtreeCollider colliderB) { CircleQuadtreeCollider circleColliderA = (CircleQuadtreeCollider)colliderA; CircleQuadtreeCollider circleColliderB = (CircleQuadtreeCollider)colliderB; return(Vector2.Distance(circleColliderA.position, circleColliderB.position) <= circleColliderA.radius + circleColliderB.radius); //TODO:圆形碰撞器的半径和最大检测半径是一样的,如果功能无误可以考虑不进行强转节约计算量 }
/// <summary> /// 向四叉树中添加碰撞器 /// </summary> /// <param name="collider"></param> public static void AddCollider(QuadtreeCollider collider) { instance.DoAddCollider(collider); if (collider.isDetector) { AddDetector(collider); } }
/// <summary> /// 移除检测器,只会移除出监测列表,不会移除碰撞器 /// </summary> /// <param name="detector"></param> internal static void RemoveDetector(QuadtreeCollider detector) { if (_instance == null) { return; } _instance._detectors.Remove(detector); }
private bool RemoveColliderFromSelfByPosition(QuadtreeCollider collider) { if (_area.Contains(collider.position)) { return(RemoveColliderFromSelf(collider)); } return(false); }
private bool RemoveColliderByPosition(QuadtreeCollider collider) { if (HaveChildren()) { return(RemoveColliderFromChildrenByPosition(collider)); } return(RemoveColliderFromSelfByPosition(collider)); }
private bool RemoveColliderFromAllNodes(QuadtreeCollider collider) { if (HaveChildren()) { return(RemoveColliderFromChildrenAndAllNodes(collider)); } return(RemoveColliderFromSelf(collider)); }
private void AddColliderIntoSelf(QuadtreeCollider collider) { _colliders.Add(collider); if (NeedSplit()) { Split(); } }
/// <summary> /// 移除碰撞器,到下次进行检测时才会真正移除碰撞器,符合条件时会合并节点 /// </summary> /// <param name="collider"></param> public static void RemoveColliderWithMerge(QuadtreeCollider collider) { // 如果没有实例,不进行处理,这一步是必须的,否则在游戏关闭时会发生销毁时四叉树实例一次次出现,进而导致异常 if (instance == null) { return; } // 添加到需要移除的碰撞器列表里 Instance.needRemoveColliders.Add(collider); }
/// <summary> /// 向四叉树中添加碰撞器 /// </summary> /// <param name="collider"></param> public static QuadtreeNode.OperationResult AddCollider(QuadtreeCollider collider) { // 不能重复存入碰撞器 if (Instance.collidersToNodes.ContainsKey(collider)) { return(new QuadtreeNode.OperationResult(false)); } // 向实例中添加碰撞器 return(Instance.DoAddCollider(collider)); }
private List <QuadtreeCollider> GetCollidersInCollisionFromChildren(QuadtreeCollider collider) { List <QuadtreeCollider> colliders = new List <QuadtreeCollider>(); foreach (QuadtreeNode child in _children) { colliders.AddRange(child.GetCollidersInCollision(collider)); } return(colliders); }
private bool AddColliderIntoChildren(QuadtreeCollider collider) { foreach (QuadtreeNode child in _children) { if (child.AddCollider(collider)) { return(true); } } throw new ArgumentOutOfRangeException("向范围是 " + _area + " 的节点的子节点存入碰撞器 " + collider + " 时发生错误:碰撞器没有存入任何子节点"); // 正常流程中不会运行到这 }
private bool RemoveColliderFromChildrenAndAllNodes(QuadtreeCollider collider) { foreach (QuadtreeNode child in _children) { if (child.RemoveColliderFromAllNodes(collider)) { return(true); } } return(false); }
private bool RemoveColliderFromChildrenByPosition(QuadtreeCollider collider) { foreach (QuadtreeNode child in _children) { if (child.RemoveColliderByPosition(collider)) { return(true); } } return(false); }
/// <summary> /// 从子节点中获取与指定碰撞器发生碰撞的碰撞器 /// </summary> /// <param name="collider"></param> /// <returns></returns> private List <QuadtreeCollider> GetCollidersInCollisionFromChildren(QuadtreeCollider collider) { List <QuadtreeCollider> colliders = new List <QuadtreeCollider>(); // 遍历子节点进行碰撞检测并保存发生碰撞的碰撞器 foreach (QuadtreeNode child in children) { colliders.AddRange(child.GetCollidersInCollision(collider)); } return(colliders); }
/// <summary> /// 从四叉树中移除碰撞器 /// </summary> /// <param name="collider"></param> public static void RemoveCollider(QuadtreeCollider collider) { if (_instance == null) { return; } _instance._root.RemoveCollider(collider); if (collider.isDetector) { RemoveDetector(collider); } }
private List <QuadtreeCollider> GetCollidersInCollisionFromSelf(QuadtreeCollider collider) { List <QuadtreeCollider> colliders = new List <QuadtreeCollider>(); foreach (QuadtreeCollider currentCollider in _colliders) { if (currentCollider.IsCollitionToCollider(collider)) { colliders.Add(currentCollider); } } return(colliders); }
/// <summary> /// 获取与指定碰撞器发生碰撞的碰撞器 /// </summary> /// <param name="collider">用于检测碰撞的碰撞器</param> /// <returns></returns> internal List <QuadtreeCollider> GetCollidersInCollision(QuadtreeCollider collider) { if (!PossibleCollisions(collider)) { return(new List <QuadtreeCollider>()); } if (HaveChildren()) { return(GetCollidersInCollisionFromChildren(collider)); } return(GetCollidersInCollisionFromSelf(collider)); }
/// <summary> /// 从当前节点中获取与指定碰撞器发生碰撞的碰撞器 /// </summary> /// <param name="collider"></param> /// <returns></returns> private List <QuadtreeCollider> GetCollidersInCollisionFromSelf(QuadtreeCollider collider) { List <QuadtreeCollider> colliders = new List <QuadtreeCollider>(); // 遍历所有碰撞器,如果与指定碰撞器发生碰撞则记录到列表里 foreach (QuadtreeCollider currentCollider in this.colliders) { if (currentCollider.IsCollitionToCollider(collider)) { colliders.Add(currentCollider); } } return(colliders); }
/// <summary> /// 向四叉树中存入碰撞器 /// </summary> /// <param name="collider">存入的碰撞器</param> /// <returns> 如果成功存入,返回 true </returns> internal bool AddCollider(QuadtreeCollider collider) { if (!_area.Contains(collider.position)) { return(false); } if (HaveChildren()) { return(AddColliderIntoChildren(collider)); } AddColliderIntoSelf(collider); return(true); }
/// <summary> /// 将碰撞器按照指定标准存入到子节点 /// </summary> /// <param name="collider">要存入的碰撞器</param> /// <param name="addCollider">存入方法</param> /// <returns></returns> private OperationResult AddColliderIntoChildren(QuadtreeCollider collider, Func <QuadtreeNode, QuadtreeCollider, OperationResult> addCollider) { // 遍历子节点存入碰撞器 foreach (QuadtreeNode child in children) { // 如果有一个子节点存入成功,则将这个节点的操作结果作为结果返回 OperationResult result = addCollider(child, collider); if (result.Success) { return(result); } } // 正常流程中不会运行到的所有子节点都保存失败的情况 throw new ArgumentOutOfRangeException("向范围是 " + area + " 的节点的子节点存入碰撞器 " + collider + " 时发生错误:碰撞器没有存入任何子节点"); }
/// <summary> /// 获取与指定碰撞器发生碰撞的碰撞器 /// </summary> /// <param name="collider">用于检测碰撞的碰撞器</param> /// <returns></returns> internal List <QuadtreeCollider> GetCollidersInCollision(QuadtreeCollider collider) { // 如果指定碰撞器不可能与当前节点内的任何碰撞器碰撞,返回空列表 if (!PossibleCollisions(collider)) { return(new List <QuadtreeCollider>()); } // 如果有子节点,从子节点中寻找发生碰撞的碰撞器 if (HaveChildren()) { return(GetCollidersInCollisionFromChildren(collider)); } // 没有子节点,从当前节点中寻找发生碰撞的碰撞器 return(GetCollidersInCollisionFromSelf(collider)); }
/// <summary> /// 根据指定标准存入碰撞器 /// </summary> /// <param name="collider">要存入的碰撞器</param> /// <param name="canAdd">如果这个方法返回 true 这说明这个碰撞器可以存入当前节点</param> /// <returns></returns> private OperationResult AddCollider(QuadtreeCollider collider, Func <QuadtreeNode, QuadtreeCollider, bool> canAdd) { // 不符合存入标准的直接返回存入失败 if (!canAdd(this, collider)) { // 不符合存入标准并不会导致映射表的变化,只返回失败即可 return(new OperationResult(false)); } // 有子节点,发给子节点保存 if (HaveChildren()) { return(AddColliderIntoChildren(collider, (nodeParam, colliderParam) => nodeParam.AddCollider(colliderParam, canAdd))); } // 没有子节点,保存节点并返回结果 return(AddColliderIntoSelf(collider)); }
/// <summary> /// 绘制单个碰撞器 /// </summary> /// <param name="collider"></param> private void DrawCollider(QuadtreeCollider collider) { Vector3 beginPoint = collider.transform.position + Vector3.right * collider.MaxRadius * Mathf.Max(Mathf.Abs(collider.transform.lossyScale.x), Mathf.Abs(collider.transform.lossyScale.y)); //三角函数角度是从正右方开始的,画圆起始点是最右边的点raw Gizmos.DrawLine(collider.transform.position, beginPoint); for (int i = 1; i <= 144; i++) { float angle = 2 * Mathf.PI / 144 * i; float x = collider.MaxRadius * Mathf.Max(Mathf.Abs(collider.transform.lossyScale.x), Mathf.Abs(collider.transform.lossyScale.y)) * Mathf.Cos(angle) + collider.transform.position.x; float y = collider.MaxRadius * Mathf.Max(Mathf.Abs(collider.transform.lossyScale.x), Mathf.Abs(collider.transform.lossyScale.y)) * Mathf.Sin(angle) + collider.transform.position.y; Vector3 endPoint = new Vector3(x, y, collider.transform.position.z); Gizmos.DrawLine(beginPoint, endPoint); beginPoint = endPoint; } }
/// <summary> /// 从四叉树中移除碰撞器 /// </summary> /// <param name="collider"></param> /// <param name="withMerge">是否需要在需要合并的时候进行合并</param> /// <returns></returns> internal static QuadtreeNode.OperationResult ImmediateRemoveCollider(QuadtreeCollider collider, bool withMerge) { // 如果没有实例,不进行处理,这一步是必须的,否则在游戏关闭时会发生销毁时四叉树实例一次次出现,进而导致异常 if (instance == null) { return(new QuadtreeNode.OperationResult(false)); } // 映射表里没有这个碰撞器,说明树里没有这个碰撞器,直接返回失败 if (!Instance.collidersToNodes.ContainsKey(collider)) { return(new QuadtreeNode.OperationResult(false)); } // 根据映射表直接从末梢节点移除碰撞器 QuadtreeNode.OperationResult result; if (withMerge) { result = Instance.collidersToNodes[collider].ImmediateRemoveColliderFromSelfWithMerge(collider); } else { result = Instance.collidersToNodes[collider].ImmediateRemoveColliderFromSelfWithOutMerge(collider); } if (result.Success) { // 移除成功后更新映射表,覆盖合并映射表并移除空值 Instance.collidersToNodes.OverlayMerge(result.CollidersToNodes).RemoveOnValueIsNull(); } else { throw new System.ArgumentOutOfRangeException( "移除碰撞器 " + "(" + collider.Position.x + ", " + collider.Position.y + ")" + " 时发生错误:碰撞器到节点的映射表中存在这个碰撞器,但映射到的节点 " + "(" + Instance.collidersToNodes[collider].Area.ToString() + ")" + " 移除失败,可能是碰撞器并不在节点中"); } return(result); }