Example #1
0
            public IntVector2[] ToPath()
            {
                List <IntVector2>     asList  = new List <IntVector2>();
                IntVector2AsAStarNode current = this;

                while (current != null)
                {
                    asList.Add(current.coord);
                    current = current.previous;
                }
                asList.Reverse();
                return(asList.ToArray());
            }
Example #2
0
        // --------------------------------------------------------------------------------------------
        /// <summary>
        /// Finds the best path for a unit to a target coordinate using A*
        /// </summary>
        public bool TryGetBestPathForUnit(Unit unit, IntVector2 startCoord, IntVector2 targetCoord, int movementExhausted, out IntVector2[] bestPath)
        {
            bestPath = new IntVector2[0];
            if (movementExhausted >= unit.MoveRange)
            {
                // return empty array if we've already exahusted the list
                return(false);
            }

            // A* implementation for best path
            HashSet <IntVector2AsAStarNode> open   = new HashSet <IntVector2AsAStarNode>();
            HashSet <IntVector2AsAStarNode> closed = new HashSet <IntVector2AsAStarNode>();

            open.Add(new IntVector2AsAStarNode
            {
                coord    = startCoord,
                previous = null,
                f        = 0,
                g        = 0,
                h        = 0,
            });

            int moveRange = unit.MoveRange - movementExhausted;

            bool succeeded = false;

            while (open.Count > 0)
            {
                List <IntVector2AsAStarNode> openAsList = new List <IntVector2AsAStarNode>(open);
                // sort the open list ascending by f value
                openAsList.Sort((IntVector2AsAStarNode a, IntVector2AsAStarNode b) =>
                {
                    return(a.f.CompareTo(b.f));
                });

                // set the current node to the node with the least f
                IntVector2AsAStarNode currentNode = openAsList[0];

                closed.Add(openAsList[0]);
                open.Remove(currentNode);

                if (currentNode.coord.Equals(targetCoord)) // remember to use .Equals() instead of == becuase these are not the same object
                {
                    bestPath  = currentNode.ToPath();
                    succeeded = true;
                    break;
                }

                List <BoardTile> nextBoardTiles = new List <BoardTile>();
                BoardTile        northTile      = GetTile(currentNode.coord.x, currentNode.coord.y + 1);
                if (northTile != null)
                {
                    nextBoardTiles.Add(northTile);
                }
                BoardTile southTile = GetTile(currentNode.coord.x, currentNode.coord.y - 1);
                if (southTile != null)
                {
                    nextBoardTiles.Add(southTile);
                }
                BoardTile eastTile = GetTile(currentNode.coord.x + 1, currentNode.coord.y);
                if (eastTile != null)
                {
                    nextBoardTiles.Add(eastTile);
                }
                BoardTile westTile = GetTile(currentNode.coord.x - 1, currentNode.coord.y);
                if (westTile != null)
                {
                    nextBoardTiles.Add(westTile);
                }
                foreach (BoardTile boardTile in nextBoardTiles)
                {
                    // check if we've already visited this coord
                    bool isClosed = false;
                    foreach (IntVector2AsAStarNode closedNode in closed)
                    {
                        isClosed |= closedNode.coord.Equals(boardTile.Coord);
                    }
                    if (isClosed)
                    {
                        continue;
                    }

                    // create a new node to add to the open list
                    IntVector2AsAStarNode childNode = new IntVector2AsAStarNode();
                    childNode.coord    = boardTile.Coord;
                    childNode.previous = currentNode;
                    childNode.g        = currentNode.g + boardTile.GetMoveCostForUnit(unit);
                    childNode.h        = (boardTile.Coord - targetCoord).ManhattanDistance;
                    childNode.f        = childNode.g + childNode.h;

                    // we can't look at tiles that are beyond a unit's move range or that are occupied by some other unit
                    if (childNode.g > moveRange || (boardTile.Occupant != null && boardTile.Occupant != unit))
                    {
                        continue;
                    }

                    // check if we've visited this coord but now we have a better path to it
                    bool foundBetterPath = false;
                    bool haveVisited     = false;
                    foreach (IntVector2AsAStarNode openNode in open)
                    {
                        if (!openNode.coord.Equals(childNode.coord))
                        {
                            continue;
                        }

                        haveVisited = true;

                        if (openNode.f < childNode.f)
                        {
                            continue;
                        }

                        // we've found a better node!
                        openNode.g        = childNode.g;
                        openNode.h        = childNode.h;
                        openNode.f        = childNode.f;
                        openNode.previous = childNode.previous;
                        foundBetterPath   = true;
                    }

                    if (!haveVisited || !foundBetterPath)
                    {
                        open.Add(childNode);
                    }
                }
            }

            if (bestPath.Length == 0)
            {
                // if we haven't found a best path, then there's no way the unit could move to the target
                // instead, return the best path to the node closest to the target
                List <IntVector2AsAStarNode> toCullFromClosed = new List <IntVector2AsAStarNode>();
                foreach (IntVector2AsAStarNode closedNode in closed)
                {
                    if (closedNode.g != moveRange)
                    {
                        toCullFromClosed.Remove(closedNode);
                    }
                }
                foreach (IntVector2AsAStarNode toRemove in toCullFromClosed)
                {
                    closed.Remove(toRemove);
                }

                List <IntVector2AsAStarNode> closedAsList = new List <IntVector2AsAStarNode>(closed);
                closedAsList.Sort((IntVector2AsAStarNode a, IntVector2AsAStarNode b) =>
                {
                    return(a.f.CompareTo(b.f));
                });

                bestPath = closedAsList[0].ToPath();
            }

            return(succeeded);
        }
