Example #1
0
        private HeightQuadTree(MatrixBounds bounds, int depth, int maxDepth)
        {
            _bounds   = bounds;
            _depth    = depth;
            _maxDepth = maxDepth;

            _indexes = new DynamicArray <VectorXZ>(10);
        }
Example #2
0
        private HeightQuadTree(int startX, int startZ, int sizeX, int sizeZ, int depth, int maxDepth)
        {
            _bounds = new MatrixBounds(startX, startZ, startX + (sizeX - 1), startZ + (sizeZ - 1));
            _depth = depth;
            _maxDepth = maxDepth;

            _indexes = new DynamicArray<VectorXZ>(10);
        }
Example #3
0
        private HeightQuadTree(MatrixBounds bounds, int depth, int maxDepth)
        {
            _bounds = bounds;
            _depth = depth;
            _maxDepth = maxDepth;

            _indexes = new DynamicArray<VectorXZ>(10);
        }
Example #4
0
        private HeightQuadTree(int startX, int startZ, int sizeX, int sizeZ, int depth, int maxDepth)
        {
            _bounds   = new MatrixBounds(startX, startZ, startX + (sizeX - 1), startZ + (sizeZ - 1));
            _depth    = depth;
            _maxDepth = maxDepth;

            _indexes = new DynamicArray <VectorXZ>(10);
        }
 public bool Contains(MatrixBounds other)
 {
     if (other.maxRow > this.maxRow || other.minRow < this.minRow || other.maxColumn > this.maxColumn)
     {
         return(false);
     }
     return(other.minColumn >= this.minColumn);
 }
 public static MatrixBounds Combine(MatrixBounds first, MatrixBounds second)
 {
     if (first.isEmpty)
     {
         return(second);
     }
     if (second.isEmpty)
     {
         return(first);
     }
     return(new MatrixBounds(Math.Min(first.minColumn, second.minColumn), Math.Min(first.minRow, second.minRow), Math.Max(first.maxColumn, second.maxColumn), Math.Max(first.maxRow, second.maxRow)));
 }
Example #7
0
        public IHeightLookup PrepareForUpdate(MatrixBounds suggestedBounds, out MatrixBounds requiredBounds)
        {
            if (!_bounds.Contains(suggestedBounds))
            {
                throw new ArgumentException("Cannot update a quadtree of a smaller size than requested bounds.", "suggestedBounds");
            }

            var updater = GetUpdateTree(null, 0, suggestedBounds);

            if (updater != null)
            {
                requiredBounds = updater.bounds;
                return(updater);
            }

            //The update covers an area that requires a full reindexing.
            //This can happen with even very small areas, they just need to overlap one of the borders between subtrees.
            //And this is why dynamic updates are not friends with quad trees
            requiredBounds = _bounds;
            _lookup        = null;
            _subTrees      = null;
            _indexes       = new DynamicArray <VectorXZ>(10);
            return(this);
        }
Example #8
0
        public IHeightLookup PrepareForUpdate(MatrixBounds suggestedBounds, out MatrixBounds requiredBounds)
        {
            if (!_bounds.Contains(suggestedBounds))
            {
                throw new ArgumentException("Cannot update a quadtree of a smaller size than requested bounds.", "suggestedBounds");
            }

            var updater = GetUpdateTree(null, 0, suggestedBounds);

            if (updater != null)
            {
                requiredBounds = updater.bounds;
                return updater;
            }

            //The update covers an area that requires a full reindexing.
            //This can happen with even very small areas, they just need to overlap one of the borders between subtrees.
            //And this is why dynamic updates are not friends with quad trees
            requiredBounds = _bounds;
            _lookup = null;
            _subTrees = null;
            _indexes = new DynamicArray<VectorXZ>(10);
            return this;
        }
Example #9
0
 /// <summary>
 /// Applies an action to a range of items
 /// </summary>
 /// <param name="bounds">The bounds specifying the index range.</param>
 /// <param name="act">The action to apply. This can be anything from modifying the items to collecting data from the items.</param>
 public void Apply(MatrixBounds bounds, Action <T> act)
 {
     Apply(bounds.minColumn, bounds.maxColumn, bounds.minRow, bounds.maxRow, act);
 }
