我从这个例子中XNA Pathfinder example采用了A *算法,这样它就可以为移动目标绘制路径。
我已经改变了方法,以便它每半秒计算一个新路径,以便它可以计算到目标的路径,从列表中清除先前的点并向其添加新点。
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;
}
我遇到的问题是角色在路径的起点上来回移动。正如有人正确地指出的那样......
“它认为前进”是一个好主意,所以就这样。然后,当它检查半秒后,它认为“回”是一个好主意,然后回去“。有人建议我应该给当前路径上存在的点重量小于路径上的新点。我试过实现这个无济于事,对此的任何帮助都会很棒。
此方法包含Astar算法
/// <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;
}
这是一种计算节点启发式值的修改方法,如果它在当前路径上,它现在给它一个权重。
/// <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;
}
这是将节点添加到打开或关闭列表的方法。
/// <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;
}
}
如何阻止“来回”问题?
答案 0 :(得分:1)
重新评估达到目标的最佳方式,同时尝试一种可能的方法来达到目标是一个非常常见的问题:这通常会导致行为不一致,例如您所描述的行为不一致。
解决这个问题的一个好方法是让当前的方式优先于具有相同分数的任何其他方式。
另一个有效的解决方案是使用阈值。这是一个例子:
目前的方式评估为100.正如我们所说的A *,让我们说这是目前考虑的路径到目标的距离。
重新评估时,我们发现另一条评估为95的路径。
但是我们使用10%的阈值来阻止角色的思维改变,除非最佳解决方案比当前的解决方案好10%
因此,我们不会在这个例子中改变角色的思想,因为我们只会获得5%。但是我们会改变我们的想法,将其评估为90或更低的路径。
我倾向于选择阈值解决方案来优先考虑当前解决方案。我觉得它更优雅自然。它也更强大,因为它允许您为行为添加一些真实性(每次只有计算机总是选择数学上最好的方法)。唯一的困难是找到好的门槛,这需要一些时间进行测试。