I am having a game with a lot of GameBodyObject
s and some of them are moving, some of them are not. When I calculate A* for the moving objects it gets really slow when all the objects are present. If there is just a Player
then the A* is fast.
Here is my Game
update loop:
public Game update(float dt) {
if(isStarted()) {
duration += dt;
ArrayList<GameBodyObject> objects = getAllGameBodyObjects();
if(!astar.isInitialized()) {
astar.initialize(GameLogicConstants.ASTAR_GRID_SIZE);
astar.getGrid().recalculateObstacles(objects);
}
for (Player p : players) {
p.update(dt, objects, astar);
}
for (BootCamp bootCamp : bootCamps) {
bootCamp.update(dt, objects, astar);
}
for(WaveManager wave : waves) {
wave.update(dt, objects, astar);
}
//checkCollisions();
astar.getGrid().recalculateObstacles(objects);
gameCycles++;
}
return this;
}
The recalculateObstacles
function is really fast, and I don't think it's the bottleneck.
For every GameBodyObject
, I have a method moveTowardsPoint
which gets an A* every tick in the game and perform the A* algorithm task and moves along the path found.
Here is my A* implementation:
public Path process(GameBodyObject me, Point target, ArrayList<GameBodyObject> others) throws Exception {
if(grid == null) {
throw new Exception("You have to initialize AStar first.");
}
grid.unsetObstacleForObject(me);
Spot start = grid.getSpotAtPosition(me.getPosition().getX(), me.getPosition().getY());
Spot end = grid.getSpotAtPosition(target.getX(), target.getY());
end = grid.moveSpotSoThatItDoesntCollide(end, me.getRadius());
List<Spot> openSet = new ArrayList<Spot>(grid.getMaxSize());
List<Spot> closedSet = new ArrayList<>();
List<Spot> path = new ArrayList<>();
openSet.add(start);
boolean hasHit = false;
while(openSet.size() > 0) {
int winner = 0;
for(int i = 1; i < openSet.size(); i++) {
if(openSet.get(i).getF() < openSet.get(winner).getF()) {
winner = i;
}
}
Spot current = openSet.get(winner);
if(current == null) {
return new Path(hasHit, false, new ArrayList<>());
}
if(current.equals(end)) {
// We are done, reconstruct the path...
Spot temp = current;
path.add(temp);
while(temp.getPrevious() != null) {
Spot previous = temp.getPrevious();
temp.setPrevious(null);
path.add(previous);
temp = previous;
}
grid.resetObstacles();
Collections.reverse(path);
return new Path(hasHit, true, path);
}
openSet.remove(current);
closedSet.add(current);
List<Spot> neighbors = current.getNeighbors();
for(Spot neighbor : neighbors) {
if(!closedSet.contains(neighbor)) {
if(!grid.isCollidingWithObstacle(neighbor, me.getRadius())) {
double tempG = current.getG() + 1;
if (openSet.contains(neighbor)) {
if (tempG < neighbor.getG()) {
neighbor.setG(tempG);
}
} else {
neighbor.setG(tempG);
openSet.add(neighbor);
}
neighbor.setH(heuristic(neighbor, end));
neighbor.setF(neighbor.getG() + neighbor.getH());
neighbor.setPrevious(current);
} else {
hasHit = true;
}
}
}
}
grid.resetObstacles();
return new Path(hasHit, false, new ArrayList<>());
}
public double heuristic(Spot spot, Spot end) {
double dx = spot.getAbsoluteX() - end.getAbsoluteX();
double dy = spot.getAbsoluteY() - end.getAbsoluteY();
return Math.sqrt(dx * dx + dy * dy);
//return Math.abs(dx) + Math.abs(dy);
}
For more context, the Grid.java: https://gist.github.com/Durisvk/4de2d7e2e0a229a6cfd4bb9cc7203996
and lastly the GameBodyObject.java: https://gist.github.com/Durisvk/209f25c781af4aa53a4011f522b5c2d9
EDIT
Super, Thank you guys, I didn't await that kind of discussion. I thought to myself that my work 4 days were wasted and I won't use the A* at the end. But I hope I will optimize it as much as I can.
There were some questions about the game I am making. It's a Dota 2 for browsers, but the problem is on server when I am calculating this A* so there is no delay in drawing on client.