Example #10
0
        private UpdatingHeightTree GetUpdateTree(HeightQuadTree parent, int parentIdx, MatrixBounds suggestedBounds)
        {
            if (_subTrees != null)
            {
                for (int i = 0; i < 4; i++)
                {
                    if (_subTrees[i]._bounds.Contains(suggestedBounds))
                    {
                        return _subTrees[i].GetUpdateTree(this, i, suggestedBounds);
                    }
                }
            }

            if (parent != null)
            {
                var freshStart = new HeightQuadTree(_bounds, _depth, _maxDepth);
                return new UpdatingHeightTree(freshStart, parent, parentIdx);
            }

            return null;
        }
 public override IEnumerator AssignHeightSettings(MatrixBounds bounds)
 {
     yield break;
 }
        /// <summary>
        /// Combines two bounds to create a new bounds that covers the area of both plus any area between them.
        /// If one <see cref="isEmpty"/> it will return the other.
        /// </summary>
        /// <param name="first">The first bounds.</param>
        /// <param name="second">The second bounds.</param>
        /// <returns>A new bounds that covers the area of both plus any area between them.</returns>
        public static MatrixBounds Combine(MatrixBounds first, MatrixBounds second)
        {
            if (first.isEmpty)
            {
                return second;
            }

            if (second.isEmpty)
            {
                return first;
            }

            return new MatrixBounds(
                Math.Min(first.minColumn, second.minColumn),
                Math.Min(first.minRow, second.minRow),
                Math.Max(first.maxColumn, second.maxColumn),
                Math.Max(first.maxRow, second.maxRow));
        }
 /// <summary>
 /// Determines whether this bounds contains the other bounds.
 /// </summary>
 /// <param name="other">The other bounds.</param>
 /// <returns><c>true</c> if contained; otherwise <c>false</c></returns>
 public bool Contains(MatrixBounds other)
 {
     return ((other.maxRow <= this.maxRow) && (other.minRow >= this.minRow) && (other.maxColumn <= this.maxColumn) && (other.minColumn >= this.minColumn));
 }
        public override IEnumerator AssignHeightSettings(MatrixBounds bounds)
        {
            var maxColumn = bounds.maxColumn;
            var maxRow = bounds.maxRow;
            bool isPartial = (maxColumn - bounds.minColumn < _matrix.columns - 1) || (maxRow - bounds.minRow < _matrix.rows - 1);
            var ledgeThreshold = Mathf.Tan(GameServices.heightStrategy.ledgeThreshold * Mathf.Deg2Rad) * _matrix.granularity;

            var rawMatrix = _matrix.rawMatrix;
            for (int x = bounds.minColumn; x <= maxColumn; x++)
            {
                for (int z = bounds.minRow; z <= maxRow; z++)
                {
                    var c = rawMatrix[x, z] as RichCell;
                    if (c.isPermanentlyBlocked)
                    {
                        continue;
                    }

                    //Process neighbours
                    for (int dz = -1; dz <= 1; dz++)
                    {
                        for (int dx = -1; dx <= 1; dx++)
                        {
                            if (dx == 0 && dz == 0)
                            {
                                continue;
                            }

                            var n = _matrix[x + dx, z + dz] as RichCell;
                            if (n == null || n.isPermanentlyBlocked)
                            {
                                continue;
                            }

                            //If height data has already been assigned (by neighbour) we don't want to do it again,
                            //unless its a partial in which case we have to since neighbours are not necessarily covered by the update
                            if (!isPartial && c.HasInitializedHeightData(dx, dz))
                            {
                                continue;
                            }

                            UpdateCellHeightData(c, n, ledgeThreshold, dx, dz);

                            yield return null;
                        }
                    } /* end neighbour loop */
                }
            }

            if (!isPartial)
            {
                yield break;
            }

            //Update corner diagonals, this is only relevant for partial updates
            //Since the cells being updated only update their own relation to neighbours, there will potentially be 4 connections not updated,
            //those are the diagonals between the cells surround each corner of the bounds, e.g. bottom left corner the connection between the cell to the left and the cell below that corner.
            //since updates also update the involved neighbour, we only have to update 4 additional cells, and only on a specific diagonal.
            var bll = _matrix[bounds.minColumn - 1, bounds.minRow] as RichCell;
            var blb = _matrix[bounds.minColumn, bounds.minRow - 1] as RichCell;

            var tll = _matrix[bounds.minColumn - 1, bounds.maxRow] as RichCell;
            var tlt = _matrix[bounds.minColumn, bounds.maxRow + 1] as RichCell;

            var brr = _matrix[bounds.maxColumn + 1, bounds.minRow] as RichCell;
            var brb = _matrix[bounds.maxColumn, bounds.minRow - 1] as RichCell;

            var trr = _matrix[bounds.maxColumn + 1, bounds.maxRow] as RichCell;
            var trt = _matrix[bounds.maxColumn, bounds.maxRow + 1] as RichCell;

            if (bll != null && blb != null)
            {
                UpdateCellHeightData(bll, blb, ledgeThreshold, 1, -1);
                yield return null;
            }

            if (tll != null && tlt != null)
            {
                UpdateCellHeightData(tll, tlt, ledgeThreshold, 1, 1);
                yield return null;
            }

            if (brr != null && brb != null)
            {
                UpdateCellHeightData(brr, brb, ledgeThreshold, -1, -1);
                yield return null;
            }

            if (trr != null && trt != null)
            {
                UpdateCellHeightData(trr, trt, ledgeThreshold, -1, 1);
                yield return null;
            }
        }
 static MatrixBounds()
 {
     MatrixBounds.nullBounds = new MatrixBounds(-1, -1, -2, -2);
 }
