예제 #1
0
        /// <summary>
        /// Attempts to find a <see cref="Path"/> between the start and end points and returns the result on completion.
        /// </summary>
        /// <param name="start">The <see cref="Index"/> into the search space representing the start position</param>
        /// <param name="end">The <see cref="Index"/> into the search space representing the end position</param>
        /// <param name="diagonal">The diagonal mode used when finding paths</param>
        /// <returns>The <see cref="Path"/> that was found or null if the algorithm failed</returns>
        public Path findPathImmediate(Index start, Index end, DiagonalMode diagonal)
        {
            PathRequestStatus status = PathRequestStatus.InvalidIndex;

            // Call through
            return(findPathImmediate(start, end, out status, diagonal));
        }
예제 #2
0
 /// <summary>
 /// Launches the pathfinding algorithm and attempts to find a <see cref="Path"/> between the start and end <see cref="Index"/>.
 /// This overload accepts a <see cref="MonoDelegate"/> as a callback.
 /// </summary>
 /// <param name="start">The start position for the search</param>
 /// <param name="end">The end position for the search</param>
 /// <param name="diagonal">The diagonal mod used when finding paths</param>
 /// <param name="callback">The <see cref="MonoDelegate"/> to invoke on completion</param>
 public void findPath(Index start, Index end, DiagonalMode diagonal, MonoDelegate callback)
 {
     // Call through
     findPath(start, end, diagonal, (Path path, PathRequestStatus status) =>
     {
         // Invoke the mono delegate
         callback.invoke(new MonoDelegateEvent(path, status));
     });
 }
예제 #3
0
        public AsyncPathRequest(SearchGrid grid, Index start, Index end, DiagonalMode diagonal, PathRequestDelegate callback)
        {
            this.grid     = grid;
            this.start    = start;
            this.end      = end;
            this.diagonal = diagonal;
            this.callback = callback;

            // Create a time stamp
            timeStamp = DateTime.UtcNow.Ticks;
        }
예제 #4
0
        /// <summary>
        /// Attempts to search this grid for a path between the start and end points.
        /// </summary>
        /// <param name="start">The <see cref="Index"/> into the search space representing the start position</param>
        /// <param name="end">The <see cref="Index"/> into the search space representing the end position</param>
        /// <param name="diagonal">The diagonal mode used when finding paths</param>
        /// <param name="callback">The <see cref="PathRequestDelegate"/> method to call whe the algorithm has completed</param>
        public void findPath(Index start, Index end, DiagonalMode diagonal, PathRequestDelegate callback)
        {
            // Make sure the grid is ready
            if (verifyReady() == false)
            {
                callback(null, PathRequestStatus.GridNotReady);
                return;
            }

            // Update max path length
            searchGrid.maxPathLength = maxPathLength;

            // Get the threading value
            bool useThreading = allowThreading;

#if UNITY_WEBGL
            // Threading is not allowed on web gl platform
            useThreading = false;
#endif

            // Check if threading is enabled
            if (useThreading == true)
            {
                // Create a request
                AsyncPathRequest request = new AsyncPathRequest(searchGrid, start, end, diagonal, (Path path, PathRequestStatus status) =>
                {
#if UNITY_EDITOR
                    // Pass the path for rendering before it is used by the caller otherwise nodes may be removed from the path
                    PathView.setRenderPath(this, path);
#endif
                    // Invoke callback
                    callback(path, status);
                });

                // Dispatch the request
                ThreadManager.Active.asyncRequest(request);
            }
            else
            {
                PathRequestStatus status;

                // Run the task immediatley
                Path result = findPathImmediate(start, end, out status, diagonal);

#if UNITY_EDITOR
                // Pass the path for rendering before it is used by the caller otherwise nodes may be removed
                PathView.setRenderPath(this, result);
#endif

                // Trigger callback
                callback(result, status);
            }
        }
예제 #5
0
        public AsyncPathRequest(SearchGrid grid, Index start, Index end, DiagonalMode diagonal, BaseTraversal2D traversal2D, PathRequestDelegate callback)
        {
            this.Grid        = grid;
            this.Start       = start;
            this.End         = end;
            this.Diagonal    = diagonal;
            this.Callback    = callback;
            this.Traversal2D = traversal2D;

            // Create a time stamp
            TimeStamp = DateTime.UtcNow.Ticks;
        }
