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.
精彩评论