开发者

Pathfinder issues

I've taken the A* Algorithm from this example XNA Pathfinder example so that it will be able to plot a path for a moving goal.

I've changed the method so that it calculates a new path every half a second so that it can cal开发者_运维百科culate a path to the goal, clears out the previous points from the list and adds the new points to it.

            timer += gameTime.ElapsedGameTime;

            if (timer.Seconds >= 0.5)
            {
                timer = TimeSpan.Zero;
                pathFinder.NewPath(position);
            }

            if (pathFinder.SearchStatus == SearchStatus.PathFound)
            {
                waypoints.Clear();
                foreach (Point point in pathFinder.FinalPath())
                {
                    Waypoints.Enqueue(level.MapToWorld(point, true));
                }
                moving = true;
            }

The issue Im having is that the character keeps moving back and forth at the starting point of the path.As someone has correctly pointed out...

"it thinks going "forth" is a good idea so it goes that way. Then, when it checks a half second later, it thinks "back" is a good idea and goes back".

Someone suggested that I should give the points that exist on the current path a smaller weight than the new points on the path. I've tried implementing this to no avail, any help with this would be great.

This method contains the Astar algorithm

/// <summary>
/// This Method looks at everything in the open list and chooses the next 
/// path to visit based on which search type is currently selected.
/// </summary>
/// <param name="result">The node to be visited</param>
/// <returns>Whether or not SelectNodeToVisit found a node to examine
/// </returns>
private bool SelectNodeToVisit(out SearchNode result)
{
    result = new SearchNode();
    bool success = false;
    float smallestCost = float.PositiveInfinity;
    float currentCost = 0f;

    if (openList.Count > 0)
    {
        foreach (SearchNode node in openList)
        {
            currentCost = Heuristic(node);
            // The heuristic value gives us our optimistic estimate 
            // for the path length, while any path with the same 
            // heuristic value is equally ‘good’ in this case we’re 
            // favoring paths that have the same heuristic value 
            // but are longer.
            if (currentCost <= smallestCost)
            {
                if (currentCost < smallestCost)
                {
                    success = true;
                    result = node;
                    smallestCost = currentCost;
                }
                else if (currentCost == smallestCost &&
                    node.DistanceTraveled < result.DistanceTraveled)
                {
                    success = true;
                    result = node;
                    smallestCost = currentCost;
                }
            }
        }
    }
    return success;
}

This is the modified method which calculates the heuristic value of a node, which now gives it a weight based off if it is on the current path or not.

     /// <summary>
    /// Generates an optimistic estimate of the total path length to the goal 
    /// from the given position.
    /// </summary>
    /// <param name="location">Location to examine</param>
    /// <returns>Path length estimate</returns>
    private float Heuristic(SearchNode location)
    {
        int Nodecost = 10;

        foreach (Point point in Currentpath)
        {
            if (location.Position == point)

                Nodecost = 7;
                break;
        }
        return location.DistanceTraveled + location.DistanceToGoal + Nodecost;
    }

This is the method which adds nodes to either the open or closed list.

 /// <summary>
/// This method find the next path node to visit, puts that node on the 
/// closed list and adds any nodes adjacent to the visited node to the 
/// open list.
/// </summary>
private void DoSearchStep(TileMap tileMap)
{
    SearchNode newOpenListNode;

    bool foundNewNode = SelectNodeToVisit(out newOpenListNode);
    if (foundNewNode)
    {
        Point currentPos = newOpenListNode.Position;
        foreach (Point point in level.OpenMapTiles(currentPos, tileMap))
        {
            SearchNode mapTile = new SearchNode(point,
                StepDistanceToEnd(point),
                newOpenListNode.DistanceTraveled + 1);

            if (!InList(openList, point) &&
                !InList(closedList, point))
            {
                openList.Add(mapTile);
                paths[point] = newOpenListNode.Position;
            }
        }
        if (currentPos == endPlace)
        {
            searchStatus = SearchStatus.PathFound;
        }
        openList.Remove(newOpenListNode);
        closedList.Add(newOpenListNode);
    }
    else
    {
        searchStatus = SearchStatus.NoPath;
    }
}

How to stop the "back-and forth" problem ?


To re-evaluate the best way to reach an objective while trying one of the possible ways to reach it is a quite common problem: this often leads to behavioural inconsistencies such as the one you describe.

  • A good way to solve that is to give the current way an higher priority to any other way that have the same score.

  • Another working solution is to use a threshold. Here is an example:

    • the current way is evaluated to 100. As we are speaking about an A*, let's say this is the distance to the goal by the currently considered path.

    • when reevaluating, we find another path evaluated to 95.

    • but we use a 10% threshold that prevent the character's mind from changing unless the best solution is 10% better than the current one

    So we don't change our character's mind in this example, as we would only gain 5%. But we would have changed our mind for a path that would have been evaluated to 90 or less.

I tend to prefer the threshold solution to the priority-to-the-current-way solution. I find it more elegant and natural. It is also more powerful as it allows you to add some realism to the behaviour (only a computer always chose the mathematically best approach every time). The only difficulty is to find the good threshold, this requires some time in testing.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