Added spatial indexing of tile targets, many bugfixes

This commit is contained in:
Anuken
2018-06-20 22:56:53 -04:00
parent 45da578756
commit ca30f49481
11 changed files with 105 additions and 52 deletions
@@ -1,10 +1,12 @@
package io.anuke.mindustry.ai;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Bits;
import com.badlogic.gdx.utils.IntMap;
import com.badlogic.gdx.utils.ObjectMap;
import com.badlogic.gdx.utils.ObjectSet;
import io.anuke.mindustry.content.Items;
import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.game.EventType.TileChangeEvent;
import io.anuke.mindustry.game.EventType.WorldLoadEvent;
import io.anuke.mindustry.game.Team;
@@ -13,11 +15,12 @@ import io.anuke.mindustry.type.Item;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.meta.BlockFlag;
import io.anuke.ucore.core.Events;
import io.anuke.ucore.entities.trait.Entity;
import io.anuke.ucore.function.Predicate;
import io.anuke.ucore.util.EnumSet;
import io.anuke.ucore.util.Mathf;
import static io.anuke.mindustry.Vars.state;
import static io.anuke.mindustry.Vars.world;
import static io.anuke.mindustry.Vars.*;
//TODO consider using quadtrees for finding specific types of blocks within an area
//TODO maybe use Arrays instead of ObjectSets?
@@ -77,6 +80,12 @@ public class BlockIndexer {
}
}
for (int x = 0; x < quadWidth(); x++) {
for (int y = 0; y < quadHeight(); y++) {
updateQuadrant(world.tile(x * structQuadrantSize, y * structQuadrantSize));
}
}
scanOres();
});
}
@@ -91,6 +100,36 @@ public class BlockIndexer {
return (!state.teams.get(team).ally ? allyMap : enemyMap).get(type, emptyArray);
}
public TileEntity findTile(Team team, float x, float y, float range, Predicate<Tile> pred){
Entity closest = null;
float dst = 0;
for(int rx = Math.max((int)((x-range)/tilesize/structQuadrantSize), 0); rx <= (int)((x+range)/tilesize/structQuadrantSize) && rx < quadWidth(); rx ++){
for(int ry = Math.max((int)((y-range)/tilesize/structQuadrantSize), 0); ry <= (int)((y+range)/tilesize/structQuadrantSize) && ry < quadHeight(); ry ++){
if(!getQuad(team, rx, ry)) continue;
for(int tx = rx * structQuadrantSize; tx < (rx + 1) * structQuadrantSize && tx < world.width(); tx ++){
for(int ty = ry * structQuadrantSize; ty < (ry + 1) * structQuadrantSize && ty < world.height(); ty ++ ){
Tile other = world.tile(tx, ty);
if(other == null || other.entity == null || !pred.test(other)) continue;
TileEntity e = other.entity;
float ndst = Vector2.dst(x, y, e.x, e.y);
if(ndst < range && (closest == null || ndst < dst)){
dst = ndst;
closest = e;
}
}
}
}
}
return (TileEntity) closest;
}
/**Returns a set of tiles that have ores of the specified type nearby.
* While each tile in the set is not guaranteed to have an ore directly on it,
* each tile will at least have an ore within {@link #oreQuadrantSize} / 2 blocks of it.
@@ -124,7 +163,8 @@ public class BlockIndexer {
//this quadrant is now 'dirty', re-scan the whole thing
int quadrantX = tile.x / structQuadrantSize;
int quadrantY = tile.y / structQuadrantSize;
int index = quadrantX * Mathf.ceil(world.width() / (float)structQuadrantSize) + quadrantY;
int index = quadrantX + quadrantY * quadWidth();
//Log.info("Updating quadrant: {0} {1}", quadrantX, quadrantY);
for(TeamData data : state.teams.getTeams()) {
@@ -150,6 +190,19 @@ public class BlockIndexer {
}
}
private boolean getQuad(Team team, int quadrantX, int quadrantY){
int index = quadrantX + quadrantY * Mathf.ceil(world.width() / (float)structQuadrantSize);
return structQuadrants[team.ordinal()].get(index);
}
private int quadWidth(){
return Mathf.ceil(world.width() / (float)structQuadrantSize);
}
private int quadHeight(){
return Mathf.ceil(world.height() / (float)structQuadrantSize);
}
private ObjectMap<BlockFlag, ObjectSet<Tile>> getMap(Team team){
if(!state.teams.has(team)) return emptyMap;
return state.teams.get(team).ally ? allyMap : enemyMap;
@@ -105,7 +105,7 @@ public class WaveSpawner {
for (int y = quady * quadsize; y < world.height() && y < (quady + 1)*quadsize; y++) {
Tile tile = world.tile(x, y);
if(tile.solid() || world.pathfinder().getValueforTeam(Team.red, x, y) == Float.MAX_VALUE){
if(tile == null || tile.solid() || world.pathfinder().getValueforTeam(Team.red, x, y) == Float.MAX_VALUE){
setQuad(quadx, quady, false);
break outer;
}