Example #3
0
        public static IntVector2[] FindPath(IntVector2 start, IntVector2 goal, Actor actor)
        {
            IntVector2[] bestPath = new IntVector2[0];

            HashSet <IntVector2AsAStarNode> open   = new HashSet <IntVector2AsAStarNode>();
            HashSet <IntVector2AsAStarNode> closed = new HashSet <IntVector2AsAStarNode>();

            open.Add(new IntVector2AsAStarNode
            {
                coord    = start,
                previous = null,
                f        = 0,
                g        = 0,
                h        = 0,
            });

            int counter = 0;

            while (open.Count > 0)
            {
                counter++;

                List <IntVector2AsAStarNode> openAsList = new List <IntVector2AsAStarNode>(open);
                // sort the open list ascending by f value
                openAsList.Sort((IntVector2AsAStarNode a, IntVector2AsAStarNode b) =>
                {
                    return(a.f.CompareTo(b.f));
                });

                if (counter > 9999)
                {
                    Debug.LogError("infinite loop detected");
                    break;
                }

                // set the current node to the node with the least f
                IntVector2AsAStarNode currentNode = openAsList[0];

                closed.Add(openAsList[0]);
                open.Remove(currentNode);

                if (currentNode.coord.Equals(goal)) // remember to use .Equals() instead of == becuase these are not the same object
                {
                    bestPath = currentNode.ToPath();
                    break;
                }

                List <IntVector2> potentialNextCoords = new List <IntVector2>();
                if (actor.CanOccupyPosition((currentNode.coord + IntVector2.Up).ToUnityVector3_XY()))
                {
                    potentialNextCoords.Add(currentNode.coord + IntVector2.Up);
                }
                if (actor.CanOccupyPosition((currentNode.coord + IntVector2.Down).ToUnityVector3_XY()))
                {
                    potentialNextCoords.Add(currentNode.coord + IntVector2.Down);
                }
                if (actor.CanOccupyPosition((currentNode.coord + IntVector2.Left).ToUnityVector3_XY()))
                {
                    potentialNextCoords.Add(currentNode.coord + IntVector2.Left);
                }
                if (actor.CanOccupyPosition((currentNode.coord + IntVector2.Right).ToUnityVector3_XY()))
                {
                    potentialNextCoords.Add(currentNode.coord + IntVector2.Right);
                }

                foreach (IntVector2 coord in potentialNextCoords)
                {
                    IntVector2AsAStarNode childNode = new IntVector2AsAStarNode();
                    childNode.coord    = coord;
                    childNode.previous = currentNode;
                    childNode.g        = currentNode.g + 1;
                    childNode.h        = (coord - goal).ManhattanDistance;
                    childNode.f        = childNode.g + childNode.h;

                    // check if we've visited this coord but now we have a better path to it
                    bool alreadyVisited = false;
                    foreach (IntVector2AsAStarNode openNode in open)
                    {
                        if (!openNode.coord.Equals(coord))
                        {
                            continue;
                        }

                        if (openNode.f <= childNode.f)
                        {
                            continue;
                        }

                        openNode.g        = childNode.g;
                        openNode.h        = childNode.h;
                        openNode.f        = childNode.f;
                        openNode.previous = childNode.previous;
                        alreadyVisited    = true;
                    }

                    foreach (IntVector2AsAStarNode closedNode in closed)
                    {
                        if (closedNode.coord.Equals(coord))
                        {
                            alreadyVisited = true;
                            break;
                        }
                    }

                    if (!alreadyVisited)
                    {
                        open.Add(childNode);
                    }
                }
            }

            if (bestPath.Length == 0)
            {
                // we couldn't find a path, so return the path that gets us closest
                List <IntVector2AsAStarNode> closedAsList = new List <IntVector2AsAStarNode>(closed);
                closedAsList.Sort((IntVector2AsAStarNode a, IntVector2AsAStarNode b) =>
                {
                    return(a.f.CompareTo(b.f));
                });

                bestPath = closedAsList[0].ToPath();
            }

            return(bestPath);
        }