如何解决A *寻路问题ProcessingJava
我对编程还是很陌生的,尽管经过一堆教程之后,我最终还是得到了这段代码来处理我要制作的一款小游戏的寻路。
如果适用于小而直的路径,但不适用于复杂的路线(它会冻结并且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_){
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,...](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,current.y);
if(tempG < s.g || !openSet.contains(s)){
s.g = tempG;
s.h = heuristic(s.x,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;
}
};
任何建议或较小的更改也将受到赞赏。
解决方法
closedSet.size()
在仅54 * 46的网格中变得大于70000
您的代码确实实现了一些说的逻辑
- “如果节点已关闭,请不要再对其进行处理”,并且
- “如果该节点已经在开放集中,则比较G得分”
但是在两种情况下它都不起作用,因为Spot
未实现equals
,因此contains
在比较引用相等性,并且始终为假。因此,实现Spot.equals
。具体来说,只比较x
和y
,因为对于为此目的被认为相等的节点,f/g/h/parent
可以不同。
即使工作正常,在contains
和ArrayList
上使用PriorityQueue
也不会对性能产生太大影响。对于封闭列表,使用HashSet
很容易(当然,也可以实现Spot.hashCode
,以某种方式仅取决于x
和y
)。对于打开的列表,摆脱慢速contains
的工作更多。您可以使用的一个技巧是手动维护二进制堆,另外还有一个HashMap
,它将x,y
对映射到对应节点所在的堆中的索引。手动维护堆的原因是,每当节点在队列中移动时,都必须更新HashMap
,而普通的PriorityQueue
没有这种功能。
从绩效的角度来看,寻找继任者的方式也令我感到担忧,但我看不到细节。
请注意,
wall
取决于碰撞图块的高度,因此它是正确的,因此从一个点开始可能是正确的,而从另一个点开始可能是错误的。那是问题吗?
很好,A *可以容忍从一侧到另一侧都无法到达的斑点。它本来不能考虑的是,从某个位置到达某个点的方向是否会影响该节点拥有哪些继任者,但这在这里不会发生。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。