A*路径查找问题处理(Java)

A*路径查找问题处理(Java),java,processing,a-star,Java,Processing,A Star,我对编程还很陌生,不过在完成了一系列教程之后,我最终得到了这段代码,用于处理我正在尝试制作的一个小游戏的寻路 If适用于小而直的路径,但不适用于复杂的路径(它会冻结并且closedSet.size()在一个只有54*46的网格中变得大于70000) 请注意,wall是真的,这取决于碰撞瓷砖的高度,因此从一点来说可能是真的,但从另一点来说可能是假的。这就是问题所在吗 import java.util.*; int heuristic(int x,int y,int x_,int y_){ i

我对编程还很陌生,不过在完成了一系列教程之后,我最终得到了这段代码,用于处理我正在尝试制作的一个小游戏的寻路

If适用于小而直的路径,但不适用于复杂的路径(它会冻结并且
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;
  }
};
import java.util.*;
整数启发式(整数x,整数y,整数x,整数y){
int-dstX=abs(x-x_);
int-dstY=abs(y-y_);
如果(dstX>dstY){
返回14*dstY+10*(dstX-dstY);
}否则{
返回14*dstX+10*(dstY-dstX);
}
}
布尔墙(intx,inty,intx,inty){
瓷砖=getTile(x,y);
tileCurr=getTile(x,y);
如果(绝对高度(平铺高度-平铺高度)>1 | |平铺高度<1){
返回true;
}否则{
返回false;
}
}
ArrayList findPath(int-startx、int-starty、int-endx、int-endy){
Queue openSet=new PriorityQueue(fComparator);
ArrayList closedSet=新的ArrayList();
点启动=新点(startx、starty);
点端点=新点(端点,端点);
点电流=启动;
添加(开始);
而(!openSet.isEmpty()){
current=openSet.poll();
closedSet.add(当前);
println(closedSet.size());
if(current.x==end.x&¤t.y==end.y){
打破
}
ArrayList继承者=新的ArrayList();
对于(int i=0;i=0&&x=0&&y
closedSet.size()
在仅为54*46的网格中大于70000

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

  • “如果某个节点已关闭,则不再处理该节点”,以及
  • 如果节点已在开放集中,请比较G分数
  • 但在这两种情况下,它都不起作用,因为
    Spot
    没有实现
    equals
    ,因此
    contains
    正在比较引用等式,它将始终为false。因此,实现
    Spot.equals
    。具体地说,让它只比较
    x
    y
    ,因为
    f/g/h/parent
    对于为此目的被视为相等的节点,允许不同

    即使有效,在
    数组列表上使用
    contains
    PriorityQueue
    对性能也不是很好。对于封闭列表,使用
    HashSet
    很容易(当然,也可以实现
    Spot.hashCode
    ,在某种程度上只取决于
    x
    y
    )。对于开放列表,摆脱慢速
    包含
    需要更多的工作。可以使用的一个技巧是手动维护二进制堆,另外还有一个
    HashMap
    ,它将
    x,y
    对映射到相应节点所在堆中的索引。手动维护堆的原因是
    具有每当节点在队列中移动时,必须更新hMap
    ,而正常的
    PriorityQueue
    不具备此类功能

    从性能的角度来看,寻找继任者作品的方式也让我感到担忧,但我看不到细节

    请注意,
    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;
      }
    };
    

    这很好,A*可以容忍一个点可以从一侧到达,但不能从另一侧到达。它不能本机考虑的是,如果一个点到达的方向会影响该节点的后续节点,但在这里不会发生这种情况。

    我看到很多整数,我应该看到地图坐标,这些坐标是真的还是真的它们是你根据模型计算距离的另一种方法?根据经验,你应该使用float或类似的格式来存储地图坐标,特别是如果你要根据这些来计算东西的话。你的帖子写得很好,但由于大部分都是调试,你会提高获得大量帮助的机会。当然,这不是一个简单的问题永远都有可能,但至少能够运行它会让更多处于更好位置的人提供帮助。非常感谢@harold