a*寻路问题处理(java)

64jmpszr  于 2021-07-12  发布在  Java
关注(0)|答案(1)|浏览(288)

我是一个编程新手,虽然我遵循了一堆教程,最后我用这段代码来处理一个小游戏的寻路,我正在努力使。
如果适用于小而直的路径,但不适用于复杂的路径(它会冻结和 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;
  }
};

如有任何建议或细微改动,我们将不胜感激。

7qhs6swi

7qhs6swi1#

closedSet.size() 在一个只有5446的网格中大于70000
你的代码实现了一些逻辑
“如果某个节点已关闭,则不再处理它”,并且
如果节点已在开放集中,请比较g分数
但在这两种情况下都不起作用,因为 Spot 不执行 equals ,因此 contains 比较引用的相等性,它总是错误的。所以,实施 Spot.equals . 具体来说,只做比较 x 以及 y ,因为 f/g/h/parent 对于为此目的被视为相等的节点,允许是不同的。
即使有效,使用 containsArrayList 和一个 PriorityQueue 不太适合表演。对于封闭列表,使用 HashSet (当然,也要实施 Spot.hashCode 在某种程度上,这只取决于 x 以及 y ). 对于开放列表,摆脱慢 contains 更多的工作。您可以使用的一个技巧是手动维护二进制堆,另外还有 HashMap 它Map了一个 x,y 与堆中相应节点所在的索引配对。手动维护堆的原因是 HashMap 必须在队列中移动节点时更新,并且 PriorityQueue 没有这样的功能。
从性能的Angular 来看,寻找接班人的工作方式也让我担心,但我看不到细节。
请注意 wall 是真的取决于碰撞瓷砖的高度,所以从一点来说可能是真的,但从另一点来说可能是假的。这就是问题所在吗?
那很好,a
可以容忍一个点可以从一边到达,但不能从另一边到达。它本机无法考虑的是,到达某个点的方向是否会影响该节点的后续节点,但在这里不会发生这种情况。

相关问题