我为一个简单的基于2d网格的游戏实现了A *算法。然而,该算法减慢了游戏速度,我最近了解了HPA *,它试图在一定程度上尝试解决这个问题。
我无法找到任何对我有用的编码示例,因为我使用Java进行编码,而且我对从哪里开始调整初始代码感到困惑。
如果有人想看看,我的代码如下。我真的只是想以某种方式调整代码,以便将路径分割成网格,这样我就可以计算出一个可能是5个方形长度的路径,而不是20个方形长度的路径并且减慢游戏速度。
if (shortestPath == null) {
openLocations.add(playerLocation);
// While the goal has not been found yet
while (openLocations.size() != 0 || pathFound != true) {
// get the first node from the open list
Node current = openLocations.get(0);
shortestPath = reconstructPath(current);
// check if current node is the goal node
if (current.getX() == goalLocation.getX()
&& current.getY() == goalLocation.getY()
//|| shortestPath.getWayPointPath().size() > GameInfo.getPathLength() + GameInfo.getPathCounter()
//|| shortestPath.getWayPointPath().size() >= 5
) {
shortestPath = reconstructPath(current);
pathFound = true;
for(Node node: shortestPath.getWayPointPath())
totalClosedLocations.add(node);
// path has been found
break;
}
// move current node to the already searched (closed) list
openLocations.remove(current);
closedLocations.add(current);
// set the current nodes neighbours
current = setNeighbours(current);
// Now it's time to go through all of the current nodes
// neighbours and see if they should be the next step
for (Node neighbor : current.getNeighborList()) {
boolean neighborIsBetter;
// if we have already searched this Node, don't bother and
// continue to the next one
if (closedLocations.contains(neighbor)) {
continue;
}
boolean found = false;
for (Node neighbournode : closedLocations) {
if (neighbournode.getX() == neighbor.getX()
&& neighbournode.getY() == neighbor.getY()) {
found = true;
continue;
}
}
if (found)
continue;
Node movable = new Node(neighbor.getX(), neighbor.getY(),
neighbor.getCategory(), neighbor.getItype(), neighbor.getId());
if (grid[movable.getX()][movable.getY()].size() > 0) {
// check to make sure that the square is not of category
// 4(immovable object) or category 3(enemy)
if ((grid[movable.getX()][movable.getY()].get(0).category == 4 && grid[movable
.getX()][movable.getY()].get(0).itype == 0)
&& grid[movable.getX()][movable.getY()].get(0).obsID != goalLocation.getId()
) {
// You cannot move on this square
neighbor.setMoveable(false);
} else {
// You can move on this square. Set parent location
// as the players current position.
movable.setParent(playerLocation);
}
}
// also just continue if the neighbor is an obstacle
if (neighbor.getMoveable()) {
// calculate how long the path is if we choose this
// neighbor
// as the next step in the path
float neighborDistanceFromStart = (current
.getDistanceFromStart() + getDistanceBetween(
current, neighbor));
// add neighbor to the open list if it is not there
if (!openLocations.contains(neighbor)) {
openLocations.add(neighbor);
neighborIsBetter = true;
// if neighbor is closer to start it could also be
// better
} else if (neighborDistanceFromStart < current
.getDistanceFromStart()) {
neighborIsBetter = true;
} else {
neighborIsBetter = false;
}
// set neighbors parameters if it is better
if (neighborIsBetter) {
neighbor.setParent(current);
neighbor.setDistanceFromStart(neighborDistanceFromStart);
neighbor.setHeuristicDistanceFromGoal(heuristicStar
.getEstimatedDistanceToGoal(
neighbor.getX(), neighbor.getY(),
goalLocation.getX(),
goalLocation.getY()));
}
}
}
}
System.out.println("====================");
}
答案 0 :(得分:1)
让我们说:你实现一个类似爬行的游戏,并拥有一个迷宫,英雄和许多怪物......
在英雄让它移动之后怪物转身,他们可能会移动,朝着英雄(一个*星)移动。我猜你在每一个回合计算每个怪物的路径?!?对?好的,然后出了点问题:
让每个怪物保持自己的道路。如果怪物距离很远,你就不必搜索最短的路径,因为即使你的英雄已经移动,最短的路径也大致相同(只有最后几步不同)。然后,也许如果怪物移动了10圈,你可以重新计算路径。通过这种方式,您可以将计算时间加速10倍 - 考虑到较长的路径比较短的路径需要更长的时间,您可以进行更多的优化如果距离很远,可以每隔5步重新计算一次路径 如果它真的很接近它需要在每个回合重新计算路径,但不要担心......如果它是一个短路径,它不需要花费太多时间来计算!
抱歉 - 没有添加任何代码...好的,让我们继续:这是一个简单的迷宫/地图:
你从上/左开始想要走到尽头(不是A,不是B,你想走到尽头!)......
如果你不计算整个路径,你将永远找不到方法,因为所有其他路径似乎都更短,特别是当你在搜索中使用启发式时!
所以 - 没有办法不进行全路径搜索!
优化: 找到邻居通常是瓶颈:当你创建一个字段时,为每个字段设置邻居!
public class Test {
public Field[][] field;
public void doSomeTest(){
field = new Field[25][25]
MazeGenerator.createMaze(field); //this makes your map = this sets the fields passable or not
for (int dy == 0; dy < 25; dy ++){
for (int dx == 0; dx < 25; dx ++){
createNeighbours(field[dx][dy]);
}
}
}
public void createNeigbours(Field f){
//north
if (isPassable(f.xpos, f.ypos-1) f.neighbours.add(field[xpos][ypos-1]);
//east
if (isPassable(f.xpos+1, f.ypos) f.neighbours.add(field[xpos+1][ypos]);
//south
if (isPassable(f.xpos, f.ypos+1) f.neighbours.add(field[xpos][ypos+1]);
//west
if (isPassable(f.xpos-1, f.ypos) f.neighbours.add(field[xpos-1][ypos]);
}
public boolean isPassable(int xpos, int ypos){
if (xpos <= 0) return false; //outside [maybe you even have a border, then xpos <= 1
if (ypos <= 0) return false; //outside
if (xpos >= Map.width) return false; //outside
if (ypos >= Map.height) return false; //outside
if (field[xpos][ypos].isBlocked) return false; //blocked
return true;
}
}
public class Field{
public final int xpos;
public final int ypos;
public boolean isBlocked = false; // this makes your map
public ArrayList<Field> neigbours = new ArrayList<Field>();
public Field(int xpos, int ypos){
this.xpos = xpos;
this.ypos = ypos;
}
public List<Field> getNeighbours(){
return neigbours ;
}
}
上面的代码仅解释了如何在创建字段时创建邻居...但是如果展开节点(a *),则可以非常快速地获得邻居并且无需计算时间(想想创建对象的频率)在你的代码中)