예제 #1
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;
                }
            }
        }
예제 #2
0
 protected virtual int DistanceBetweenNodes(AStarNode current, AStarNode other, AStarNode end)
 {
     return(current.G + 1);
 }
예제 #3
0
        protected void GetNeighbors(List <AStarNode> memory, AStarNode current, bool diagonal)
        {
            memory.Clear();

            int x = current.X;
            int y = current.Y;

            bool hasLeft   = x > 0 && x <= _pathingGrid.Width - 1;
            bool hasRight  = x >= 0 && x < _pathingGrid.Width - 1;
            bool hasTop    = y > 0 && y <= _pathingGrid.Height - 1;
            bool hasBottom = y >= 0 && y < _pathingGrid.Height - 1;

            // Check for left.
            if (hasLeft)
            {
                AStarNode left = CreateNodeFromIfValid(x - 1, y);
                if (left != null)
                {
                    _neighbors.Add(left);
                }

                // Check top left diagonal.
                if (diagonal && hasTop)
                {
                    AStarNode topLeft = CreateNodeFromIfValid(x - 1, y - 1);
                    if (topLeft != null)
                    {
                        _neighbors.Add(topLeft);
                    }
                }
            }

            // Check for right.
            if (hasRight)
            {
                AStarNode right = CreateNodeFromIfValid(x + 1, y);
                if (right != null)
                {
                    _neighbors.Add(right);
                }

                // Check top right diagonal.
                if (diagonal && hasTop)
                {
                    AStarNode topRight = CreateNodeFromIfValid(x + 1, y - 1);
                    if (topRight != null)
                    {
                        _neighbors.Add(topRight);
                    }
                }
            }

            // Check for top.
            if (hasTop)
            {
                AStarNode top = CreateNodeFromIfValid(x, y - 1);
                if (top != null)
                {
                    _neighbors.Add(top);
                }
            }

            // Check for bottom.
            // ReSharper disable once InvertIf
            if (hasBottom)
            {
                AStarNode bottom = CreateNodeFromIfValid(x, y + 1);
                if (bottom != null)
                {
                    _neighbors.Add(bottom);
                }

                // Check bottom left diagonal.
                if (diagonal && hasLeft)
                {
                    AStarNode bottomLeft = CreateNodeFromIfValid(x - 1, y + 1);
                    if (bottomLeft != null)
                    {
                        _neighbors.Add(bottomLeft);
                    }
                }

                // Check bottom right diagonal.
                // ReSharper disable once InvertIf
                if (diagonal && hasRight)
                {
                    AStarNode bottomRight = CreateNodeFromIfValid(x + 1, y + 1);
                    if (bottomRight != null)
                    {
                        _neighbors.Add(bottomRight);
                    }
                }
            }
        }
예제 #4
0
 /// <summary>
 /// The function to be used for determining the heuristic value of each node. The first argument is the subject, and the
 /// second is the goal node.
 /// By default this is the euclidean distance.
 /// </summary>
 protected virtual int Heuristic(AStarNode current, AStarNode end, AStarNode currentFrom)
 {
     return((int)Vector2.Distance(current.Location, end.Location));
 }