/// <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;
            }));
        }
Esempio n. 5
0
 /// <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:圆形碰撞器的半径和最大检测半径是一样的,如果功能无误可以考虑不进行强转节约计算量
        }
Esempio n. 8
0
        /// <summary>
        /// 向四叉树中添加碰撞器
        /// </summary>
        /// <param name="collider"></param>
        public static void AddCollider(QuadtreeCollider collider)
        {
            instance.DoAddCollider(collider);

            if (collider.isDetector)
            {
                AddDetector(collider);
            }
        }
Esempio n. 9
0
        /// <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));
        }
Esempio n. 13
0
        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));
        }
Esempio n. 16
0
        private List <QuadtreeCollider> GetCollidersInCollisionFromChildren(QuadtreeCollider collider)
        {
            List <QuadtreeCollider> colliders = new List <QuadtreeCollider>();

            foreach (QuadtreeNode child in _children)
            {
                colliders.AddRange(child.GetCollidersInCollision(collider));
            }

            return(colliders);
        }
Esempio n. 17
0
        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);
        }
Esempio n. 20
0
        /// <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);
        }
Esempio n. 21
0
        /// <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);
            }
        }
Esempio n. 22
0
        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);
        }
Esempio n. 23
0
        /// <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));
        }
Esempio n. 24
0
        /// <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);
        }
Esempio n. 25
0
        /// <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 + " 时发生错误:碰撞器没有存入任何子节点");
        }
Esempio n. 27
0
        /// <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));
        }
Esempio n. 29
0
        /// <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);
        }