예제 #6
0
        public void FindPath(Index start, Index end, DiagonalMode diagonal, BaseTraversal2D traversal2D, PathRequestDelegate callback)
        {
            if (!IsValid(start) || !IsValid(end))
            {
                return;
            }
            searchGrid.maxPathLength = maxPathLength;
            bool useThreading = allowThreading;

            if (useThreading == true)
            {
                AsyncPathRequest request = new AsyncPathRequest(searchGrid, start, end, diagonal, traversal2D, (Path path, PathRequestStatus status) =>
                {
                    PathView.setRenderPath(this, path);
                    callback(path, status);
                });
                ThreadManager.Active.asyncRequest(request);
            }
            else
            {
                PathRequestStatus status;
                Path result = FindPathImmediate(start, end, out status, diagonal);
                PathView.setRenderPath(this, result);
                callback(result, status);
            }

            Path FindPathImmediate(Index subStart, Index subEnd, out PathRequestStatus subStatus, DiagonalMode subDiagonal)
            {
                searchGrid.maxPathLength = maxPathLength;
                Path path = null;
                PathRequestStatus temp = PathRequestStatus.InvalidIndex;

                searchGrid.FindPath(subStart, subEnd, subDiagonal, traversal2D, (Path result, PathRequestStatus resultStatus) =>
                {
                    temp = resultStatus;
                    if (resultStatus == PathRequestStatus.PathFound)
                    {
                        path = result;
                        PathView.setRenderPath(this, path);
                    }
                });

                subStatus = temp;
                return(path);
            }
        }
예제 #7
0
        //获得节点之间的距离
        public int GetDistance(Index start, Index end, DiagonalMode diagonal)
        {
            int count  = 1;
            int deltaX = Mathf.Abs(start.X - end.X);
            int deltaY = Mathf.Abs(start.Y - end.Y);

            if (diagonal == DiagonalMode.NoDiagonal)
            {
                count += (deltaX + deltaY);
            }
            else
            {
                int smallest = deltaX;
                if (deltaY < smallest)
                {
                    smallest = deltaY;
                }
                int diagonalSteps = Mathf.Abs(deltaX - deltaY);
                count += (diagonalSteps + smallest);
            }
            return(count);
        }
예제 #8
0
        /// <summary>
        /// Calculates the minumum number of node steps required tbetween the start and end nodes.
        /// This will only ever provide the best possible case and will not take into account non-walkable nodes or obstructions.
        /// </summary>
        /// <param name="start">The start index</param>
        /// <param name="end">The end index</param>
        /// <param name="diagonal">The diagonal mode to use</param>
        /// <returns>The number of nodes required to move between the start and end indexes</returns>
        public static int findNodeDistance(Index start, Index end, DiagonalMode diagonal)
        {
            // Include start node
            int count = 1;

            // Change in x
            int deltaX = Mathf.Abs(start.X - end.X);

            // Change in y
            int deltaY = Mathf.Abs(start.Y - end.Y);

            if (diagonal == DiagonalMode.NoDiagonal)
            {
                // Add the x and y offset
                count += (deltaX + deltaY);
            }
            else
            {
                // Get the smallest delta
                int smallest = deltaX;

                // Check if y is smaller
                if (deltaY < smallest)
                {
                    smallest = deltaY;
                }

                // Get the number of diagonal steps
                int diagonalSteps = Mathf.Abs(deltaX - deltaY);

                // Add the diagonal offset
                count += (diagonalSteps + smallest);
            }

            return(count);
        }
예제 #9
0
 /// <summary>
 /// Attempts to find a <see cref="Path"/> between the start and end points and returns the result on completion.
 /// </summary>
 /// <param name="start">The <see cref="Index"/> into the search space representing the start position</param>
 /// <param name="end">The <see cref="Index"/> into the search space representing the end position</param>
 /// <param name="diagonal">The diagonal mode used when finding paths</param>
 /// <returns>The <see cref="Path"/> that was found or null if the algorithm failed</returns>
 public abstract Path findPathImmediate(Index start, Index end, DiagonalMode diagonal);
