/// <summary>
        /// Initializes a new instance of the <see cref="FullGridVectorField"/> class.
        /// </summary>
        /// <param name="group">The transient unit group.</param>
        /// <param name="path">The path.</param>
        /// <param name="options">The vector field options.</param>
        public FullGridVectorField(TransientGroup<IUnitFacade> group, Path path, VectorFieldOptions options)
        {
            Ensure.ArgumentNotNull(group, "group");
            this.group = group;

            _currentPath = path;

            var modelUnit = group.modelUnit;
            _unitProperties = modelUnit;
            var pathOptions = modelUnit.pathFinderOptions;

            // cache options locally
            _obstacleStrengthFactor = options.obstacleStrengthFactor;
            _allowCornerCutting = pathOptions.allowCornerCutting;
            _allowDiagonals = !pathOptions.preventDiagonalMoves;
            _announceAllNodes = modelUnit.pathNavigationOptions.announceAllNodes;

            _builtInContainment = options.builtInContainment;
            _updateInterval = options.updateInterval;

            // pre-allocate lists
            _openSet = new SimpleQueue<Cell>(31);
            _tempWalkableNeighbours = new DynamicArray<Cell>(8);
            _extraTempWalkableNeighbours = new DynamicArray<Cell>(8);

            _grid = GridManager.instance.GetGrid(group.modelUnit.position);
            if (_grid != null)
            {
                _fastMarchedCells = new PlaneVector[_grid.sizeX, _grid.sizeZ];
                _cellDirs = new VectorFieldCell[_grid.sizeX, _grid.sizeZ];
            }
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="ProgressiveVectorField"/> class.
        /// </summary>
        /// <param name="group">The group.</param>
        /// <param name="path">The path.</param>
        /// <param name="options">The options.</param>
        public ProgressiveVectorField(TransientGroup<IUnitFacade> group, Path path, VectorFieldOptions options)
        {
            Ensure.ArgumentNotNull(group, "group");
            this.group = group;

            _currentPath = path;

            var modelUnit = group.modelUnit;
            _unitProperties = modelUnit;
            var pathOptions = modelUnit.pathFinderOptions;

            // cache options locally
            _allowCornerCutting = pathOptions.allowCornerCutting;
            _allowDiagonals = !pathOptions.preventDiagonalMoves;
            _announceAllNodes = modelUnit.pathNavigationOptions.announceAllNodes;

            _obstacleStrengthFactor = options.obstacleStrengthFactor;
            _builtInContainment = options.builtInContainment;
            _updateInterval = options.updateInterval;
            _paddingIncrease = options.paddingIncrease;
            _maxExtraPadding = options.maxExtraPadding;
            _boundsPadding = options.boundsPadding;
            _boundsRecalculateThreshold = options.boundsRecalculateThreshold;
            _expectedGroupGrowthFactor = 1f + options.expectedGroupGrowthFactor;

            // pre-allocate lists memory
            _openSet = new SimpleQueue<Cell>(31);
            _tempWalkableNeighbours = new DynamicArray<Cell>(8);
            _extraTempWalkableNeighbours = new DynamicArray<Cell>(8);
            _groupBounds = new RectangleXZ(group.centerOfGravity, _boundsPadding, _boundsPadding);
        }
Beispiel #3
0
        /// <summary>
        /// Determines whether the cell is walkable from all directions.
        /// </summary>
        /// <param name="unitProps">The unit properties.</param>
        /// <returns><c>true</c> if the cell is walkable, otherwise <c>false</c></returns>
        public override bool isWalkableFromAllDirections(IUnitProperties unitProps)
        {
            if (!isWalkable(unitProps.attributes))
            {
                return false;
            }

            return (_heightBlockedFrom == NeighbourPosition.None);
        }
        public static Cell GetNearestWalkableCellFromRelation(this IGrid grid, Vector3 position, Vector3 inRelationTo, bool requireWalkableFromPosition, int maxCellDistance, IUnitProperties unitProps)
        {
            var cell = grid.GetCell(position);
            if (cell == null)
            {
                return null;
            }

            if (cell.isWalkable(unitProps.attributes))
            {
                return cell;
            }

            var relationCell = grid.GetCell(inRelationTo);
            if (relationCell == null)
            {
                return null;
            }

            int dist = 1;
            var unitAttributes = unitProps.attributes;
            var candidates = new List<Cell>();
            while (candidates.Count == 0 && dist <= maxCellDistance)
            {
                foreach (var c in grid.GetConcentricNeighbours(cell, dist++))
                {
                    if (requireWalkableFromPosition)
                    {
                        if (c.isWalkableFrom(relationCell, unitProps))
                        {
                            candidates.Add(c);
                        }
                    }
                    else if (c.isWalkable(unitAttributes))
                    {
                        candidates.Add(c);
                    }
                }
            }

            Cell winner = null;
            float lowestDist = float.MaxValue;
            for (int i = 0; i < candidates.Count; i++)
            {
                var distSqr = (candidates[i].position - inRelationTo).sqrMagnitude;
                if (distSqr < lowestDist)
                {
                    winner = candidates[i];
                    lowestDist = distSqr;
                }
            }

            return winner;
        }
Beispiel #5
0
        /// <summary>
        /// Determines whether the cell is walkable from the specified neighbour.
        /// </summary>
        /// <param name="neighbour">The neighbour.</param>
        /// <param name="unitProps">The unit properties.</param>
        /// <returns><c>true</c> if the cell is walkable, otherwise <c>false</c></returns>
        public override bool isWalkableFrom(IGridCell neighbour, IUnitProperties unitProps)
        {
            if (!isWalkable(unitProps.attributes))
            {
                return false;
            }

            var pos = neighbour.GetRelativePositionTo(this);

            return (_heightBlockedFrom & pos) == 0;
        }
Beispiel #6
0
        /// <summary>
        /// Determines whether the cell is walkable from all directions.
        /// </summary>
        /// <param name="mask">The mask.</param>
        /// <returns><c>true</c> if the cell is walkable, otherwise <c>false</c></returns>
        public override bool isWalkableFromAllDirections(IUnitProperties unitProps)
        {
            if (!isWalkable(unitProps.attributes))
            {
                return false;
            }

            var uc = unitProps.heightNavigationCapability;

            return ((uc.maxClimbHeight >= _worstCase.dropHeight && uc.maxDropHeight >= _worstCase.climbHeight) || uc.maxSlopeAngle >= _worstCase.slope);
        }
Beispiel #7
0
        /// <summary>
        /// Determines whether the cell is walkable from the specified neighbour.
        /// </summary>
        /// <param name="neighbour">The neighbour.</param>
        /// <param name="mask">The attribute mask used to determine walk-ability.</param>
        /// <returns><c>true</c> if the cell is walkable, otherwise <c>false</c></returns>
        public override bool isWalkableFrom(IGridCell neighbour, IUnitProperties unitProps)
        {
            if (!isWalkable(unitProps.attributes))
            {
                return false;
            }

            var dx = Mathf.Clamp(neighbour.matrixPosX - this.matrixPosX, -1, 1);
            var dz = Mathf.Clamp(neighbour.matrixPosZ - this.matrixPosZ, -1, 1);

            var idx = (dx + (3 * dz) + 4);

            var uc = unitProps.heightNavigationCapability;
            var d = _heightData[idx];

            //We compare to opposites since this is from the neighbour's point of view
            return ((uc.maxClimbHeight >= d.dropHeight && uc.maxDropHeight >= d.climbHeight) || uc.maxSlopeAngle >= d.slope);
        }
        /// <summary>
        /// Initializes a new instance of the <see cref="FunnelVectorField"/> class.
        /// </summary>
        /// <param name="group">The group.</param>
        /// <param name="path">The path.</param>
        /// <param name="options">The options.</param>
        public FunnelVectorField(TransientGroup<IUnitFacade> group, Path path, VectorFieldOptions options)
        {
            Ensure.ArgumentNotNull(group, "group");
            this.group = group;

            _currentPath = path;

            var modelUnit = group.modelUnit;
            _unitProperties = modelUnit;
            var pathOptions = modelUnit.pathFinderOptions;

            // cache options locally
            _funnelWidth = options.funnelWidth;
            _obstacleStrengthFactor = options.obstacleStrengthFactor;
            _allowCornerCutting = pathOptions.allowCornerCutting;
            _allowDiagonals = !pathOptions.preventDiagonalMoves;
            _announceAllNodes = modelUnit.pathNavigationOptions.announceAllNodes;

            _builtInContainment = options.builtInContainment;
            _updateInterval = options.updateInterval;

            // pre-allocate lists memory
            _openSet = new SimpleQueue<Cell>(31);
            _tempWalkableNeighbours = new DynamicArray<Cell>(8);
            _extraTempWalkableNeighbours = new DynamicArray<Cell>(8);

            _grid = GridManager.instance.GetGrid(group.modelUnit.position);
            if (_grid != null)
            {
                // we allocate half of the grid's size in order to have a bit more allocated memory than we expect to actually use
                int size = Mathf.CeilToInt((_grid.sizeX * _grid.sizeZ) / 2f);

                float minF = 9.99999944E-11f;
                _cellDirsSet = new Dictionary<Vector3, VectorFieldCell>(size, new Vector3EqualityComparer(minF));
                _fastMarchedCellsSet = new Dictionary<Vector3, PlaneVector>(size, new Vector3EqualityComparer(minF));
            }

            _funnelWidthSqr = _funnelWidth * _funnelWidth;
        }
Beispiel #9
0
        private static bool CanReducePath(IPositioned point1, IPositioned point3, IUnitProperties unitProps, CellMatrix matrix, ICellCostStrategy costStrategy)
        {
            Vector3 p1;
            Vector3 p3;

            //Assign the points so we start with the point with the lowest x-value to simplify things
            if (point1.position.x > point3.position.x)
            {
                p1 = point3.position;
                p3 = point1.position;
            }
            else
            {
                p1 = point1.position;
                p3 = point3.position;
            }

            var requesterRadius = unitProps.radius;
            var tan             = Tangents.Create(p1, p3, requesterRadius);

            var incZ     = tan.slopeDir;
            var cellSize = matrix.cellSize;
            var halfCell = cellSize / 2.0f;

            //Adjust the start and end cells to possibly include their immediate neighbour if the unit's radius crossed said boundary.
            var radiusAdjust = new Vector3(requesterRadius, 0.0f, requesterRadius * incZ);

            //Get the start and end cells, get the cost of the actual start and end, and then reassign the start and end with the above adjustment.
            var startCell = matrix.GetCell(p1, true);
            var startCost = costStrategy.GetCellCost(startCell, unitProps);

            startCell = matrix.GetCell(p1 - radiusAdjust, true);

            var endCell = matrix.GetCell(p3, true);
            var endCost = costStrategy.GetCellCost(endCell, unitProps);

            endCell = matrix.GetCell(p3 + radiusAdjust, true);

            //We want x to end up on cell boundaries, the first of which is this far from the first points position
            var xAdj = p1.x + (startCell.position.x - p1.x) + halfCell;

            //We want to adjust z so that we correctly count impacted cells, this adjusts z so it starts at the bottom boundary of the first cell (for purposes of calculation)
            var zAdj = p1.z - (halfCell + ((p1.z - startCell.position.z) * incZ));

            //The movement across the x-axis
            float deltaX = 0.0f;

            var cellMatrix = matrix.rawMatrix;
            int indexX     = 0;

            for (int x = startCell.matrixPosX; x <= endCell.matrixPosX; x++)
            {
                //So instead of just checking all cells in the bounding rect defined by the two cells p1 and p3,
                //we limit it to the cells immediately surrounding the proposed line (tangents), including enough cells that we ensure the unit will be able to pass through,
                //at the extreme routes between the two cells (i.e top corner to top corner and bottom corner to bottom corner
                int startZ;
                int endZ;

                //If the tangents are horizontal or vertical z range is obvious
                if (tan.isAxisAligned)
                {
                    startZ = startCell.matrixPosZ;
                    endZ   = endCell.matrixPosZ + incZ;
                }
                else
                {
                    if (indexX == 0)
                    {
                        startZ = startCell.matrixPosZ;
                    }
                    else
                    {
                        var startCellsPassed = Mathf.FloorToInt((tan.LowTangent(deltaX) - zAdj) / cellSize) * incZ;

                        startZ = LimitStart(
                            startCell.matrixPosZ + startCellsPassed,
                            startCell.matrixPosZ,
                            incZ);
                    }

                    //The movement this step will perform across the x-axis
                    deltaX = xAdj + (indexX * cellSize);

                    var endCellsIntercepted = Mathf.FloorToInt((tan.HighTangent(deltaX) - zAdj) / cellSize) * incZ;

                    endZ = LimitEnd(
                        startCell.matrixPosZ + endCellsIntercepted,
                        endCell.matrixPosZ,
                        incZ) + incZ;
                }

                indexX++;

                for (int z = startZ; z != endZ; z += incZ)
                {
                    var intermediary     = cellMatrix[x, z];
                    var intermediaryCost = costStrategy.GetCellCost(intermediary, unitProps);
                    if (!intermediary.isWalkableFrom(startCell, unitProps) || (startCost < intermediaryCost && endCost < intermediaryCost))
                    {
                        return(false);
                    }
                }
            }

            return(true);
        }
Beispiel #10
0
 void IPathNode.GetWalkableNeighbours(DynamicArray<IPathNode> neighbours, IUnitProperties unitProps, bool cornerCuttingAllowed, bool preventDiagonalMoves)
 {
     var destinationNodes = _partner._neighbourNodes;
     var nodeCount = destinationNodes.Length;
     var unitAttributes = unitProps.attributes;
     for (int i = 0; i < nodeCount; i++)
     {
         if (destinationNodes[i].isWalkable(unitAttributes))
         {
             neighbours.Add(destinationNodes[i]);
         }
     }
 }
Beispiel #11
0
        bool IPathNode.TryGetWalkableNeighbour(int dx, int dz, IUnitProperties unitProps, DynamicArray<IPathNode> neighbours)
        {
            var x = this.matrixPosX + dx;
            var z = this.matrixPosZ + dz;

            var neighbour = _parent[x, z];

            if (neighbour == null)
            {
                return false;
            }

            if (neighbour.isWalkableFrom(this, unitProps))
            {
                neighbours.Add(neighbour);
                return true;
            }

            return false;
        }
Beispiel #12
0
 /// <summary>
 /// Determines whether the cell is walkable from the specified neighbour. This check does not take unit size into consideration.
 /// </summary>
 /// <param name="neighbour">The neighbour.</param>
 /// <param name="unitProps">The unit properties.</param>
 /// <returns>
 ///   <c>true</c> if the cell is walkable, otherwise <c>false</c>
 /// </returns>
 public abstract bool IsWalkableFrom(IGridCell neighbour, IUnitProperties unitProps);
Beispiel #13
0
        /// <summary>
        /// Called when a request is about to be processed.
        /// </summary>
        /// <param name="start">The start node.</param>
        protected override void OnStart(IPathNode start)
        {
            _openSet.Clear();

            //Reset all g's on all nodes marking them not expanded
            _expandedSet.Apply(c => c.g = 0);
            _expandedSet.Clear();
            _closestNode = start;

            //Initialize and add the start node. Since no expanded set is used start g must be initialized to a small > 0  value to mark it as expanded
            //Since the start node will never reenter the open set, there is no need to initialize the h and f values.
            start.g = 1;
            start.h = this.costProvider.GetHeuristic(start, this.goal);
            start.predecessor = null;

            _openSet.Add(start);
            _expandedSet.Add(start);

            _unitProps = this.currentRequest.requesterProperties;
            _unitAttributes = _unitProps.attributes;
            _preventDiagonalMoves = this.currentRequest.pathFinderOptions.preventDiagonalMoves;
            _cutCorners = this.currentRequest.pathFinderOptions.allowCornerCutting;
        }
Beispiel #14
0
        /// <summary>
        /// Gets the walkable neighbours.
        /// </summary>
        /// <param name="grid">The grid</param>
        /// <param name="c">The cell whose walkable neighbours to return.</param>
        /// <param name="unitProps">The unit properties</param>
        /// <param name="excludeCornerCutting">if set to <c>true</c> otherwise walkable neighbours on the diagonal that would cause a move from it to the current cell to cut a corner are excluded (deemed not walkable).</param>
        /// <returns>The walkable neighbours to the referenced cell.</returns>
        public static IEnumerable <Cell> GetWalkableNeighbours(this IGrid grid, IGridCell c, IUnitProperties unitProps, bool excludeCornerCutting)
        {
            Cell n;

            //Straight move neighbours
            bool uw = grid.TryGetWalkableNeighbour(c, 0, 1, unitProps, out n);

            if (uw)
            {
                yield return(n);
            }

            bool dw = grid.TryGetWalkableNeighbour(c, 0, -1, unitProps, out n);

            if (dw)
            {
                yield return(n);
            }

            bool rw = grid.TryGetWalkableNeighbour(c, 1, 0, unitProps, out n);

            if (rw)
            {
                yield return(n);
            }

            bool lw = grid.TryGetWalkableNeighbour(c, -1, 0, unitProps, out n);

            if (lw)
            {
                yield return(n);
            }

            //Diagonal neighbours. First determine if they are unwalkable as a consequence of their straight neighbours
            bool urw, drw, dlw, ulw;

            if (excludeCornerCutting)
            {
                urw = uw && rw;
                drw = dw && rw;
                dlw = dw && lw;
                ulw = uw && lw;
            }
            else
            {
                urw = uw || rw;
                drw = dw || rw;
                dlw = dw || lw;
                ulw = uw || lw;
            }

            urw = urw && grid.TryGetWalkableNeighbour(c, 1, 1, unitProps, out n);
            if (urw)
            {
                yield return(n);
            }

            drw = drw && grid.TryGetWalkableNeighbour(c, 1, -1, unitProps, out n);
            if (drw)
            {
                yield return(n);
            }

            dlw = dlw && grid.TryGetWalkableNeighbour(c, -1, -1, unitProps, out n);
            if (dlw)
            {
                yield return(n);
            }

            ulw = ulw && grid.TryGetWalkableNeighbour(c, -1, 1, unitProps, out n);
            if (ulw)
            {
                yield return(n);
            }
        }
Beispiel #15
0
        private bool ValidateGoalNeighbour(IUnitProperties unitProps, int dx, int dz)
        {
            var c = _goal.GetNeighbour(dx, dz);

            return((c == null) || c.isWalkableFrom(_goal, unitProps));
        }
Beispiel #16
0
 /// <summary>
 /// Gets a walkable neighbours iterator. Optimization used by the pathing engines.
 /// </summary>
 /// <param name="c">The reference cell.</param>
 /// <param name="requesterAttributes">The requester attributes.</param>
 /// <param name="excludeCornerCutting">whether to exclude corner cutting.</param>
 /// <returns>
 /// An enumerator of the walkable cells
 /// </returns>
 public IEnumerator <IPathNode> GetWalkableNeighboursIterator(IGridCell c, IUnitProperties unitProps, bool excludeCornerCutting)
 {
     _walkableIter.Prepare(c, unitProps, excludeCornerCutting);
     return(_walkableIter);
 }
Beispiel #17
0
 bool IGridCell.isWalkableFromAllDirections(IUnitProperties unitProps)
 {
     return(isWalkable(unitProps.attributes));
 }
Beispiel #18
0
        public static bool CanReducePath(IPositioned point1, IPositioned point3, IUnitProperties unitProps, CellMatrix matrix, ICellCostStrategy costStrategy)
        {
            Vector3 p1;
            Vector3 p3;

            //Assign the points so we start with the point with the lowest x-value to simplify things
            if (point1.position.x > point3.position.x)
            {
                p1 = point3.position;
                p3 = point1.position;
            }
            else
            {
                p1 = point1.position;
                p3 = point3.position;
            }

            var requesterRadius = unitProps.radius;
            var tan = Tangents.Create(p1, p3, requesterRadius);

            var incZ = tan.slopeDir;
            var cellSize = matrix.cellSize;
            var halfCell = cellSize / 2.0f;

            //Adjust the start and end cells to possibly include their immediate neighbour if the unit's radius crossed said boundary.
            var radiusAdjust = new Vector3(requesterRadius, 0.0f, requesterRadius * incZ);

            //Get the start and end cells, get the cost of the actual start and end, and then reassign the start and end with the above adjustment.
            var startCell = matrix.GetCell(p1, true);
            var startCost = costStrategy.GetCellCost(startCell, unitProps);

            startCell = matrix.GetCell(p1 - radiusAdjust, true);

            var endCell = matrix.GetCell(p3, true);
            var endCost = costStrategy.GetCellCost(endCell, unitProps);

            endCell = matrix.GetCell(p3 + radiusAdjust, true);

            //We want x to end up on cell boundaries, the first of which is this far from the first points position
            var xAdj = p1.x + (startCell.position.x - p1.x) + halfCell;

            //We want to adjust z so that we correctly count impacted cells, this adjusts z so it starts at the bottom boundary of the first cell (for purposes of calculation)
            var zAdj = p1.z - (halfCell + ((p1.z - startCell.position.z) * incZ));

            //The movement across the x-axis
            float deltaX = 0.0f;

            var cellMatrix = matrix.rawMatrix;
            int indexX = 0;
            for (int x = startCell.matrixPosX; x <= endCell.matrixPosX; x++)
            {
                //So instead of just checking all cells in the bounding rect defined by the two cells p1 and p3,
                //we limit it to the cells immediately surrounding the proposed line (tangents), including enough cells that we ensure the unit will be able to pass through,
                //at the extreme routes between the two cells (i.e top corner to top corner and bottom corner to bottom corner
                int startZ;
                int endZ;

                //If the tangents are horizontal or vertical z range is obvious
                if (tan.isAxisAligned)
                {
                    startZ = startCell.matrixPosZ;
                    endZ = endCell.matrixPosZ + incZ;
                }
                else
                {
                    if (indexX == 0)
                    {
                        startZ = startCell.matrixPosZ;
                    }
                    else
                    {
                        var startCellsPassed = Mathf.FloorToInt((tan.LowTangent(deltaX) - zAdj) / cellSize) * incZ;

                        startZ = LimitStart(
                            startCell.matrixPosZ + startCellsPassed,
                            startCell.matrixPosZ,
                            incZ);
                    }

                    //The movement this step will perform across the x-axis
                    deltaX = xAdj + (indexX * cellSize);

                    var endCellsIntercepted = Mathf.FloorToInt((tan.HighTangent(deltaX) - zAdj) / cellSize) * incZ;

                    endZ = LimitEnd(
                        startCell.matrixPosZ + endCellsIntercepted,
                        endCell.matrixPosZ,
                        incZ) + incZ;
                }

                indexX++;

                for (int z = startZ; z != endZ; z += incZ)
                {
                    var intermediary = cellMatrix[x, z];
                    var intermediaryCost = costStrategy.GetCellCost(intermediary, unitProps);
                    if (!intermediary.isWalkableFrom(startCell, unitProps) || (startCost < intermediaryCost && endCost < intermediaryCost))
                    {
                        return false;
                    }
                }
            }

            return true;
        }
        /// <summary>
        /// Determines whether an unobstructed path exists between two points.
        /// </summary>
        /// <param name="from">The from point.</param>
        /// <param name="to">The to point.</param>
        /// <param name="unitProps">The unit properties to test against (Walkability).</param>
        /// <param name="matrix">The matrix where both <paramref name="from"/> and <paramref name="to"/> must be part of.</param>
        /// <param name="costStrategy">The cost strategy.</param>
        /// <returns><c>true</c> if an unobstructed path exists between the two points; otherwise <c>false</c>.</returns>
        public static bool CanReducePath(IPositioned from, IPositioned to, IUnitProperties unitProps, CellMatrix matrix, ICellCostStrategy costStrategy)
        {
            //The reference cell is always the from cell. The fact the points are swapped to simplify tangents does not affect this.
            var refCell = matrix.GetCell(from.position, false);

            Vector3 p1;
            Vector3 p2;

            //Assign the points so we start with the point with the lowest x-value to simplify things
            if (from.position.x > to.position.x)
            {
                p1 = to.position;
                p2 = from.position;
            }
            else
            {
                p1 = from.position;
                p2 = to.position;
            }

            var unitRadius = unitProps.radius;
            var tan        = Tangents.Create(p1, p2, unitRadius, matrix);

            var slopeDir = tan.slopeDir;
            var cellSize = matrix.cellSize;
            var halfCell = cellSize * 0.5f;

            //Get the start and end cells, get the cost of the actual start and end, and then reassign the start and end to accommodate for unit size.
            var startCell = matrix.GetCell(p1, false);
            var startCost = costStrategy.GetCellCost(startCell, unitProps);

            startCell = matrix.GetCell(new Vector3(p1.x - unitRadius, p1.y, p1.z), true);

            var endCell = matrix.GetCell(p2, false);
            var endCost = costStrategy.GetCellCost(endCell, unitProps);

            endCell = matrix.GetCell(new Vector3(p2.x + unitRadius, p2.y, p2.z), true);

            //The movement across the x-axis
            float minXCoord = (startCell.position.x - matrix.start.x) - halfCell;
            float maxXCoord = (startCell.position.x - matrix.start.x) + halfCell;

            int minZ;
            int maxZ;

            if (slopeDir < 0)
            {
                var distLowerCellBoundary = halfCell - (endCell.position.z - p2.z);
                var minOverlap            = Mathf.CeilToInt((unitRadius - distLowerCellBoundary) / cellSize);
                minZ = Math.Max(0, endCell.matrixPosZ - Math.Max(0, minOverlap));

                var distUpperCellBoundary = halfCell - (p1.z - startCell.position.z);
                var maxOverlap            = Mathf.CeilToInt((unitRadius - distUpperCellBoundary) / cellSize);
                maxZ = Math.Min(matrix.rows - 1, startCell.matrixPosZ + Math.Max(0, maxOverlap));
            }
            else
            {
                var distLowerCellBoundary = halfCell - (startCell.position.z - p1.z);
                var minOverlap            = Mathf.CeilToInt((unitRadius - distLowerCellBoundary) / cellSize);
                minZ = Math.Max(0, startCell.matrixPosZ - Math.Max(0, minOverlap));

                var distUpperCellBoundary = halfCell - (p2.z - endCell.position.z);
                var maxOverlap            = Mathf.CeilToInt((unitRadius - distUpperCellBoundary) / cellSize);
                maxZ = Math.Min(matrix.rows - 1, endCell.matrixPosZ + Math.Max(0, maxOverlap));
            }

            int  startX     = startCell.matrixPosX;
            int  endX       = endCell.matrixPosX;
            bool isVertical = tan.isVertical;
            var  cellMatrix = matrix.rawMatrix;

            for (int x = startX; x <= endX; x++)
            {
                int startZ;
                int endZ;

                if (isVertical)
                {
                    startZ = Math.Min(startCell.matrixPosZ, endCell.matrixPosZ);
                    endZ   = Math.Max(startCell.matrixPosZ, endCell.matrixPosZ);
                }
                else
                {
                    if (slopeDir < 0)
                    {
                        startZ = Math.Max((int)(tan.LowTangent(maxXCoord) / cellSize), minZ);
                        endZ   = Math.Min((int)(tan.HighTangent(minXCoord) / cellSize), maxZ);
                    }
                    else
                    {
                        startZ = Math.Max((int)(tan.LowTangent(minXCoord) / cellSize), minZ);
                        endZ   = Math.Min((int)(tan.HighTangent(maxXCoord) / cellSize), maxZ);
                    }
                }

                for (int z = startZ; z <= endZ; z++)
                {
                    var intermediary = cellMatrix[x, z];
                    if (!isVertical && tan.IsOutsideSecants(intermediary.position))
                    {
                        continue;
                    }

                    var intermediaryCost = costStrategy.GetCellCost(intermediary, unitProps);
                    if (!intermediary.IsWalkableFrom(refCell, unitProps) || (startCost < intermediaryCost || endCost < intermediaryCost))
                    {
                        return(false);
                    }
                }

                minXCoord = maxXCoord;
                maxXCoord = maxXCoord + cellSize;
            }

            return(true);
        }
Beispiel #20
0
 /// <summary>
 /// Determines whether the cell is walkable from all directions.
 /// </summary>
 /// <param name="mask">The mask.</param>
 /// <returns><c>true</c> if the cell is walkable, otherwise <c>false</c></returns>
 public abstract bool isWalkableFromAllDirections(IUnitProperties unitProps);
Beispiel #21
0
 /// <summary>
 /// Determines whether the cell is walkable from the specified neighbour.
 /// </summary>
 /// <param name="neighbour">The neighbour.</param>
 /// <param name="mask">The attribute mask used to determine walk-ability.</param>
 /// <returns><c>true</c> if the cell is walkable, otherwise <c>false</c></returns>
 public abstract bool isWalkableFrom(IGridCell neighbour, IUnitProperties unitProps);
 /// <summary>
 /// Determines whether the cell is walkable from all directions.
 /// </summary>
 /// <param name="unitProps">The unit properties.</param>
 /// <returns><c>true</c> if the cell is walkable, otherwise <c>false</c></returns>
 public override bool isWalkableFromAllDirections(IUnitProperties unitProps)
 {
     return isWalkable(unitProps.attributes);
 }
Beispiel #23
0
 /// <summary>
 /// Determines whether the cell is walkable from the specified neighbour.
 /// </summary>
 /// <param name="neighbour">The neighbour.</param>
 /// <param name="unitProps">The unit properties.</param>
 /// <returns><c>true</c> if the cell is walkable, otherwise <c>false</c></returns>
 public override bool IsWalkableFromWithClearance(IGridCell neighbour, IUnitProperties unitProps)
 {
     return(IsWalkableWithClearance(unitProps));
 }
Beispiel #24
0
            internal void Prepare(IGridCell c, IUnitProperties unitProps, bool excludeCornerCutting)
            {
                Reset();

                int idx = 0;

                Cell n;

                //Straight move neighbours
                bool uw = _g.TryGetWalkableNeighbour(c, 0, 1, unitProps, out n);

                if (uw)
                {
                    _neighbours[idx++] = n;
                }

                bool dw = _g.TryGetWalkableNeighbour(c, 0, -1, unitProps, out n);

                if (dw)
                {
                    _neighbours[idx++] = n;
                }

                bool rw = _g.TryGetWalkableNeighbour(c, 1, 0, unitProps, out n);

                if (rw)
                {
                    _neighbours[idx++] = n;
                }

                bool lw = _g.TryGetWalkableNeighbour(c, -1, 0, unitProps, out n);

                if (lw)
                {
                    _neighbours[idx++] = n;
                }

                //Diagonal neighbours. First determine if they are unwalkable as a consequence of their straight neighbours
                bool urw, drw, dlw, ulw;

                if (excludeCornerCutting)
                {
                    urw = uw && rw;
                    drw = dw && rw;
                    dlw = dw && lw;
                    ulw = uw && lw;
                }
                else
                {
                    urw = uw || rw;
                    drw = dw || rw;
                    dlw = dw || lw;
                    ulw = uw || lw;
                }

                urw = urw && _g.TryGetWalkableNeighbour(c, 1, 1, unitProps, out n);
                if (urw)
                {
                    _neighbours[idx++] = n;
                }

                drw = drw && _g.TryGetWalkableNeighbour(c, 1, -1, unitProps, out n);
                if (drw)
                {
                    _neighbours[idx++] = n;
                }

                dlw = dlw && _g.TryGetWalkableNeighbour(c, -1, -1, unitProps, out n);
                if (dlw)
                {
                    _neighbours[idx++] = n;
                }

                ulw = ulw && _g.TryGetWalkableNeighbour(c, -1, 1, unitProps, out n);
                if (ulw)
                {
                    _neighbours[idx++] = n;
                }
            }
 private bool ValidateGoalNeighbour(IUnitProperties unitProps, int dx, int dz)
 {
     var c = _goal.GetNeighbour(dx, dz);
     return ((c == null) || c.isWalkableFrom(_goal, unitProps));
 }
Beispiel #26
0
 public EvalData(IUnitProperties unit)
 {
     _unit = unit;
 }
Beispiel #27
0
        /// <summary>
        /// Gets the nearest walkable cell to a position seen in relation to another position.
        /// </summary>
        /// <param name="grid">The grid.</param>
        /// <param name="position">The position to check.</param>
        /// <param name="inRelationTo">The relative position.</param>
        /// <param name="requireWalkableFromPosition">Whether the cell to find must be accessible from the direction of <paramref name="position"/></param>
        /// <param name="maxCellDistance">The maximum cell distance to check.</param>
        /// <param name="unitProps">The unit properties.</param>
        /// <returns></returns>
        public static Cell GetNearestWalkableCellFromRelation(this IGrid grid, Vector3 position, Vector3 inRelationTo, bool requireWalkableFromPosition, int maxCellDistance, IUnitProperties unitProps)
        {
            var cell = grid.GetCell(position);

            if (cell == null)
            {
                return(null);
            }

            if (cell.IsWalkableWithClearance(unitProps))
            {
                return(cell);
            }

            var relationCell = grid.GetCell(inRelationTo);

            if (relationCell == null)
            {
                return(null);
            }

            int dist       = 1;
            var candidates = new List <Cell>();

            while (candidates.Count == 0 && dist <= maxCellDistance)
            {
                foreach (var c in grid.GetConcentricNeighbours(cell, dist++))
                {
                    if (requireWalkableFromPosition)
                    {
                        if (c.IsWalkableFromWithClearance(relationCell, unitProps))
                        {
                            candidates.Add(c);
                        }
                    }
                    else if (c.IsWalkableWithClearance(unitProps))
                    {
                        candidates.Add(c);
                    }
                }
            }

            Cell  winner     = null;
            float lowestDist = float.MaxValue;

            for (int i = 0; i < candidates.Count; i++)
            {
                var distSqr = (candidates[i].position - inRelationTo).sqrMagnitude;
                if (distSqr < lowestDist)
                {
                    winner     = candidates[i];
                    lowestDist = distSqr;
                }
            }

            return(winner);
        }
Beispiel #28
0
 bool IGridCell.IsWalkableFromAllDirections(IUnitProperties unitProps)
 {
     return(IsWalkableWithClearance(unitProps));
 }
Beispiel #29
0
 /// <summary>
 /// Determines whether the cell is walkable to a certain unit / unit type.
 /// </summary>
 /// <param name="unitProps">The unit properties.</param>
 /// <returns>
 ///   <c>true</c> if the cell is walkable, otherwise <c>false</c>
 /// </returns>
 public virtual bool IsWalkableWithClearance(IUnitProperties unitProps)
 {
     return(IsWalkable(unitProps.attributes));
 }
Beispiel #30
0
 bool IPathNode.TryGetWalkableNeighbour(int dx, int dz, IUnitProperties unitProps, DynamicArray <IPathNode> neighbours)
 {
     return(false);
 }
Beispiel #31
0
 /// <summary>
 /// Determines whether the cell is walkable.
 /// </summary>
 /// <param name="unitProps">The unit properties.</param>
 /// <returns>
 ///   <c>true</c> if the cell is walkable, otherwise <c>false</c>
 /// </returns>
 public bool IsWalkableWithClearance(IUnitProperties unitProps)
 {
     return(_parentPortal.IsUsableBy(unitProps.attributes));
 }
Beispiel #32
0
        void IPathNode.GetWalkableNeighbours(DynamicArray<IPathNode> neighbours, IUnitProperties unitProps, bool cornerCuttingAllowed, bool preventDiagonalMoves)
        {
            var @this = this as IPathNode;

            //Straight move neighbours
            bool uw = @this.TryGetWalkableNeighbour(0, 1, unitProps, neighbours);

            bool dw = @this.TryGetWalkableNeighbour(0, -1, unitProps, neighbours);

            bool rw = @this.TryGetWalkableNeighbour(1, 0, unitProps, neighbours);

            bool lw = @this.TryGetWalkableNeighbour(-1, 0, unitProps, neighbours);

            if (preventDiagonalMoves)
            {
                return;
            }

            //Diagonal neighbours. First determine if they are unwalkable as a consequence of their straight neighbours
            bool urw, drw, dlw, ulw;
            if (cornerCuttingAllowed)
            {
                urw = uw || rw;
                drw = dw || rw;
                dlw = dw || lw;
                ulw = uw || lw;
            }
            else
            {
                urw = uw && rw;
                drw = dw && rw;
                dlw = dw && lw;
                ulw = uw && lw;
            }

            if (urw)
            {
                @this.TryGetWalkableNeighbour(1, 1, unitProps, neighbours);
            }

            if (drw)
            {
                @this.TryGetWalkableNeighbour(1, -1, unitProps, neighbours);
            }

            if (dlw)
            {
                @this.TryGetWalkableNeighbour(-1, -1, unitProps, neighbours);
            }

            if (ulw)
            {
                @this.TryGetWalkableNeighbour(-1, 1, unitProps, neighbours);
            }
        }
Beispiel #33
0
 bool IGridCell.IsWalkableFromWithClearance(IGridCell neighbour, IUnitProperties unitProps)
 {
     return(_parentPortal.IsUsableBy(unitProps.attributes));
 }
Beispiel #34
0
 /// <summary>
 /// Determines whether the cell is walkable from all directions.
 /// </summary>
 /// <param name="unitProps">The unit properties.</param>
 /// <returns><c>true</c> if the cell is walkable, otherwise <c>false</c></returns>
 public override bool isWalkableFromAllDirections(IUnitProperties unitProps)
 {
     return(isWalkable(unitProps.attributes));
 }
Beispiel #35
0
 void IPathNode.GetVirtualNeighbours(DynamicArray <IPathNode> neighbours, IUnitProperties unitProps)
 {
     /* Currently not supported */
 }
Beispiel #36
0
 /// <summary>
 /// Determines whether the cell is walkable from all directions.
 /// </summary>
 /// <param name="unitProps">The unit properties.</param>
 /// <returns><c>true</c> if the cell is walkable, otherwise <c>false</c></returns>
 public abstract bool isWalkableFromAllDirections(IUnitProperties unitProps);
        /// <summary>
        /// Gets the walkable neighbours.
        /// </summary>
        /// <param name="grid">The grid</param>
        /// <param name="c">The cell whose walkable neighbours to return.</param>
        /// <param name="unitProps">The unit properties</param>
        /// <param name="excludeCornerCutting">if set to <c>true</c> otherwise walkable neighbours on the diagonal that would cause a move from it to the current cell to cut a corner are excluded (deemed not walkable).</param>
        /// <returns>The walkable neighbours to the referenced cell.</returns>
        public static IEnumerable<Cell> GetWalkableNeighbours(this IGrid grid, IGridCell c, IUnitProperties unitProps, bool excludeCornerCutting)
        {
            Cell n;

            //Straight move neighbours
            bool uw = grid.TryGetWalkableNeighbour(c, 0, 1, unitProps, out n);
            if (uw)
            {
                yield return n;
            }

            bool dw = grid.TryGetWalkableNeighbour(c, 0, -1, unitProps, out n);
            if (dw)
            {
                yield return n;
            }

            bool rw = grid.TryGetWalkableNeighbour(c, 1, 0, unitProps, out n);
            if (rw)
            {
                yield return n;
            }

            bool lw = grid.TryGetWalkableNeighbour(c, -1, 0, unitProps, out n);
            if (lw)
            {
                yield return n;
            }

            //Diagonal neighbours. First determine if they are unwalkable as a consequence of their straight neighbours
            bool urw, drw, dlw, ulw;
            if (excludeCornerCutting)
            {
                urw = uw && rw;
                drw = dw && rw;
                dlw = dw && lw;
                ulw = uw && lw;
            }
            else
            {
                urw = uw || rw;
                drw = dw || rw;
                dlw = dw || lw;
                ulw = uw || lw;
            }

            urw = urw && grid.TryGetWalkableNeighbour(c, 1, 1, unitProps, out n);
            if (urw)
            {
                yield return n;
            }

            drw = drw && grid.TryGetWalkableNeighbour(c, 1, -1, unitProps, out n);
            if (drw)
            {
                yield return n;
            }

            dlw = dlw && grid.TryGetWalkableNeighbour(c, -1, -1, unitProps, out n);
            if (dlw)
            {
                yield return n;
            }

            ulw = ulw && grid.TryGetWalkableNeighbour(c, -1, 1, unitProps, out n);
            if (ulw)
            {
                yield return n;
            }
        }
Beispiel #38
0
        /// <summary>
        /// Gets the nearest walkable cell on the specified perimeter.
        /// </summary>
        /// <param name="position">The reference position.</param>
        /// <param name="perimeter">The perimeter to check.</param>
        /// <param name="unitProps">The requester units properties.</param>
        /// <param name="adjustPositionToPerimiter">if set to <c>true</c> <paramref name="position" /> will be adjusted to be on the perimeter (if it is not already).</param>
        /// <returns>The nearest walkable perimeter cell</returns>
        public Cell GetNearestWalkablePerimeterCell(Vector3 position, Vector3 perimeter, IUnitProperties unitProps, bool adjustPositionToPerimiter)
        {
            //Adjust the cell to the perimeter and within bounds
            if (adjustPositionToPerimiter)
            {
                if (perimeter.x != 0)
                {
                    position.x = GetPerimeterEdge(perimeter, true);
                    var dzb = this.bottom.edgeMid;
                    var dzf = this.top.edgeMid;
                    if (position.z < dzb)
                    {
                        position.z = dzb;
                    }
                    else if (position.z > dzf)
                    {
                        position.z = dzf;
                    }
                }
                else if (perimeter.z != 0)
                {
                    position.z = GetPerimeterEdge(perimeter, true);
                    var dxl = this.left.edgeMid;
                    var dxr = this.right.edgeMid;
                    if (position.x < dxl)
                    {
                        position.x = dxl;
                    }
                    else if (position.x > dxr)
                    {
                        position.x = dxr;
                    }
                }
            }

            //If this is already the nearest walkable cell return it
            var c = GetCell(position);

            if (c == null)
            {
                return(null);
            }

            if (c.IsWalkableWithClearance(unitProps))
            {
                return(c);
            }

            //Traverse along the perimeter to find the closet walkable cell
            if (perimeter.x != 0)
            {
                return(TraversePerimeterX(c, 1, unitProps));
            }

            return(TraversePerimeterZ(c, 1, unitProps));
        }
Beispiel #39
0
 /// <summary>
 /// Determines whether the cell is walkable from the specified neighbour.
 /// </summary>
 /// <param name="neighbour">The neighbour.</param>
 /// <param name="unitProps">The unit properties.</param>
 /// <returns><c>true</c> if the cell is walkable, otherwise <c>false</c></returns>
 public override bool isWalkableFrom(IGridCell neighbour, IUnitProperties unitProps)
 {
     return(isWalkable(unitProps.attributes));
 }
 bool IGridCell.isWalkableFromAllDirections(IUnitProperties unitProps)
 {
     return isWalkable(unitProps.attributes);
 }
 bool IGridCell.isWalkableFrom(IGridCell neighbour, IUnitProperties unitProps)
 {
     return _parentPortal.IsUsableBy(unitProps.attributes);
 }
        void IPathNode.GetWalkableNeighbours(DynamicArray<IPathNode> neighbours, IUnitProperties unitProps, bool cornerCuttingAllowed, bool preventDiagonalMoves)
        {
            var destinationNodes = _partner._neighbourNodes;
            var nodeCount = destinationNodes.Length;
            var unitAttributes = unitProps.attributes;

            if (_parentPortal.type == PortalType.Connector)
            {
                //This logic depends on the prerequisite that connector portals always a only one cell wide or high, such that the cells covered by the portal represents a simple array.
                //The prerequisite also demands that connector portals are symmetric and placed directly across from one another, the cannot be offset, e.g. cell one on one side must link to cell one on the other side.
                //We then simply find the index of the cell being evaluated (the portal predecessor) and only return maximum 3 cell on the other side, its immediate partner plus each diagonal if they exist.
                //  _______________
                // |___|_N_|_N_|_N_|
                // |___|___|_P_|___|
                //
                //This accomplished two things, First of all we reduce the number of cells being evaluated. Second the resulting path will cross the portal as quickly as possible and not make long diagonal moves across a portal.
                var p = ((IPathNode)this).predecessor;
                var idx = _matrixBounds.IndexOf(p.matrixPosX, p.matrixPosZ);
                if (idx < 0)
                {
                    return;
                }

                var start = Math.Max(idx - 1, 0);
                var end = Math.Min(idx + 2, nodeCount);

                for (int i = start; i < end; i++)
                {
                    if (destinationNodes[i].isWalkable(unitAttributes))
                    {
                        neighbours.Add(destinationNodes[i]);
                    }
                }
            }
            else
            {
                for (int i = 0; i < nodeCount; i++)
                {
                    if (destinationNodes[i].isWalkable(unitAttributes))
                    {
                        neighbours.Add(destinationNodes[i]);
                    }
                }
            }
        }
        /// <summary>
        /// Initializes the Unit Facade.
        /// </summary>
        /// <param name="unitObject">The unit game object.</param>
        public virtual void Initialize(GameObject unitObject)
        {
            _props = unitObject.As<IUnitProperties>(false, true);
            _movable = unitObject.As<IMovable>(false, false);
            _moving = unitObject.As<IMovingObject>(false, true);
            _speeder = unitObject.As<IDefineSpeed>(false, true);
            _pathFinderOptions = unitObject.As<IPathFinderOptions>(false, false) ?? new PathFinderOptions();
            _pathNavOptions = unitObject.As<IPathNavigationOptions>(false, false) ?? new PathNavigationOptions();

            this.isMovable = _movable != null;
            if (!this.isMovable)
            {
                _movable = new MovableDummy(unitObject.name);
            }

            this.gameObject = unitObject;
            this.transform = unitObject.transform;
            this.collider = unitObject.GetComponent<Collider>();

            this.isAlive = true;
            this.hasArrivedAtDestination = true;
        }
 bool IPathNode.TryGetWalkableNeighbour(int dx, int dz, IUnitProperties unitProps, DynamicArray<IPathNode> neighbours)
 {
     return false;
 }
 /// <summary>
 /// Determines whether the cell is walkable from the specified neighbour.
 /// </summary>
 /// <param name="neighbour">The neighbour.</param>
 /// <param name="unitProps">The unit properties.</param>
 /// <returns><c>true</c> if the cell is walkable, otherwise <c>false</c></returns>
 public override bool isWalkableFrom(IGridCell neighbour, IUnitProperties unitProps)
 {
     return isWalkable(unitProps.attributes);
 }
Beispiel #46
0
 /// <summary>
 /// Determines whether the cell is walkable from all directions.
 /// </summary>
 /// <param name="unitProps">The unit properties.</param>
 /// <returns><c>true</c> if the cell is walkable, otherwise <c>false</c></returns>
 public override bool IsWalkableFromAllDirections(IUnitProperties unitProps)
 {
     return(IsWalkableWithClearance(unitProps));
 }