我是一个编程新手,虽然我遵循了一堆教程,最后我用这段代码来处理一个小游戏的寻路,我正在努力使。
如果适用于小而直的路径,但不适用于复杂的路径(它会冻结和 closedSet.size()
在一个只有54*46的网格中大于70000)。
请注意 wall
是真的取决于碰撞瓷砖的高度,所以从一点来说可能是真的,但从另一点来说可能是假的。这就是问题所在吗?
import java.util.*;
int heuristic(int x,int y,int x_,int y_){
int dstX = abs(x - x_);
int dstY = abs(y - y_);
if(dstX > dstY){
return 14*dstY + 10*(dstX - dstY);
}else{
return 14*dstX + 10*(dstY - dstX);
}
}
boolean wall(int x, int y, int x_, int y_){
Tile tileS = getTile(x, y);
Tile tileCurr = getTile(x_, y_);
if(abs(tileS.altitude - tileCurr.altitude) > 1 || tileS.altitude < 1){
return true;
}else{
return false;
}
}
ArrayList<PVector> findPath(int startx, int starty, int endx, int endy){
Queue<Spot> openSet = new PriorityQueue<Spot>(fComparator);
ArrayList<Spot> closedSet = new ArrayList<Spot>();
Spot start = new Spot(startx, starty);
Spot end = new Spot(endx, endy);
Spot current = start;
openSet.add(start);
while(!openSet.isEmpty()){
current = openSet.poll();
closedSet.add(current);
println(closedSet.size());
if (current.x == end.x && current.y == end.y) {
break;
}
ArrayList<Spot> successors = new ArrayList<Spot>();
for(int i = 0; i < collidingTiles.size(); i++){
JSONObject difference = collidingTiles.getJSONObject(i);
/*JSONArray such as
[{x: -1, y: -1},{x: 0, y: -1},...](not including {x:0, y:0})
*/
int x_ = difference.getInt("x");
int y_ = difference.getInt("y");
int x = x_ + current.x;
int y = y_ + current.y;
if(x >= 0 && x <= map.columns && y >= 0 && y <= map.rows){
Spot s = new Spot(x, y);
successors.add(s);
}
}
for(Spot s: successors){
if (!closedSet.contains(s) && !wall(s.x, s.y, current.x, current.y)) {
int tempG = current.g + heuristic(s.x, s.y, current.x, current.y);
if(tempG < s.g || !openSet.contains(s)){
s.g = tempG;
s.h = heuristic(s.x, s.y, end.x, end.y);
s.f = s.g + s.h;
s.parent = current;
if (!openSet.contains(s)) {
openSet.add(s);
}
}
}
}
successors.clear();
}
ArrayList<PVector> path = new ArrayList<PVector>();
Spot temp = current;
PVector tile = new PVector(temp.x + 0.5, temp.y + 0.5);
path.add(tile);
while (temp.parent != null) {
tile = new PVector(temp.parent.x + 0.5, temp.parent.y + 0.5);
path.add(0, tile);
temp = temp.parent;
}
return path;
}
class Spot{
int x, y;
int f, g, h = 0;
Spot parent;
Spot(int x_, int y_){
x = x_;
y = y_;
}
}
Comparator<Spot> fComparator = new Comparator<Spot>() {
@Override
int compare(Spot s1, Spot s2) {
return s1.f - s2.f;
}
};
如有任何建议或细微改动,我们将不胜感激。
1条答案
按热度按时间7qhs6swi1#
closedSet.size()
在一个只有5446的网格中大于70000你的代码实现了一些逻辑
“如果某个节点已关闭,则不再处理它”,并且
如果节点已在开放集中,请比较g分数
但在这两种情况下都不起作用,因为
Spot
不执行equals
,因此contains
比较引用的相等性,它总是错误的。所以,实施Spot.equals
. 具体来说,只做比较x
以及y
,因为f/g/h/parent
对于为此目的被视为相等的节点,允许是不同的。即使有效,使用
contains
在ArrayList
和一个PriorityQueue
不太适合表演。对于封闭列表,使用HashSet
(当然,也要实施Spot.hashCode
在某种程度上,这只取决于x
以及y
). 对于开放列表,摆脱慢contains
更多的工作。您可以使用的一个技巧是手动维护二进制堆,另外还有HashMap
它Map了一个x,y
与堆中相应节点所在的索引配对。手动维护堆的原因是HashMap
必须在队列中移动节点时更新,并且PriorityQueue
没有这样的功能。从性能的Angular 来看,寻找接班人的工作方式也让我担心,但我看不到细节。
请注意
wall
是真的取决于碰撞瓷砖的高度,所以从一点来说可能是真的,但从另一点来说可能是假的。这就是问题所在吗?那很好,a可以容忍一个点可以从一边到达,但不能从另一边到达。它本机无法考虑的是,到达某个点的方向是否会影响该节点的后续节点,但在这里不会发生这种情况。