示例#1
0
    public Queue <Location> GetPath(Location start, Location end)
    {
        //Check if locations provided are in bounds. If not, exit.
        if (!gameController.IsInBounds(start) || !gameController.IsInBounds(end))
        {
            Debug.LogError("Tried to get a path with start or end out of bounds: S " + start.x + "," + start.z + " E " + end.x + "," + end.z);
            return(null);
        }
        else
        {
            //Early exit if start and end are identical
            if (gameController.AreLocationsIdentical(start, end))
            {
                path.Enqueue(start);
                return(path);
            }

            //Get map size limits from GameController
            int xSize = gameController.xSize;
            int zSize = gameController.zSize;

            //Create variables used for pathfinding
            Queue <Location> path     = new Queue <Location> ();
            PriorityQueue    frontier = new PriorityQueue();
            bool[,] visited = new bool[xSize, zSize];
            Dictionary <PathNode, PathNode> leadingMap = new Dictionary <PathNode, PathNode> ();
            float[,] scores = new float[xSize, zSize];

            int steps = 0;
            scores [start.x, start.z] = 0;
            Location currentPosition = start;
            PathNode currentNode;

            while (true)
            {
                if (gameController.AreLocationsIdentical(currentPosition, end))
                {
                    //When node being evaluated == end, path has been found
                    break;
                }
                else
                {
                    steps++;
                    //To prevent freeze up, early exit if steps exceeds full tile grid size
                    if (steps > xSize * ySize)
                    {
                        Debug.LogError("Frontier while loop timed out.");
                        return(null);
                    }
                    currentNode = pathGrid.GetPathNode(currentPosition);
                    foreach (PathEdge edge in currentNode.edges)
                    {
                        int x = edge.end.location.x;
                        int z = edge.end.location.z;

                        //If tile has not been visited and is not currently in frontier, score, add to frontier, and add to leadingMap.
                        if (!visited [x, z] && !frontier.Contains(edge.end.location))
                        {
                            float f = ManhattenDistance(end, currentPosition);
                            float g = scores[currentPosition.x, currentPosition.z] + edge.moveCost;
                            scores [x, z] = f + g;
                            frontier.Enqueue(edge.end.location, scores [x, z]);
                            leadingMap.Add(edge.end, currentNode);
                        }
                    }
                    //Set visited for current tile to true and remove from frontier.
                    visited [currentPosition.x, currentPosition.z] = true;
                    currentPosition = frontier.Dequeue();
                }
            }
            //To prevent freeze up, early exit if attempts exceeds full tile grid size
            int attempts = 0;
            //Path is gathered from end to start, so a stack is used before poping all locations in path in to a queue
            Stack <Location> rev = new Stack <Location> ();
            //Start at end
            currentPosition = end;
            //Start at end and use leadingMap to find all locations in best path.
            while (true)
            {
                attempts++;
                if (attempts > xSize * ySize)
                {
                    Debug.LogError("While loop for stack population timed out.");
                    return(null);
                }
                if (gameController.AreLocationsIdentical(currentPosition, start))
                {
                    break;
                }
                rev.Push(currentPosition);
                currentPosition = leadingMap [pathGrid.GetPathNode(currentPosition)].location;
            }
            int pathCount = rev.Count;
            //Reverse order of stack by popping in to queue.
            for (int i = 0; i < pathCount; i++)
            {
                path.Enqueue(rev.Pop());
            }
            return(path);
        }
    }