예제 #10
0
 /// <summary>
 /// Attempts to find a <see cref="Path"/> between the start and end points and returns the result on completion.
 /// </summary>
 /// <param name="start">The <see cref="Index"/> into the search space representing the start position</param>
 /// <param name="end">The <see cref="Index"/> into the search space representing the end position</param>
 /// <param name="status">The <see cref="PathRequestStatus"/> describing the state of the result</param>
 /// <param name="diagonal">The diagonal mode used when finding paths</param>
 /// <returns>The <see cref="Path"/> that was found or null if the algorithm failed</returns>
 public abstract Path findPathImmediate(Index start, Index end, out PathRequestStatus status, DiagonalMode diagonal);
예제 #11
0
        private int constructAdjacentNodes(PathNode center, PathNode[] nodes, DiagonalMode diagonal)
        {
            // Get the center node
            Index node = center.Index;

            // Clear the shared array so that old data is not used
            for (int i = 0; i < nodes.Length; i++)
            {
                nodes[i] = null;
            }

            int index = 0;

            // Check for per node diagonal status
            if (center.DiagonalMode != PathNodeDiagonalMode.UseGlobal)
            {
                switch (center.DiagonalMode)
                {
                case PathNodeDiagonalMode.Diagonal: diagonal = DiagonalMode.Diagonal; break;

                case PathNodeDiagonalMode.NoDiagonal: diagonal = DiagonalMode.NoDiagonal; break;

                case PathNodeDiagonalMode.DiagonalNoCutting: diagonal = DiagonalMode.DiagonalNoCutting; break;
                }
            }

            // Check if diagonal movements can be used
            if (diagonal != DiagonalMode.NoDiagonal)
            {
                // Cache the adjacent nodes
                PathNode left   = safeGetNode(node.X - 1, node.Y);
                PathNode right  = safeGetNode(node.X + 1, node.Y);
                PathNode top    = safeGetNode(node.X, node.Y + 1);
                PathNode bottom = safeGetNode(node.X, node.Y - 1);

                bool canAdd = true;

                // Bottom left
                {
                    canAdd = true;

                    if (diagonal == DiagonalMode.DiagonalNoCutting)
                    {
                        // Left cutting
                        if (left != null && left.IsWalkable == false)
                        {
                            canAdd = false;
                        }

                        // Bottom cutting
                        if (bottom != null && bottom.IsWalkable == false)
                        {
                            canAdd = false;
                        }
                    }

                    // Make sure the diagonal movement is allowed
                    if (canAdd == true)
                    {
                        nodes[index++] = safeGetNode(node.X - 1, node.Y - 1);
                    }
                } // End bottom left

                // Top right
                {
                    canAdd = true;

                    if (diagonal == DiagonalMode.DiagonalNoCutting)
                    {
                        // Right cutting
                        if (right != null && right.IsWalkable == false)
                        {
                            canAdd = false;
                        }

                        // Top cutting
                        if (top != null && top.IsWalkable == false)
                        {
                            canAdd = false;
                        }
                    }

                    // Make sure the diagonal movement is allowed
                    if (canAdd == true)
                    {
                        nodes[index++] = safeGetNode(node.X + 1, node.Y + 1);
                    }
                } // End top right

                // Top Left
                {
                    canAdd = true;

                    if (diagonal == DiagonalMode.DiagonalNoCutting)
                    {
                        // Left cutting
                        if (left != null && left.IsWalkable == false)
                        {
                            canAdd = false;
                        }

                        // Top cutting
                        if (top != null && top.IsWalkable == false)
                        {
                            canAdd = false;
                        }
                    }

                    // Make sure the diagonal movement is allowed
                    if (canAdd == true)
                    {
                        nodes[index++] = safeGetNode(node.X - 1, node.Y + 1);
                    }
                } // End top left

                // Bottom right
                {
                    canAdd = true;

                    if (diagonal == DiagonalMode.DiagonalNoCutting)
                    {
                        // Right cutting
                        if (right != null && right.IsWalkable == false)
                        {
                            canAdd = false;
                        }

                        // Bottom cutting
                        if (bottom != null && bottom.IsWalkable == false)
                        {
                            canAdd = false;
                        }
                    }

                    // Make sure the diagonal movement is allowed
                    if (canAdd == true)
                    {
                        nodes[index++] = safeGetNode(node.X + 1, node.Y - 1);
                    }
                } // End bottom right
            }

            // Bottom
            nodes[index++] = safeGetNode(node.X, node.Y - 1);

            // Left
            nodes[index++] = safeGetNode(node.X - 1, node.Y);

            // Right
            nodes[index++] = safeGetNode(node.X + 1, node.Y);

            // Top
            nodes[index++] = safeGetNode(node.X, node.Y + 1);

            return(index + 1);
        }
