Exemplo n.º 1
0
        /// <summary>
        /// Returns an array of objects that intersect with the specified bounds, if any. Otherwise returns an empty array. See also: IsColliding.
        /// </summary>
        /// <param name="checkBounds">Bounds to check. Passing by ref as it improves performance with structs.</param>
        /// <param name="result">List result.</param>
        /// <returns>Objects that intersect with the specified bounds.</returns>
        public void GetColliding(ref LRect checkBounds, List <ColliderProxy> result)
        {
            // Are the input bounds at least partially in this node?
            if (!bounds.Overlaps(checkBounds))
            {
                return;
            }

            // Check against any objects in this node
            for (int i = 0; i < objects.Count; i++)
            {
                if (objects[i].Bounds.Overlaps(checkBounds))
                {
                    result.Add(objects[i].Obj);
                }
            }

            // Check children
            if (children != null)
            {
                for (int i = 0; i < NUM_CHILDREN; i++)
                {
                    children[i].GetColliding(ref checkBounds, result);
                }
            }
        }
Exemplo n.º 2
0
        public bool CheckCollision(ref LRect checkBounds, FuncCollision callback)
        {
            // Are the input bounds at least partially in this node?
            if (!bounds.Overlaps(checkBounds))
            {
                return(false);
            }

            // Check against any objects in this node
            for (int i = 0; i < objects.Count; i++)
            {
                var o = objects[i];
                if (o.Bounds.Overlaps(checkBounds))
                {
                    callback(o.Obj);
                }
            }
            // Check children
            if (children != null)
            {
                for (int i = 0; i < NUM_CHILDREN; i++)
                {
                    if (children[i].CheckCollision(ref checkBounds, callback))
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
Exemplo n.º 3
0
        public void CheckCollision(ColliderProxy obj, ref LRect checkBounds)
        {
            // Are the input bounds at least partially in this node?
            if (!bounds.Overlaps(checkBounds))
            {
                return;
            }

            // Check against any objects in this node
            for (int i = 0; i < objects.Count; i++)
            {
                var o = objects[i];
                if (!ReferenceEquals(o.Obj, obj) &&
                    BoundsQuadTree.FuncCanCollide(o.Obj, obj) &&
                    o.Bounds.Overlaps(checkBounds)
                    )
                {
                    BoundsQuadTree.funcOnCollide(obj, o.Obj);
                }
            }

            // Check children
            if (children != null)
            {
                for (int i = 0; i < NUM_CHILDREN; i++)
                {
                    children[i].CheckCollision(obj, ref checkBounds);
                }
            }
        }
Exemplo n.º 4
0
        public LRect GetBounds()
        {
            //TODO
            var col  = collider;
            var tran = transform;
            var type = (EShape2D)col.TypeId;

            switch (type)
            {
            case EShape2D.Circle: {
                var radius = ((CCircle)col).radius;
                return(LRect.CreateRect(tran.pos, new LVector2(radius, radius)));
            }

            case EShape2D.AABB: {
                var halfSize = ((CAABB)col).size;
                return(LRect.CreateRect(tran.pos, halfSize));
            }

            case EShape2D.OBB: {
                var radius = ((COBB)col).radius;
                return(LRect.CreateRect(tran.pos, new LVector2(radius, radius)));
            }
            }

            Debug.LogError("No support type" + type);

            return(new LRect());
        }
Exemplo n.º 5
0
        /// <summary>
        /// Check if the specified bounds intersect with anything in the tree. See also: GetColliding.
        /// </summary>
        /// <param name="checkBounds">Bounds to check.</param>
        /// <returns>True if there was a collision.</returns>
        public bool IsColliding(ColliderProxy obj, ref LRect checkBounds)
        {
            // Are the input bounds at least partially in this node?
            if (!bounds.Overlaps(checkBounds))
            {
                return(false);
            }

            // Check against any objects in this node
            for (int i = 0; i < objects.Count; i++)
            {
                var o = objects[i];
                if (!ReferenceEquals(o.Obj, obj) && o.Bounds.Overlaps(checkBounds))
                {
                    return(true);
                }
            }

            // Check children
            if (children != null)
            {
                for (int i = 0; i < NUM_CHILDREN; i++)
                {
                    if (children[i].IsColliding(obj, ref checkBounds))
                    {
                        return(true);
                    }
                }
            }

            return(false);
        }
Exemplo n.º 6
0
        /// <summary>
        /// Private counterpart to the public <see cref="Remove(ColliderProxy, LRect)"/> method.
        /// </summary>
        /// <param name="obj">Object to remove.</param>
        /// <param name="objBounds">3D bounding box around the object.</param>
        /// <returns>True if the object was removed successfully.</returns>
        bool SubRemove(ColliderProxy obj, LRect objBounds)
        {
            bool removed = false;

            for (int i = 0; i < objects.Count; i++)
            {
                if (ReferenceEquals(objects[i].Obj, obj))
                {
                    removed = objects.Remove(objects[i]);
                    break;
                }
            }

            if (!removed && children != null)
            {
                int bestFitChild = BestFitChild(objBounds.center);
                removed = children[bestFitChild].SubRemove(obj, objBounds);
            }

            if (removed && children != null)
            {
                // Check if we should merge nodes now that we've removed an item
                if (ShouldMerge())
                {
                    Merge();
                }
            }

            return(removed);
        }
Exemplo n.º 7
0
 /// <summary>
 /// Returns an array of objects that intersect with the specified bounds, if any. Otherwise returns an empty array. See also: IsColliding.
 /// </summary>
 /// <param name="collidingWith">list to store intersections.</param>
 /// <param name="checkBounds">bounds to check.</param>
 /// <returns>Objects that intersect with the specified bounds.</returns>
 public void GetColliding(List <ColliderProxy> collidingWith, LRect checkBounds)
 {
     //#if UNITY_EDITOR
     // For debugging
     //AddCollisionCheck(checkBounds);
     //#endif
     rootNode.GetColliding(ref checkBounds, collidingWith);
 }
Exemplo n.º 8
0
        // #### PRIVATE METHODS ####

        /// <summary>
        /// Used for visualising collision checks with DrawCollisionChecks.
        /// Automatically removed from builds so that collision checks aren't slowed down.
        /// </summary>
        /// <param name="checkBounds">bounds that were passed in to check for collisions.</param>
#if UNITY_EDITOR
        void AddCollisionCheck(LRect checkBounds)
        {
            lastBoundsCollisionChecks.Enqueue(checkBounds);
            if (lastBoundsCollisionChecks.Count > numCollisionsToSave)
            {
                lastBoundsCollisionChecks.Dequeue();
            }
        }
Exemplo n.º 9
0
 /// <summary>
 /// Check if the specified bounds intersect with anything in the tree. See also: GetColliding.
 /// </summary>
 /// <param name="checkBounds">bounds to check.</param>
 /// <returns>True if there was a collision.</returns>
 public bool IsColliding(ColliderProxy obj, LRect checkBounds)
 {
     //#if UNITY_EDITOR
     // For debugging
     //AddCollisionCheck(checkBounds);
     //#endif
     return(rootNode.IsColliding(obj, ref checkBounds));
 }
Exemplo n.º 10
0
 public void Init(ColliderPrefab prefab, LVector2 pos, LFloat y, LFloat deg)
 {
     this.Prefab = prefab;
     _bound      = prefab.GetBounds();
     Transform2D = new CTransform2D(pos, y, deg);
     unchecked {
         Id = autoIncId++;
     }
 }
Exemplo n.º 11
0
        /// <summary>
        /// Removes the specified object at the given position. Makes the assumption that the object only exists once in the tree.
        /// </summary>
        /// <param name="obj">Object to remove.</param>
        /// <param name="objBounds">3D bounding box around the object.</param>
        /// <returns>True if the object was removed successfully.</returns>
        public bool Remove(ColliderProxy obj, LRect objBounds)
        {
            if (!Encapsulates(bounds, objBounds))
            {
                return(false);
            }

            return(false);
        }
Exemplo n.º 12
0
        /// <summary>
        /// Add an object.
        /// </summary>
        /// <param name="obj">Object to add.</param>
        /// <param name="objBounds">3D bounding box around the object.</param>
        /// <returns>True if the object fits entirely within this node.</returns>
        public bool Add(ColliderProxy obj, LRect objBounds)
        {
            if (!Encapsulates(bounds, objBounds))
            {
                return(false);
            }

            SubAdd(obj, objBounds);
            return(true);
        }
Exemplo n.º 13
0
 public void Init(ColliderPrefab prefab, CTransform2D trans)
 {
     this.Prefab = prefab;
     _bound      = prefab.GetBounds();
     Transform2D = trans;
     _prePos     = Transform2D.pos;
     _preDeg     = Transform2D.deg;
     unchecked {
         Id = autoIncId++;
     }
 }
Exemplo n.º 14
0
 public void Init(ColliderPrefab prefab, CTransform2D trans)
 {
     this.Prefab = prefab;
     _bound      = prefab.GetBounds();
     MaxSideSize = LMath.Max(_bound.halfSize.x, _bound.halfSize.y);
     Transform2D = trans;
     _prePos     = Transform2D.pos;
     _preDeg     = Transform2D.deg;
     unchecked {
         Id = autoIncId++;
     }
 }
Exemplo n.º 15
0
        public void QueryRegion(int layerType, LVector2 pos, LVector2 size, LVector2 forward, FuncCollision callback)
        {
            Debug.Trace($"QueryRegion layerType:{layerType} pos:{pos} size:{size}  forward:{forward} ");
            tempCallback = callback;
            _tempSize    = size;
            _tempForward = forward;
            _tempPos     = pos;
            var radius      = size.magnitude;
            var checkBounds = LRect.CreateRect(pos, new LVector2(radius, radius));

            GetBoundTree(layerType).CheckCollision(ref checkBounds, _CheckRegionOBB);
        }
Exemplo n.º 16
0
        /// <summary>
        /// Removes the specified object at the given position. Makes the assumption that the object only exists once in the tree.
        /// </summary>
        /// <param name="obj">Object to remove.</param>
        /// <param name="objBounds">3D bounding box around the object.</param>
        /// <returns>True if the object was removed successfully.</returns>
        public bool Remove(ColliderProxy obj, LRect objBounds)
        {
            bool removed = rootNode.Remove(obj, objBounds);

            // See if we can shrink the octree down now that we've removed the item
            if (removed)
            {
                Count--;
                Shrink();
            }

            return(removed);
        }
Exemplo n.º 17
0
 public void UpdateObj(ColliderProxy obj, LRect bound)
 {
     for (int i = 0; i < objects.Count; i++)
     {
         if (ReferenceEquals(objects[i].Obj, obj))
         {
             objects[i] = new OctreeObject()
             {
                 Obj = obj, Bounds = bound
             };
         }
     }
 }
Exemplo n.º 18
0
        /// <summary>
        /// Removes the specified object at the given position. Makes the assumption that the object only exists once in the tree.
        /// </summary>
        /// <param name="obj">Object to remove.</param>
        /// <param name="objBounds">3D bounding box around the object.</param>
        /// <returns>True if the object was removed successfully.</returns>
        public bool Remove(ColliderProxy obj, LRect objBounds)
        {
            Debug.Trace($"ColliderProxy Add { obj.Id} objBounds  {objBounds}");
            bool removed = rootNode.Remove(obj, objBounds);

            // See if we can shrink the octree down now that we've removed the item
            if (removed)
            {
                Count--;
                Shrink();
            }

            return(removed);
        }
Exemplo n.º 19
0
        /// <summary>
        /// Add an object.
        /// </summary>
        /// <param name="obj">Object to add.</param>
        /// <param name="objBounds">3D bounding box around the object.</param>
        public void Add(ColliderProxy obj, LRect objBounds)
        {
            // Add object or expand the octree until it can be added
            int count = 0; // Safety check against infinite/excessive growth

            while (!rootNode.Add(obj, objBounds))
            {
                Debug.LogError("Grow");
                Grow(objBounds.center - rootNode.Center);
                if (++count > 20)
                {
                    Debug.LogError("Aborted Add operation as it seemed to be going on forever (" + (count - 1) +
                                   ") attempts at growing the octree.");
                    return;
                }
            }

            Count++;
        }
Exemplo n.º 20
0
        /// <summary>
        /// Draws node boundaries visually for debugging.
        /// Must be called from OnDrawGizmos externally. See also: DrawAllObjects.
        /// </summary>
        /// <param name="depth">Used for recurcive calls to this method.</param>
        public void DrawBoundQuadTreeNode(float depth = 0)
        {
            float tintVal = depth / 7; // Will eventually get values > 1. Color rounds to 1 automatically

            Gizmos.color = new Color(tintVal, 0, 1.0f - tintVal);

            LRect thisBounds = CreateLRect(Center, new LVector2(adjLength, adjLength));

            Gizmos.DrawWireCube(thisBounds.center.ToLVector3().ToVector3(), thisBounds.size.ToLVector3().ToVector3());

            if (children != null)
            {
                depth++;
                for (int i = 0; i < NUM_CHILDREN; i++)
                {
                    children[i].DrawBoundQuadTreeNode(depth);
                }
            }

            Gizmos.color = Color.white;
        }
Exemplo n.º 21
0
        public void UpdateObj(ColliderProxy obj, LRect bound)
        {
            var node = GetNode(obj);

            if (node == null)
            {
                Add(obj, bound);
            }
            else
            {
                if (!node.ContainBound(bound))
                {
                    Remove(obj);
                    Add(obj, bound);
                }
                else
                {
                    node.UpdateObj(obj, bound);
                }
            }
        }
Exemplo n.º 22
0
        public void UpdateObj(ColliderProxy obj, LRect bound)
        {
            Debug.Trace($"ColliderProxy UpdateObj { obj.Id} objBounds  {bound}");
            var node = GetNode(obj);

            if (node == null)
            {
                Add(obj, bound);
            }
            else
            {
                if (!node.ContainBound(bound))
                {
                    Remove(obj);
                    Add(obj, bound);
                }
                else
                {
                    node.UpdateObj(obj, bound);
                }
            }
        }
Exemplo n.º 23
0
        /*
         * /// <summary>
         * /// Get the total amount of objects in this node and all its children, grandchildren etc. Useful for debugging.
         * /// </summary>
         * /// <param name="startingNum">Used by recursive calls to add to the previous total.</param>
         * /// <returns>Total objects in this node and its children, grandchildren etc.</returns>
         * public int GetTotalObjects(int startingNum = 0) {
         *  int totalObjects = startingNum + objects.Count;
         *  if (children != null) {
         *      for (int i = 0; i < 8; i++) {
         *          totalObjects += children[i].GetTotalObjects();
         *      }
         *  }
         *  return totalObjects;
         * }
         */

        // #### PRIVATE METHODS ####

        /// <summary>
        /// Set values for this node.
        /// </summary>
        /// <param name="baseLengthVal">Length of this node, not taking looseness into account.</param>
        /// <param name="minSizeVal">Minimum size of nodes in this octree.</param>
        /// <param name="loosenessVal">Multiplier for baseLengthVal to get the actual size.</param>
        /// <param name="centerVal">Centre position of this node.</param>
        void SetValues(LFloat baseLengthVal, LFloat minSizeVal, LFloat loosenessVal, LVector2 centerVal)
        {
            BaseLength = baseLengthVal;
            minSize    = minSizeVal;
            looseness  = loosenessVal;
            Center     = centerVal;
            adjLength  = looseness * baseLengthVal;

            // Create the bounding box.
            LVector2 size = new LVector2(adjLength, adjLength);

            bounds = CreateLRect(Center, size);

            LFloat   quarter           = BaseLength / 4;
            LFloat   childActualLength = (BaseLength / 2) * looseness;
            LVector2 childActualSize   = new LVector2(childActualLength, childActualLength);

            childBounds    = new LRect[NUM_CHILDREN];
            childBounds[0] = CreateLRect(Center + new LVector2(-quarter, -quarter), childActualSize);
            childBounds[1] = CreateLRect(Center + new LVector2(quarter, -quarter), childActualSize);
            childBounds[2] = CreateLRect(Center + new LVector2(-quarter, quarter), childActualSize);
            childBounds[3] = CreateLRect(Center + new LVector2(quarter, quarter), childActualSize);
        }
Exemplo n.º 24
0
 public void CheckCollision(ref LRect checkBounds, FuncCollision callback)
 {
     rootNode.CheckCollision(ref checkBounds, callback);
 }
Exemplo n.º 25
0
        public void CheckCollision(LVector2 pos, LFloat radius, FuncCollision callback)
        {
            var rect = LRect.CreateRect(pos, new LVector2(radius, radius));

            rootNode.CheckCollision(rect, callback);
        }
Exemplo n.º 26
0
 public void CheckCollision(ColliderProxy obj, LRect checkBounds)
 {
     rootNode.CheckCollision(obj, ref checkBounds);
 }
Exemplo n.º 27
0
 public bool ContainBound(LRect bound)
 {
     return(Encapsulates(bounds, bound));
 }
Exemplo n.º 28
0
        public void CheckCollision(ColliderProxy obj, FuncCollision callback)
        {
            var checkBounds = LRect.CreateRect(obj.pos, new LVector2(obj.MaxSideSize, obj.MaxSideSize));

            rootNode.CheckCollision(ref checkBounds, callback);
        }
Exemplo n.º 29
0
        /// <summary>
        /// Private counterpart to the public Add method.
        /// </summary>
        /// <param name="obj">Object to add.</param>
        /// <param name="objBounds">3D bounding box around the object.</param>
        void SubAdd(ColliderProxy obj, LRect objBounds)
        {
            // We know it fits at this level if we've got this far

            // We always put things in the deepest possible child
            // So we can skip some checks if there are children aleady
            if (!HasChildren)
            {
                // Just add if few objects are here, or children would be below min size
                if (objects.Count < NUM_OBJECTS_ALLOWED || (BaseLength / 2) < minSize)
                {
                    OctreeObject newObj = new OctreeObject {
                        Obj = obj, Bounds = objBounds
                    };
                    objects.Add(newObj);
#if SHOW_NODES
                    obj.UnityTransform?.SetParent(monoTrans, true);
#endif

                    obj2Node[obj] = this;
                    return; // We're done. No children yet
                }

                // Fits at this level, but we can go deeper. Would it fit there?
                // Create the 8 children
                int bestFitChild;
                if (children == null)
                {
                    Split();
                    if (children == null)
                    {
                        Debug.LogError("Child creation failed for an unknown reason. Early exit.");
                        return;
                    }

                    // Now that we have the new children, see if this node's existing objects would fit there
                    for (int i = objects.Count - 1; i >= 0; i--)
                    {
                        OctreeObject existingObj = objects[i];
                        // Find which child the object is closest to based on where the
                        // object's center is located in relation to the octree's center
                        bestFitChild = BestFitChild(existingObj.Bounds.center);
                        // Does it fit?
                        if (Encapsulates(children[bestFitChild].bounds, existingObj.Bounds))
                        {
                            children[bestFitChild]
                            .SubAdd(existingObj.Obj, existingObj.Bounds); // Go a level deeper
                            objects.Remove(existingObj);                  // Remove from here
                        }
                    }
                }
            }

            // Handle the new object we're adding now
            int bestFit = BestFitChild(objBounds.center);
            if (Encapsulates(children[bestFit].bounds, objBounds))
            {
                children[bestFit].SubAdd(obj, objBounds);
            }
            else
            {
                // Didn't fit in a child. We'll have to it to this node instead
                OctreeObject newObj = new OctreeObject {
                    Obj = obj, Bounds = objBounds
                };
                objects.Add(newObj);
                obj2Node[obj] = this;
            }
        }
Exemplo n.º 30
0
 /// <summary>
 /// Checks if outerBounds encapsulates innerBounds.
 /// </summary>
 /// <param name="outerBounds">Outer bounds.</param>
 /// <param name="innerBounds">Inner bounds.</param>
 /// <returns>True if innerBounds is fully encapsulated by outerBounds.</returns>
 static bool Encapsulates(LRect outerBounds, LRect innerBounds)
 {
     return(outerBounds.Contains(innerBounds.min) && outerBounds.Contains(innerBounds.max));
 }