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

您的代码确实实现了一些说的逻辑

  1. “如果节点已关闭,请不要再对其进行处理”,并且
  2. “如果该节点已经在开放集中,则比较G得分”

但是在两种情况下它都不起作用,因为Spot未实现equals,因此contains在比较引用相等性,并且始终为假。因此,实现Spot.equals。具体来说,只比较xy,因为对于为此目的被认为相等的节点,f/g/h/parent可以不同。

即使工作正常,在containsArrayList上使用PriorityQueue也不会对性能产生太大影响。对于封闭列表,使用HashSet很容易(当然,也可以实现Spot.hashCode,以某种方式仅取决于xy)。对于打开的列表,摆脱慢速contains的工作更多。您可以使用的一个技巧是手动维护二进制堆,另外还有一个HashMap,它将x,y对映射到对应节点所在的堆中的索引。手动维护堆的原因是,每当节点在队列中移动时,都必须更新HashMap,而普通的PriorityQueue没有这种功能。

从绩效的角度来看,寻找继任者的方式也令我感到担忧,但我看不到细节。

请注意,wall取决于碰撞图块的高度,因此它是正确的,因此从一个点开始可能是正确的,而从另一个点开始可能是错误的。那是问题吗?

很好,A *可以容忍从一侧到另一侧都无法到达的斑点。它本来不能考虑的是,从某个位置到达某个点的方向是否会影响该节点拥有哪些继任者,但这在这里不会发生。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...