예제 #12
0
 /// <summary>
 /// Attempts to search this grid for a path between the start and end points.
 /// </summary>
 /// <param name="start">The <see cref="Index"/> into the search space representing the start position</param>
 /// <param name="end">The <see cref="Index"/> into the search space representing the end position</param>
 /// <param name="diagonal">The diagonal mode used when finding paths</param>
 /// <param name="callback">The <see cref="PathRequestDelegate"/> method to call whe the algorithm has completed</param>
 public abstract void findPath(Index start, Index end, DiagonalMode diagonal, PathRequestDelegate callback);
예제 #13
0
        /// <summary>
        /// Launches the pathfinding algorithm and attempts to find a <see cref="Path"/> between the start and end <see cref="Index"/>.
        /// </summary>
        /// <param name="start">The start position for the search</param>
        /// <param name="end">The end position for the search</param>
        /// <param name="diagonal">The diagonal mod used when finding paths</param>
        /// <param name="callback">The <see cref="PathRequestDelegate"/> method to call on completion</param>
        public void findPath(Index start, Index end, DiagonalMode diagonal, PathRequestDelegate callback)
        {
            // Already at the destination
            if (start.Equals(end))
            {
                callback(null, PathRequestStatus.SameStartEnd);
                return;
            }

            // Get the nodes
            PathNode startNode = nodeGrid[start.X, start.Y];
            PathNode endNode   = nodeGrid[end.X, end.Y];

            // Clear all previous data
            clearSearchData();

            // Starting scores
            startNode.g = 0;
            startNode.h = provider.heuristic(startNode, endNode);
            startNode.f = startNode.h;

            // Add the start node
            openMap.add(startNode);
            runtimeMap.add(startNode);
            orderedMap.push(startNode);

            while (openMap.Count > 0)
            {
                // Get the front value
                PathNode value = orderedMap.pop();

                if (value == endNode)
                {
                    // We have found the path
                    Path result = constructPath(searchGrid[endNode.Index.X, endNode.Index.Y]);

                    // Last node
                    if (maxPathLength == -1 || result.NodeCount < maxPathLength)
                    {
                        result.push(endNode, endNode.Index);
                    }

                    // Trigger the delegate with success
                    callback(result, PathRequestStatus.PathFound);

                    // Exit the method
                    return;
                }
                else
                {
                    openMap.remove(value);
                    closedMap.add(value);

                    // Fill our array with surrounding nodes
                    constructAdjacentNodes(value, adjacentNodes, diagonal);

                    // Process each neighbor
                    foreach (PathNode adjacent in adjacentNodes)
                    {
                        bool isBetter = false;

                        // Skip null nodes
                        if (adjacent == null)
                        {
                            continue;
                        }

                        // Make sure the node is walkable
                        if (adjacent.IsWalkable == false)
                        {
                            continue;
                        }

                        // Check for occupied
                        if (CheckIndexOccupied != null)
                        {
                            if (CheckIndexOccupied(adjacent.Index) == true)
                            {
                                continue;
                            }
                        }

                        // Make sure it has not already been excluded
                        if (closedMap.contains(adjacent) == true)
                        {
                            continue;
                        }

                        // Check for custom exclusion descisions
                        if (validateConnection(value, adjacent) == false)
                        {
                            continue;
                        }

                        // Calculate the score for the node
                        float score = runtimeMap[value].g + provider.adjacentDistance(value, adjacent) + (adjacent.Weighting * weightingInfluence);
                        bool  added = false;

                        // Make sure it can be added to the open map
                        if (openMap.contains(adjacent) == false)
                        {
                            openMap.add(adjacent);
                            isBetter = true;
                            added    = true;
                        }
                        else if (score < runtimeMap[adjacent].g)
                        {
                            // The score is better
                            isBetter = true;
                        }
                        else
                        {
                            // The score is not better
                            isBetter = false;
                        }

                        // CHeck if a better score has been found
                        if (isBetter == true)
                        {
                            // Update the search grid
                            searchGrid[adjacent.Index.X, adjacent.Index.Y] = value;

                            // Add the adjacent node
                            if (runtimeMap.contains(adjacent) == false)
                            {
                                runtimeMap.add(adjacent);
                            }

                            // Update the score values for the node
                            runtimeMap[adjacent].g = score;
                            runtimeMap[adjacent].h = provider.heuristic(adjacent, endNode);
                            runtimeMap[adjacent].f = runtimeMap[adjacent].g + runtimeMap[adjacent].h;

                            // CHeck if we added to the open map
                            if (added == true)
                            {
                                // Push the adjacent node to the set
                                orderedMap.push(adjacent);
                            }
                            else
                            {
                                // Refresh the set
                                orderedMap.refresh(adjacent);
                            }
                        }
                    }
                }
            } // End while

            // Failure
            callback(null, PathRequestStatus.PathNotFound);
        }