Example #16
0
 public IHeightLookup PrepareForUpdate(MatrixBounds suggestedBounds, out MatrixBounds requiredBounds)
 {
     requiredBounds = suggestedBounds;
     return(this);
 }
Example #17
0
 IHeightLookup IHeightLookup.PrepareForUpdate(MatrixBounds suggestedBounds, out MatrixBounds requiredBounds)
 {
     throw new InvalidOperationException("This is a temporary construct used for dynamic updates only.");
 }
Example #18
0
            public MatrixBounds Prepare(CellMatrix matrix, bool block)
            {
                _lastCoverage = _newCoverage;

                if (!block)
                {
                    _newCoverage = MatrixBounds.nullBounds;
                    return _lastCoverage;
                }

                var velocity = _parent.GetVelocity();

                var sensitivity = (matrix.cellSize / 2f) - (_parent.useGridObstacleSensitivity ? matrix.obstacleSensitivityRange : _parent.customSensitivity);

                var bounds = GrowBoundsByVelocity(_collider.bounds, velocity);

                _newCoverage = matrix.GetMatrixBounds(bounds, sensitivity, true);

                return MatrixBounds.Combine(_lastCoverage, _newCoverage);
            }
Example #19
0
 public bool Contains(MatrixBounds other)
 {
     return((other.maxRow <= this.maxRow) && (other.minRow >= this.minRow) && (other.maxColumn <= this.maxColumn) && (other.minColumn >= this.minColumn));
 }
Example #20
0
 /// <summary>
 /// Gets a range of items
 /// </summary>
 /// <param name="bounds">The bounds specifying the index range.</param>
 /// <returns>The range of items that lie inside the index range given by the parameter.</returns>
 public IEnumerable <T> GetRange(MatrixBounds bounds)
 {
     return(GetRange(bounds.minColumn, bounds.maxColumn, bounds.minRow, bounds.maxRow));
 }
Example #21
0
        private UpdatingHeightTree GetUpdateTree(HeightQuadTree parent, int parentIdx, MatrixBounds suggestedBounds)
        {
            if (_subTrees != null)
            {
                for (int i = 0; i < 4; i++)
                {
                    if (_subTrees[i]._bounds.Contains(suggestedBounds))
                    {
                        return(_subTrees[i].GetUpdateTree(this, i, suggestedBounds));
                    }
                }
            }

            if (parent != null)
            {
                var freshStart = new HeightQuadTree(_bounds, _depth, _maxDepth);
                return(new UpdatingHeightTree(freshStart, parent, parentIdx));
            }

            return(null);
        }
