- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
编辑:
为了帮助看这个问题的人成为回答者,我会注意到这个问题似乎是在跳转的对角线情况下。当递归运行时,该方法中的什么会导致速度变慢?
编辑结束。
在我开发的 XNA 游戏中,我使用 A* + JPS 算法在每一帧的统一方形网格上导航。我了解了 JPS here和 here .但是,当我运行游戏时,帧率下降。帧率太低,以至于无法玩游戏。删除对跳跃点搜索“跳跃”的调用,并改为使用常规 A*,解决了足够大的正方形尺寸的问题。根据这篇文章,JPS 应该比常规 A* 更有效。速度变慢的原因似乎是在“对角线情况”中对 Jump 的两次调用(Jump 方法的第 15-29 行)。
很明显,我的实现一定有问题/效率低下。但它是什么?
代码:
Jump方法是JPS递归跳转功能的实现。
public Vector2? Jump(Vector2 current, Vector2 direction, Vector2 start, Vector2 end)
{
// Position of new node we are going to consider:
Vector2 next = current + direction * SquareSize;
// If it's blocked we can't jump here
if (IsBlocked(next))
return null;
// If the node is the goal return it
if (next.X == end.X && next.Y == end.Y)
return next;
// Diagonal Case
if (direction.X != 0 && direction.Y != 0)
{
Vector2 horizontalBehind = current - new Vector2(direction.X * SquareSize, 0);
Vector2 verticalBehind = current - new Vector2(0, direction.Y * SquareSize);
if (IsBlocked(horizontalBehind) || IsBlocked(verticalBehind))
{
return current;
}
// Check in horizontal and vertical directions for forced neighbors
// This is a special case for diagonal direction
if (Jump(next, new Vector2(direction.X, 0), start, end) != null || Jump(next, new Vector2(0, direction.Y), start, end) != null)
{
return current;
}
}
else
{
// Horizontal case
if (direction.X != 0)
{
Vector2 topBehind = current - new Vector2(direction.X * SquareSize, SquareSize);
Vector2 above = current - new Vector2(0, SquareSize);
Vector2 bottomBehind = current + new Vector2(-direction.X * SquareSize, SquareSize);
Vector2 below = current + new Vector2(0, SquareSize);
if (IsBlocked(topBehind) || IsBlocked(above) || IsBlocked(bottomBehind) || IsBlocked(below))
{
return current;
}
}
else
{
Vector2 leftBehind = current - new Vector2(SquareSize, direction.Y * SquareSize);
Vector2 left = current - new Vector2(SquareSize, 0);
Vector2 rightBehind = current + new Vector2(-SquareSize, direction.Y * SquareSize);
Vector2 right = current - new Vector2(SquareSize, 0);
if (IsBlocked(leftBehind) || IsBlocked(left) || IsBlocked(rightBehind) || IsBlocked(right))
{
return current;
}
}
}
// If forced neighbor was not found try next jump point
return Jump(next, direction, start, end);
}
#endregion
}
Navigate是实现A*的方法,从'start'参数到'end'参数。
PriorityQueue 是基于this article 的通用实现.它的入队和出队方法具有 O(log2(n)) 复杂度。
public Vector2? Navigate(Vector2 start, Vector2 end)
{
PriorityQueue<float, Vector2> openSet = new PriorityQueue<float, Vector2>();
List<Vector2> closedSet = new List<Vector2>(10);
Dictionary<Vector2, Vector2> cameFrom = new Dictionary<Vector2, Vector2>(10);
Dictionary<Vector2, float> gScores = new Dictionary<Vector2, float>(10);
gScores[start] = 0;
openSet.Enqueue(H(start, end), start);
while (openSet.Count != 0)
{
Vector2 current = openSet.Dequeue().Value;
if (WorldMap.InSquare(current) == WorldMap.InSquare(end))
return ReconstructPath(cameFrom, current, start);
List<Vector2> neighbours = WorldMap.GetNeighbours(current, start, end);
closedSet.Add(current);
foreach(Vector2 neighbour in neighbours)
{
if (closedSet.Contains(neighbour))
continue;
float tenativeGScore = gScores[current] + Vector2.Distance(current, neighbour);
if(!gScores.ContainsKey(neighbour) || gScores[neighbour] > tenativeGScore)//Discover a new node || Find a better path to a node
{
cameFrom[neighbour] = current;
gScores[neighbour] = tenativeGScore;
float fScore = tenativeGScore + H(neighbour, end);//Calculate F.
openSet.Enqueue(fScore, neighbour);
}
}
}
return null;
}
GetNeighbours 是一种返回节点“向量”的邻居的方法。A* 版本:
public List<Vector2> GetNeighbours(Vector2 point, Vector2 start, Vector2 end)
{
Vector2[] directions = new Vector2[8];
List<Vector2> neighbours = new List<Vector2>(8);
directions[0] = Vector2.UnitX;//right
directions[1] = -Vector2.UnitX;//left
directions[2] = Vector2.UnitY;//down
directions[3] = -Vector2.UnitY;//up
directions[4] = Vector2.UnitX + Vector2.UnitY;//down right
directions[5] = -Vector2.UnitX + Vector2.UnitY;//down left
directions[6] = Vector2.UnitX - Vector2.UnitY;//up right
directions[7] = -Vector2.UnitX - Vector2.UnitY;//up left
foreach(Vector2 direction in directions)
{
Vector2 neighbour = point + direction * SquareSize;
if (!IsBlocked(neighbour))
neighbours.Add(neighbour);
}
return neighbours;
}
跳点搜索版本:
public List<Vector2> GetNeighbours(Vector2 point, Vector2 start, Vector2 end)
{
Vector2[] directions = new Vector2[8];
List<Vector2> neighbours = new List<Vector2>(8);
directions[0] = Vector2.UnitX;//right
directions[1] = -Vector2.UnitX;//left
directions[2] = Vector2.UnitY;//down
directions[3] = -Vector2.UnitY;//up
directions[4] = Vector2.UnitX + Vector2.UnitY;//down right
directions[5] = -Vector2.UnitX + Vector2.UnitY;//down left
directions[6] = Vector2.UnitX - Vector2.UnitY;//up right
directions[7] = -Vector2.UnitX - Vector2.UnitY;//up left
foreach(Vector2 direction in directions)
{
//The only difference between this GetNeighbours and the other one
//is that this one calls Jump here.
Vector2? jp = Jump(point + direction * SquareSize, direction, start, end);
if (jp != null)
neighbours.Add((Vector2)jp);
}
return neighbours;
}
InSqaure 是一种返回表示 Vector2 所在正方形的 Vector2 的方法。它的复杂度为 O(1)。
IsBlocked 是一种方法,用于检查 Vector2 是否在 map 内部,以及它是否位于被阻挡的正方形中(“被阻挡”表示正方形中有障碍物)。它具有 O(log2(n)) 复杂度。
附加信息:
如果需要更多信息,我会很乐意提供,
提前致谢!
最佳答案
在我的游戏中,我使用 A* 进行立体寻路。这需要更多的处理时间,但实现的构建方式几乎不可见。
public void FixedUpdate()
{
if (calculating && openSet.Count > 0 && calculatingStep < 240)
PathfindingStep(navDestination, navAccurancyFactor);
else calculating = false;//...
}
FixedUpdate 每秒调用 50 次。
private void PathfindingBegin(Vector3 destination)
{
navAccurancyFactor = (1 + (Vector3.Distance(walkerTransform.position, destination) / (accurancy * 5)));
navDestination = destination;
calculatingStep = 0;
calculating = true;
closedSet = new List<PathNode>();
openSet = new List<PathNode>();
Vector3 startPos;
if (path.Count > 0)
startPos = path.Last();
else
startPos = walkerTransform.position;
// Шаг 2.
PathNode startNode = new PathNode()
{
Position = startPos,
CameFrom = null,
PathLengthFromStart = 0,
HeuristicEstimatePathLength = GetHeuristicPathLength(walkerTransform.position, destination)
};
openSet.Add(startNode);
}
调用 PathfindingBegin 开始,接下来每帧调用 PathfindingStep onse 来构建路径。
private void PathfindingStep(Vector3 destination, float accuracyFactor)
{
calculatingStep++;
PathNode currentNode;
// Шаг 3.
currentNode = openSet.OrderBy(node => node.EstimateFullPathLength).First();
// Шаг 4.
if (Vector3.Distance(currentNode.Position, destination) <= accurancy * accuracyFactor)
{
PathfindingComplete(CollapsePath(GetPathForNode(currentNode)).ToArray());
return;
}
// Шаг 5.
openSet.Remove(currentNode);
closedSet.Add(currentNode);
// Шаг 6.
List<PathNode> neighbours = GetNeighbours(currentNode, destination, accuracyFactor);
foreach (PathNode neighbourNode in neighbours)
{
// Шаг 7.
if (closedSet.Count(node => node.Position == neighbourNode.Position) > 0)
continue;
PathNode openNode = openSet.Find(node => node.Position == neighbourNode.Position);
// Шаг 8.
if (openNode == null)
openSet.Add(neighbourNode);
else if (openNode.PathLengthFromStart > neighbourNode.PathLengthFromStart)
{
// Шаг 9.
openNode.CameFrom = currentNode;
openNode.PathLengthFromStart = neighbourNode.PathLengthFromStart;
}
}
}
最后调用 PathfindingComplete 应用路径。或者如果目的地不可用。
private void PathfindingComplete(Vector3[] pathPoints)
{
if (pathPoints != null)
{
status = DriverStatus.Navigating;
foreach (Vector3 x in pathPoints)
{
//Debug.Log(x);
path.Enqueue(x);
}
BuildPathArrows();
}
calculating = false;
}
附言我们可以在 https://github.com/DaniilChikish/SpaceComander 找到所有项目
关于c# - 跳点搜索比 XNA 中的常规 A* 慢的 A*?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37949315/
当给定两个 bool 参数时,^ 运算符执行异或,例如 true ^ true == false true ^ false == true false ^ true == true false ^ f
我需要下载一个文件(例如: https://www.betaseries.com/srt/391160 )所以我在网上找到了不同的方法: def download(String remoteUrl,
可以说,我们正在计算考试成绩的平均值: 起始考试成绩:75、80、92、64、83、99、79 平均值= 572/7 = 81.714 ... 现在给出81.714,如果您不知道初始测试分数,是否可以
我和一个 friend 正在争论线程池中的线程数应该是处理器计数+ 1还是仅仅是处理器计数。 我之所以选择处理器数量,是因为每个处理器可以分配偶数个线程,而他选择处理器数量+ 1是因为他认为这将帮助他
我已经养成了尽可能使用闭包来代替常规方法的习惯,即使我不需要访问自由变量。所以,我将使用这个: def addNumbers = { 左、右 -> 左 + 右 } ..而不是这个: def addNu
我对 Groovy 非常陌生,我正在尝试《Groovy in Action》书中的这个示例。我有这个 fibonacci.groovy 程序,当尝试使用 java 命令运行该程序时,我收到 NoCla
我有 3 个 TextView 。我需要将它们的权重设置为 Light、Regular 和 Condensed。有人可以帮助我了解如何在 Android 中实现这一点吗? 最佳答案 在 TextVie
如果用户启动我的应用程序并最初选择不允许位置服务,我想通过 UIAlertMessage 提示用户重新考虑(“更新”和“不,谢谢。”)。 “不,谢谢。”这将是一个简单的取消,我希望“更新”将它们直接链
如何在 groovy 中显示一个值是真还是假?我使用 Eclipse 作为我的 IDE。 assert 4 * ( 2 + 3 ) - 6 == 14 //integers only 而且我也
我的问题与“多处理器编程的艺术”一书有关。第4章介绍安全/常规/原子寄存器及其实现。 以下是安全多读取器单写 boolean 寄存器的以下实现,该寄存器基于安全单读取器单写 boolean 寄存器,被
使用下面的代码来保存 float 的值 domainInstance.standardScore = params["standardScore"] as float 在这种情况下,我的输入是 17.
使用下面的代码来保存 float 的值 domainInstance.standardScore = params["standardScore"] as float 在这种情况下,我的输入是 17.
在iOS的about部分中,它具有有关设备的大量信息。 我和我可以访问此信息吗? 我想快速获取settings -> General -> About的数据。在iOS中获得相同的价格是否可行? 最佳答
我正在开发Windows服务,它将承载两件事: WCF服务 用于定期作业执行的“常规” Windows服务(使用Quartz.net) 因此,基本上,一个应用程序(可执行)承载这两种服务类型。 这两种
在mysql中,我有一个名为users的表,其中包含系统中的用户列表... id | name | surname | active ____________________________ 1
所以我在 Debian 服务器上设置了一个 MySQL 数据库,并且它在 phpMyAdmin 客户端上运行良好。我目前正在开发一个项目,编写一个 Java 服务器,该服务器能够通过 JDBC 连接使
已关闭。这个问题是 not reproducible or was caused by typos 。目前不接受答案。 这个问题是由拼写错误或无法再重现的问题引起的。虽然类似的问题可能是 on-top
前两天考试了,其中一道题是把@前面的字母换成新的名字 所以在试卷中我们有 array = "toto@yahoo.com","mimi@yahoo.com".soso@yahoo.com"所以我们应该
大家好 如果字符串语法如下,我如何从字符串中获取数字(正数): t_def_type_id_2 t_def_type_id_22 t_def_type_id_334 所以,在第一个字符串中我想得到 1
我正在寻找不会在内核中阻塞的文件描述符类型。我知道我可以使用 fstat(2) 但 fstat 还会给我各种元数据信息(访问时间等),这些信息可能会阻塞任意时间(特别是在网络文件系统上)。 编辑:我正
我是一名优秀的程序员,十分优秀!