예제 #14
0
        /// <summary>
        /// Attempts to find a <see cref="Path"/> between the start and end points and returns the result on completion.
        /// </summary>
        /// <param name="start">The <see cref="Index"/> into the search space representing the start position</param>
        /// <param name="end">The <see cref="Index"/> into the search space representing the end position</param>
        /// <param name="status">The <see cref="PathRequestStatus"/> describing the state of the result</param>
        /// <param name="diagonal">The diagonal mode used when finding a path</param>
        /// <returns>The <see cref="Path"/> that was found or null if the algorithm failed</returns>
        public Path findPathImmediate(Index start, Index end, out PathRequestStatus status, DiagonalMode diagonal)
        {
            // Make sure the grid is ready
            if (verifyReady() == false)
            {
                status = PathRequestStatus.GridNotReady;
                return(null);
            }

            // Update max path length
            searchGrid.maxPathLength = maxPathLength;

            // Store a temp path
            Path path = null;
            PathRequestStatus temp = PathRequestStatus.InvalidIndex;

            // Find a path
            searchGrid.findPath(start, end, diagonal, (Path result, PathRequestStatus resultStatus) =>
            {
                // Store the status
                temp = resultStatus;

                // Make sure the path was found
                if (resultStatus == PathRequestStatus.PathFound)
                {
                    path = result;

#if UNITY_EDITOR
                    PathView.setRenderPath(this, path);
#endif
                }
            });

            status = temp;
            return(path);
        }
예제 #15
0
 /// <summary>
 /// Attempts to search this grid for a path between the start and end points.
 /// </summary>
 /// <param name="start">The <see cref="Index"/> into the search space representing the start position</param>
 /// <param name="end">The <see cref="Index"/> into the search space representing the end position</param>
 /// <param name="diagonal">The diagonal mode used when finding paths</param>
 /// <param name="callback">The <see cref="PathRequestDelegate"/> method to call whe the algorithm has completed</param>
 public abstract void findPath(Index start, Index end, DiagonalMode diagonal, Action <Path, PathRequestStatus> callback);