Example #22
0
 IHeightLookup IHeightLookup.PrepareForUpdate(MatrixBounds suggestedBounds, out MatrixBounds requiredBounds)
 {
     throw new InvalidOperationException("This is a temporary construct used for dynamic updates only.");
 }
        internal IGrid Initialize(PortalCell partner, Bounds portalBounds)
        {
            var grid = GridManager.instance.GetGrid(portalBounds.center);
            if (grid == null)
            {
                return null;
            }

            _partner = partner;
            this.parent = grid.cellMatrix;
            this.position = portalBounds.center;

            _matrixBounds = grid.cellMatrix.GetMatrixBounds(portalBounds, 0.0f, true);
            _neighbourNodes = grid.cellMatrix.GetRange(_matrixBounds).ToArray();

            return grid;
        }
Example #24
0
 /// <summary>
 /// Gets a range of items
 /// </summary>
 /// <param name="bounds">The bounds specifying the index range.</param>
 /// <param name="predicate">A filter predicate, only those elements that match the predicate will be included in the result.</param>
 /// <param name="result">The result to be populated by the range of items that lie inside the index range given by the parameter.</param>
 public void GetRange(MatrixBounds bounds, Func <T, bool> predicate, ICollection <T> result)
 {
     GetRange(bounds.minColumn, bounds.maxColumn, bounds.minRow, bounds.maxRow, predicate, result);
 }
Example #25
0
 public IHeightLookup PrepareForUpdate(MatrixBounds suggestedBounds, out MatrixBounds requiredBounds)
 {
     requiredBounds = suggestedBounds;
     return this;
 }
Example #26
0
 public AxisBounds(Collider collider, DynamicObstacle parent)
 {
     _collider = collider;
     _parent = parent;
     _lastCoverage = _newCoverage = MatrixBounds.nullBounds;
 }
