/// <summary>
        /// Update the path. Executes a single step of path finding until the final path has been found.
        /// </summary>
        /// <returns>The current path in progress, or null if there is no path.</returns>
        public AStarNode[] Update()
        {
            // Loop while there are nodes in the open set, if there are none left and a path hasn't been found then there is no path.
            if (_openSet.Count > 0)
            {
                // Get the node with the lowest score. (F)
                AStarNode current = _openSet.OrderBy(x => x.F).First();

                // Check if the current node is the end, in which case the path has been found.
                if (current.Equals(_end))
                {
                    Finished = true;
                }
                else
                {
                    // Update sets.
                    _openSet.Remove(current);
                    _closedSet.Add(current);

                    // Get neighbors of current.
                    IEnumerable <AStarNode> neighbors = GetNeighbors(current.X, current.Y);

                    foreach (AStarNode neighbor in neighbors)
                    {
                        // Check if the neighbor is done with, in which case we skip.
                        if (_closedSet.Contains(neighbor))
                        {
                            continue;
                        }

                        // Get the tentative distance between the current and the neighbor. Using 1 as distance.
                        int tentativeG = current.G + 1;

                        // Check if the neighbor is being evaluated.
                        if (_openSet.Contains(neighbor))
                        {
                            // Check if we have found a more efficient way to the neighbor node.
                            if (tentativeG < neighbor.G)
                            {
                                neighbor.G = tentativeG;
                            }
                        }
                        else
                        {
                            // Assign the calculated distance and add the node to the open set.
                            neighbor.G = tentativeG;
                            _openSet.Add(neighbor);
                        }

                        neighbor.H        = HeuristicFunction(neighbor, _end);
                        neighbor.CameFrom = current;
                    }
                }

                // Return the path as currently found.
                List <AStarNode> path = new List <AStarNode> {
                    current
                };

                // Trace current's ancestry.
                while (current.CameFrom != null)
                {
                    path.Add(current.CameFrom);
                    current = current.CameFrom;
                }

                // Reverse so the goal isn't at the 0 index but is last node.
                path.Reverse();
                LastFoundPath = path.ToArray();

                return(LastFoundPath);
            }

            Finished = true;
            return(LastFoundPath);
        }
示例#2
0
        /// <summary>
        /// Find a path within the grid.
        /// </summary>
        /// <param name="pathMemory">The memory to fill with the path output.</param>
        /// <param name="start">The location to start pathing from</param>
        /// <param name="end">The location to path to.</param>
        /// <param name="diagonalMovement">Whether diagonal movement is allowed.</param>
        public void FindPath(List <Vector2> pathMemory, Vector2 start, Vector2 end, bool diagonalMovement = false)
        {
            pathMemory.Clear();

            AStarNode startNode = CreateNodeFromIfValid(start);
            AStarNode endNode   = CreateNodeFromIfValid(end);

            if (startNode == null || endNode == null)
            {
                return;                                       // Invalid path
            }
            _openSet.Clear();
            _closedSet.Clear();
            _openSet.Add(startNode);

            // Reset cache.
            foreach ((int _, AStarNode cachedNode) in _cache)
            {
                cachedNode.CameFrom = null;
                cachedNode.G        = 0;
                cachedNode.H        = 0;
            }

            // Loop while there are nodes in the open set, if there are none left and a path hasn't been found then there is no path.
            while (_openSet.Count > 0)
            {
                // Get the node with the lowest score. (F)
                AStarNode current  = null;
                var       closestF = 0;
                foreach (AStarNode node in _openSet)
                {
                    if (current != null && closestF <= node.F)
                    {
                        continue;
                    }
                    current  = node;
                    closestF = node.F;
                }

                if (current == null)
                {
                    break;                  // Should never occur.
                }
                // Check if the current node is the end, in which case the path has been found.
                if (current.Equals(endNode))
                {
                    pathMemory.Add(endNode.Location);

                    // Trace the path backwards.
                    AStarNode trace = endNode;
                    while (trace.CameFrom != null)
                    {
                        AStarNode nextNode = trace.CameFrom;
                        pathMemory.Add(nextNode.Location);
                        trace = nextNode;
                    }

                    // Reverse so the goal isn't at the 0 index but is last node.
                    pathMemory.Reverse();

                    return;
                }

                // Update sets.
                _openSet.Remove(current);
                _closedSet.Add(current);

                // Get neighbors of current.
                GetNeighbors(_neighbors, current, diagonalMovement);

                // Apply heuristics to neighbors.
                for (var i = 0; i < _neighbors.Count; i++)
                {
                    AStarNode node = _neighbors[i];
                    node.H = Heuristic(node, endNode, current);
                }

                _neighbors.Sort();

                for (var i = 0; i < _neighbors.Count; i++)
                {
                    AStarNode neighbor = _neighbors[i];
                    if (neighbor.H < 0)
                    {
                        continue;
                    }

                    // Check if the neighbor is done with, in which case we skip.
                    if (_closedSet.Contains(neighbor))
                    {
                        continue;
                    }

                    // Get the tentative distance between the current and the neighbor. Using 1 as distance.
                    int tentativeG = DistanceBetweenNodes(current, neighbor, endNode);

                    // Check if the neighbor is being evaluated.
                    if (_openSet.Contains(neighbor))
                    {
                        // Check if we have found a more efficient way to the neighbor node.
                        if (tentativeG < neighbor.G)
                        {
                            neighbor.G = tentativeG;
                        }
                        else
                        {
                            continue;
                        }
                    }
                    else
                    {
                        // Assign the calculated distance and add the node to the open set.
                        neighbor.G = tentativeG;
                        _openSet.Add(neighbor);
                    }

                    neighbor.CameFrom = current;
                }
            }
        }