예제 #16
0
        private IPathNode[] getSurroundingNodes(int x, int y)
        {
            // Create the array
            IPathNode[] nodes = new IPathNode[(visualizeGrid.diagonalMovement == DiagonalMode.NoDiagonal) ? 4 : 8];

            // Center node
            IPathNode center = safeGetNode(x, y);

            // Left node
            nodes[0] = safeGetNode(x - 1, y);

            // Right node
            nodes[1] = safeGetNode(x + 1, y);

            // Up node
            nodes[2] = safeGetNode(x, y + 1);

            // Down node
            nodes[3] = safeGetNode(x, y - 1);


            DiagonalMode diagonalMode = visualizeGrid.diagonalMovement;

            if (center.DiagonalMode != PathNodeDiagonalMode.UseGlobal)
            {
                switch (center.DiagonalMode)
                {
                case PathNodeDiagonalMode.Diagonal: diagonalMode = DiagonalMode.Diagonal; break;

                case PathNodeDiagonalMode.NoDiagonal: diagonalMode = DiagonalMode.NoDiagonal; break;

                case PathNodeDiagonalMode.DiagonalNoCutting: diagonalMode = DiagonalMode.DiagonalNoCutting; break;
                }
            }


            // Diagonal neighbors
            if (diagonalMode != DiagonalMode.NoDiagonal)
            {
                IPathNode left   = safeGetNode(x - 1, y);
                IPathNode right  = safeGetNode(x + 1, y);
                IPathNode top    = safeGetNode(x, y + 1);
                IPathNode bottom = safeGetNode(x, y - 1);

                bool canAdd = true;

                // Top left
                if (diagonalMode == DiagonalMode.DiagonalNoCutting)
                {
                    if (left != null && left.IsWalkable == false)
                    {
                        canAdd = false;
                    }

                    if (top != null && top.IsWalkable == false)
                    {
                        canAdd = false;
                    }
                }
                if (canAdd == true)
                {
                    nodes[4] = safeGetNode(x - 1, y + 1);
                }

                // Top right
                canAdd = true;
                if (diagonalMode == DiagonalMode.DiagonalNoCutting)
                {
                    if (right != null && right.IsWalkable == false)
                    {
                        canAdd = false;
                    }

                    if (top != null && top.IsWalkable == false)
                    {
                        canAdd = false;
                    }
                }
                if (canAdd == true)
                {
                    nodes[5] = safeGetNode(x + 1, y + 1);
                }

                // Bottom left
                canAdd = true;
                if (diagonalMode == DiagonalMode.DiagonalNoCutting)
                {
                    if (left != null && left.IsWalkable == false)
                    {
                        canAdd = false;
                    }

                    if (bottom != null && bottom.IsWalkable == false)
                    {
                        canAdd = false;
                    }
                }
                if (canAdd == true)
                {
                    nodes[6] = safeGetNode(x - 1, y - 1);
                }

                // Bottom right
                canAdd = true;
                if (diagonalMode == DiagonalMode.DiagonalNoCutting)
                {
                    if (right != null && right.IsWalkable == false)
                    {
                        canAdd = false;
                    }

                    if (bottom != null && bottom.IsWalkable == false)
                    {
                        canAdd = false;
                    }
                }
                if (canAdd == true)
                {
                    nodes[7] = safeGetNode(x + 1, y - 1);
                }
            }
            return(nodes);
        }