Example #27
0
 /// <summary>
 /// Gets a range of items
 /// </summary>
 /// <param name="bounds">The bounds specifying the index range.</param>
 /// <param name="result">The result to be populated by the range of items that lie inside the index range given by the parameter.</param>
 public void GetRange(MatrixBounds bounds, ICollection <T> result)
 {
     GetRange(bounds.minColumn, bounds.maxColumn, bounds.minRow, bounds.maxRow, result);
 }
        /// <summary>
        /// Assigns height settings to a portion of the matrix.
        /// </summary>
        /// <param name="bounds">The portion of the matrix to update.</param>
        /// <returns>
        /// An enumerator which once enumerated will do the update.
        /// </returns>
        public override IEnumerator AssignHeightSettings(MatrixBounds bounds)
        {
            if (_maxWalkableSlopeAngle >= 90f)
            {
                yield break;
            }

            var ledgeThreshold = Mathf.Tan(GameServices.heightStrategy.ledgeThreshold * Mathf.Deg2Rad) * _matrix.granularity;
            var maxHeightDiff = Mathf.Tan(_maxWalkableSlopeAngle * Mathf.Deg2Rad) * _granularity;
            var maxHeightDiffDiag = maxHeightDiff * Consts.SquareRootTwo;

            var maxColumn = bounds.maxColumn;
            var maxRow = bounds.maxRow;
            bool isPartial = (maxColumn - bounds.minColumn < _matrix.columns - 1) || (maxRow - bounds.minRow < _matrix.rows - 1);

            var rawMatrix = _matrix.rawMatrix;
            for (int x = bounds.minColumn; x <= maxColumn; x++)
            {
                for (int z = bounds.minRow; z <= maxRow; z++)
                {
                    var c = rawMatrix[x, z] as StandardCell;
                    if (c.isPermanentlyBlocked)
                    {
                        continue;
                    }

                    //Process neighbours
                    for (int dz = -1; dz <= 1; dz++)
                    {
                        for (int dx = -1; dx <= 1; dx++)
                        {
                            if (dx == 0 && dz == 0)
                            {
                                continue;
                            }

                            var n = _matrix[x + dx, z + dz] as StandardCell;
                            if (n == null || n.isPermanentlyBlocked)
                            {
                                continue;
                            }

                            var pos = n.GetRelativePositionTo(c);
                            if (!isPartial && (c.heightIntializedFrom & pos) > 0)
                            {
                                continue;
                            }

                            //If doing a partial update we need to remove the blocked flag from the neighbour first since he may not be processed on his own.
                            if (isPartial)
                            {
                                c.heightBlockedFrom &= ~pos;
                                n.heightBlockedFrom &= ~c.GetRelativePositionTo(n);
                            }

                            switch (pos)
                            {
                                //Straight neighbours
                                case NeighbourPosition.Bottom:
                                case NeighbourPosition.Top:
                                case NeighbourPosition.Left:
                                case NeighbourPosition.Right:
                                {
                                    UpdateCellHeightData(c, n, pos, maxHeightDiff, ledgeThreshold, true);
                                    break;
                                }

                                //diagonals
                                default:
                                {
                                    UpdateCellHeightData(c, n, pos, maxHeightDiffDiag, ledgeThreshold, false);
                                    break;
                                }
                            }

                            yield return null;
                        }
                    } /* end neighbour loop */
                }
            }

            if (!isPartial)
            {
                yield break;
            }

            //Update corner diagonals, this is only relevant for partial updates
            //Since the cells being updated only update their own relation to neighbours, there will potentially be 4 connections not updated,
            //those are the diagonals between the cells surround each corner of the bounds, e.g. bottom left corner the connection between the cell to the left and the cell below that corner.
            //since updates also update the involved neighbour, we only have to update 4 additional cells, and only on a specific diagonal.
            var bll = _matrix[bounds.minColumn - 1, bounds.minRow] as StandardCell;
            var blb = _matrix[bounds.minColumn, bounds.minRow - 1] as StandardCell;

            var tll = _matrix[bounds.minColumn - 1, bounds.maxRow] as StandardCell;
            var tlt = _matrix[bounds.minColumn, bounds.maxRow + 1] as StandardCell;

            var brr = _matrix[bounds.maxColumn + 1, bounds.minRow] as StandardCell;
            var brb = _matrix[bounds.maxColumn, bounds.minRow - 1] as StandardCell;

            var trr = _matrix[bounds.maxColumn + 1, bounds.maxRow] as StandardCell;
            var trt = _matrix[bounds.maxColumn, bounds.maxRow + 1] as StandardCell;

            if (bll != null && blb != null)
            {
                bll.heightBlockedFrom &= ~NeighbourPosition.BottomRight;
                blb.heightBlockedFrom &= ~NeighbourPosition.TopLeft;
                UpdateCellHeightData(bll, blb, NeighbourPosition.BottomRight, maxHeightDiffDiag, ledgeThreshold, false);
                yield return null;
            }

            if (tll != null && tlt != null)
            {
                tll.heightBlockedFrom &= ~NeighbourPosition.TopRight;
                tlt.heightBlockedFrom &= ~NeighbourPosition.BottomLeft;
                UpdateCellHeightData(tll, tlt, NeighbourPosition.TopRight, maxHeightDiffDiag, ledgeThreshold, false);
                yield return null;
            }

            if (brr != null && brb != null)
            {
                brr.heightBlockedFrom &= ~NeighbourPosition.BottomLeft;
                brb.heightBlockedFrom &= ~NeighbourPosition.TopRight;
                UpdateCellHeightData(brr, brb, NeighbourPosition.BottomLeft, maxHeightDiffDiag, ledgeThreshold, false);
                yield return null;
            }

            if (trr != null && trt != null)
            {
                trr.heightBlockedFrom &= ~NeighbourPosition.TopLeft;
                trt.heightBlockedFrom &= ~NeighbourPosition.BottomRight;
                UpdateCellHeightData(trr, trt, NeighbourPosition.TopLeft, maxHeightDiffDiag, ledgeThreshold, false);
                yield return null;
            }
        }
 /// <summary>
 /// Assigns height settings to a portion of the matrix.
 /// </summary>
 /// <param name="bounds">The portion of the matrix to update.</param>
 /// <returns>An enumerator which once enumerated will do the update.</returns>
 public abstract IEnumerator AssignHeightSettings(MatrixBounds bounds);