示例#1
0
        /// <summary>
        /// Returns a UnitRange containing up to 3 lists of points: which squares the unit can move to,
        /// which squares the unit can attack, and which squares the unit can utility-ize.
        /// </summary>
        /// <param name="unit">The unit we are querying for</param>
        /// <param name="blockedSpaces">spaces the unit is not allowed to occupy (e.g. due to ally unit already being there)</param>
        /// <returns></returns>
        /// //TODO: Add this to a different class
        public UnitRange GetPathsForUnit(UnitEntity unit, Position unitPosition, List <Position> blockedSpaces)
        {
            UnitRange retRange = new UnitRange();

            List <PathNode> unvisited  = new List <PathNode>();
            List <PathNode> accessible = new List <PathNode>();

            //Step 1
            //make a node for each tile within raw movement range.
            unvisited = GetUnvisitedTiles(unit.Move, unitPosition, unit.MoveCosts, unit.TeamID);

            //Step 2
            //run Dijkstra's algorithm
            accessible = DijkstraPathfinder.CalculatePathDistance(unvisited, unitPosition.xPos, unitPosition.yPos);

            //Accessible now has only the squares which the unit can actually reach.
            //break them back into Tuples for the UnitRange
            HashSet <Position> validPositions = new HashSet <Position>();

            foreach (PathNode node in accessible.Where(node => node.distance <= unit.Move))
            {
                validPositions.Add(new Position(node.pos.xPos, node.pos.yPos));
            }
            //blocked positions can be pathed through, but not ended in.
            //you can end in your own space though
            validPositions.RemoveWhere(s => blockedSpaces.Contains(s) && !(s.Equals(unitPosition)));

            //Item ranges
            HashSet <Position> attackRanges        = unit.AllAttackRanges();
            HashSet <Position> utilityRanges       = unit.AllUtilityRanges();
            HashSet <Position> attackablePositions = new HashSet <Position>();
            HashSet <Position> utilityPositions    = new HashSet <Position>();

            foreach (Position pos in validPositions)
            {
                foreach (Position offset in attackRanges)
                {
                    Position targetTile = new Position(pos.xPos + offset.xPos, pos.yPos + offset.yPos);
                    if (targetTile.xPos >= 0 && targetTile.xPos < Width && targetTile.yPos >= 0 && targetTile.yPos < Height)
                    {
                        attackablePositions.Add(targetTile);
                    }
                }

                foreach (Position offset in utilityRanges)
                {
                    Position targetTile = new Position(pos.xPos + offset.xPos, pos.yPos + offset.yPos);
                    if (targetTile.xPos >= 0 && targetTile.xPos < Width && targetTile.yPos >= 0 && targetTile.yPos < Height)
                    {
                        utilityPositions.Add(targetTile);
                    }
                }
            }

            retRange.moveRange    = validPositions;
            retRange.attackRange  = attackablePositions;
            retRange.utilityRange = utilityPositions;

            return(retRange);
        }
示例#2
0
        /// <summary>
        /// Finds a path to the given space, using current path as a starting point
        /// </summary>
        /// <param name="selectedUnit"></param>
        /// <param name="targ"></param>
        /// <param name="currentPath"></param>
        /// <returns></returns>
        internal List <Position> FindPath(UnitEntity unit, Position targ, List <Position> currentPath)
        {
            List <PathNode> unvisited  = new List <PathNode>();
            List <PathNode> accessible = new List <PathNode>();

            //Part 1 - make sure the target is not already in the path
            if (currentPath.Contains(targ))
            {
                int i = currentPath.IndexOf(targ);
                return(currentPath.GetRange(0, i + 1));
            }

            //Part 2 - find path from existing position
            if (unit.Move - currentPath.Count > 0)             //fail fast for finding path from scratch
            {
                Position previousPosition = currentPath.Last();

                //Step 1
                //make a node for each tile within modified movement range.
                unvisited = GetUnvisitedTiles(unit.Move - currentPath.Count, previousPosition, unit.MoveCosts, unit.TeamID);

                //Step 2
                //run Dijkstra's algorithm
                accessible = DijkstraPathfinder.CalculatePathDistance(unvisited, previousPosition.xPos, previousPosition.yPos);

                if (accessible.Find(s => s.pos.Equals(targ)) != null)
                {
                    //we can reach the new square from our existing path. return the new path as an append to the existing path
                    List <Position> appendList = new List <Position>();

                    PathNode markerNode = accessible.Find(s => s.pos.Equals(targ));

                    while (markerNode != null && !markerNode.pos.Equals(previousPosition))
                    {
                        appendList.Add(markerNode.pos);
                        markerNode = markerNode.previousNode;
                    }

                    appendList.Reverse();
                    currentPath.AddRange(appendList);
                    return(currentPath);
                }
                //else - we need to find the path from scratch
            }

            //Part 3 - calculate path from scratch

            //Step 1
            //make a node for each tile within modified movement range.
            unvisited = GetUnvisitedTiles(unit.Move, currentPath[0], unit.MoveCosts, unit.TeamID);

            //Step 2
            //run Dijkstra's algorithm
            accessible = DijkstraPathfinder.CalculatePathDistance(unvisited, currentPath[0].xPos, currentPath[0].yPos);
            if (accessible.Find(s => s.pos.Equals(targ)) != null)
            {
                //we can reach the new square from our existing path. return the new path as an append to the existing path
                List <Position> retList = new List <Position>();

                PathNode markerNode = accessible.Find(s => s.pos.Equals(targ));

                while (markerNode != null)
                {
                    retList.Add(markerNode.pos);
                    markerNode = markerNode.previousNode;
                }

                retList.Reverse();

                return(retList);
            }
            else
            {
                throw new PathFindingException("Could not find path to a navigable tile");
            }
        }