예제 #17
0
        public void FindPath(Index start, Index end, DiagonalMode diagonal, BaseTraversal2D traversal, PathRequestDelegate callback)
        {
            // Already at the destination
            if (start.Equals(end))
            {
                callback(null, PathRequestStatus.SameStartEnd);
                return;
            }

            // Get the nodes
            PathNode startNode = nodeGrid[start.X, start.Y];
            PathNode endNode   = nodeGrid[end.X, end.Y];

            // Clear all previous data
            ClearSearchData();

            // Starting scores
            startNode.g = 0;
            startNode.h = provider.heuristic(startNode, endNode);
            startNode.f = startNode.h;

            // Add the start node
            openMap.add(startNode);
            runtimeMap.add(startNode);
            orderedMap.Push(startNode);

            while (openMap.Count > 0)
            {
                // Get the front value
                PathNode value = orderedMap.Pop();

                if (value == endNode)
                {
                    // We have found the path
                    Path result = ConstructPath(searchGrid[endNode.Index.X, endNode.Index.Y]);

                    // Last node
                    if (maxPathLength == -1 || result.NodeCount < maxPathLength)
                    {
                        result.Push(endNode);
                    }

                    // Trigger the delegate with success
                    callback(result, PathRequestStatus.PathFound);

                    // Exit the method
                    return;
                }
                else
                {
                    openMap.remove(value);
                    closedMap.add(value);

                    // Fill our array with surrounding nodes
                    ConstructAdjacentNodes(value, adjacentNodes, diagonal);

                    // Process each neighbor
                    foreach (PathNode pathNode in adjacentNodes)
                    {
                        bool isBetter = false;

                        // Skip null nodes
                        if (pathNode == null)
                        {
                            continue;
                        }

                        // Make sure the node is walkable
                        if (pathNode.IsWalkable == false)
                        {
                            continue;
                        }

                        // Check for occupied
                        if (IsIndexObstacle != null)
                        {
                            if (IsIndexObstacle(pathNode.Index) == true)
                            {
                                continue;
                            }
                        }

                        //检查Traversal
                        if (traversal != null)
                        {
                            if (traversal.Filter(pathNode.TileNode) == false)
                            {
                                continue;
                            }
                        }

                        // Make sure it has not already been excluded
                        if (closedMap.contains(pathNode) == true)
                        {
                            continue;
                        }

                        // Check for custom exclusion descisions
                        if (ValidateConnection(value, pathNode) == false)
                        {
                            continue;
                        }

                        // Calculate the score for the node
                        float score = runtimeMap[value].g + provider.adjacentDistance(value, pathNode) + (pathNode.Weighting * weightingInfluence);
                        bool  added = false;

                        // Make sure it can be added to the open map
                        if (openMap.contains(pathNode) == false)
                        {
                            openMap.add(pathNode);
                            isBetter = true;
                            added    = true;
                        }
                        else if (score < runtimeMap[pathNode].g)
                        {
                            // The score is better
                            isBetter = true;
                        }
                        else
                        {
                            // The score is not better
                            isBetter = false;
                        }

                        // CHeck if a better score has been found
                        if (isBetter == true)
                        {
                            // Update the search grid
                            searchGrid[pathNode.Index.X, pathNode.Index.Y] = value;

                            // Add the adjacent node
                            if (runtimeMap.contains(pathNode) == false)
                            {
                                runtimeMap.add(pathNode);
                            }

                            // Update the score values for the node
                            runtimeMap[pathNode].g = score;
                            runtimeMap[pathNode].h = provider.heuristic(pathNode, endNode);
                            runtimeMap[pathNode].f = runtimeMap[pathNode].g + runtimeMap[pathNode].h;

                            // CHeck if we added to the open map
                            if (added == true)
                            {
                                // Push the adjacent node to the set
                                orderedMap.Push(pathNode);
                            }
                            else
                            {
                                // Refresh the set
                                orderedMap.Refresh(pathNode);
                            }
                        }
                    }
                }
            } // End while

            // Failure
            callback(null, PathRequestStatus.PathNotFound);

            void ClearSearchData()
            {
                // Reset all data
                closedMap.clear();
                openMap.clear();
                runtimeMap.clear();
                orderedMap.Clear();

                for (int x = 0; x < width; x++)
                {
                    for (int y = 0; y < height; y++)
                    {
                        searchGrid[x, y] = null;
                    }
                }
            }

            //构造路径
            Path ConstructPath(PathNode current)
            {
                // Create the path
                Path path = new Path(this);

                // Call the dee construct method
                DeepConstructPath(current, path);

                return(path);
            }

            void DeepConstructPath(PathNode inputCurrent, Path output)
            {
                // Get the node from the search grid
                PathNode node = searchGrid[inputCurrent.Index.X, inputCurrent.Index.Y];

                // Make sure we have a valid node
                if (node != null)
                {
                    // Call through reccursive
                    DeepConstructPath(node, output);
                }

                // Limit the maximumnumber of nodes in the path
                if (maxPathLength != -1)
                {
                    if (output.NodeCount > maxPathLength)
                    {
                        return;
                    }
                }

                // Push the node to the path
                output.Push(inputCurrent);
            }
        }