mirror of
https://github.com/Anuken/Mindustry.git
synced 2025-03-13 19:39:04 +07:00
Implemented fast dijkstra-map pathfinding
This commit is contained in:
parent
036f233946
commit
3dd07d2f4a
@ -7,7 +7,7 @@ import io.anuke.mindustry.game.EventType.TileChangeEvent;
|
||||
import io.anuke.mindustry.game.EventType.WorldLoadEvent;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.flags.BlockFlag;
|
||||
import io.anuke.mindustry.world.BlockFlag;
|
||||
import io.anuke.ucore.core.Events;
|
||||
import io.anuke.ucore.util.EnumSet;
|
||||
|
||||
|
@ -28,7 +28,7 @@ public class Heuristics {
|
||||
if(other.breakable() && other.block().solid) cost += tilesize* solidMultiplier + other.block().health;
|
||||
|
||||
//if this block has solid blocks near it, increase the cost, as we don't want enemies hugging walls
|
||||
if(node.occluded) cost += tilesize*occludedMultiplier;
|
||||
//if(node.occluded) cost += tilesize*occludedMultiplier;
|
||||
|
||||
return cost;
|
||||
}
|
||||
@ -55,7 +55,7 @@ public class Heuristics {
|
||||
if(other.breakable() && other.block().solid) cost += tilesize* solidMultiplier + other.block().health;
|
||||
|
||||
//if this block has solid blocks near it, increase the cost, as we don't want enemies hugging walls
|
||||
if(node.occluded) cost += tilesize*occludedMultiplier;
|
||||
//if(node.occluded) cost += tilesize*occludedMultiplier;
|
||||
|
||||
if(other.getLinked() != null) other = other.getLinked();
|
||||
if(node.getLinked() != null) node = node.getLinked();
|
||||
|
@ -13,8 +13,6 @@ import io.anuke.ucore.function.Consumer;
|
||||
import io.anuke.ucore.util.Geometry;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
|
||||
import static io.anuke.mindustry.Vars.tilesize;
|
||||
|
||||
/**An IndexedAStarPathfinder that uses an OptimizedGraph, and therefore has less allocations.*/
|
||||
public class OptimizedPathFinder {
|
||||
IntMap<NodeRecord> records = new IntMap<>();
|
||||
@ -303,8 +301,8 @@ public class OptimizedPathFinder {
|
||||
}
|
||||
|
||||
protected float estimate(Tile tile, Tile other){
|
||||
return Math.abs(tile.worldx() - other.worldx()) + Math.abs(tile.worldy() - other.worldy()) +
|
||||
(tile.occluded ? tilesize : 0) + (other.occluded ? tilesize : 0);
|
||||
return Math.abs(tile.worldx() - other.worldx()) + Math.abs(tile.worldy() - other.worldy()) +0;
|
||||
// (tile.occluded ? tilesize : 0) + (other.occluded ? tilesize : 0);
|
||||
}
|
||||
|
||||
protected int relDirection(Tile from, Tile current){
|
||||
|
@ -1,57 +1,146 @@
|
||||
package io.anuke.mindustry.ai;
|
||||
|
||||
import com.badlogic.gdx.ai.pfa.PathSmoother;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.math.GridPoint2;
|
||||
import com.badlogic.gdx.utils.IntArray;
|
||||
import com.badlogic.gdx.utils.Queue;
|
||||
import com.badlogic.gdx.utils.async.AsyncExecutor;
|
||||
import io.anuke.mindustry.content.fx.Fx;
|
||||
import io.anuke.mindustry.entities.Units;
|
||||
import io.anuke.mindustry.game.EventType.WorldLoadEvent;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.game.TeamInfo.TeamData;
|
||||
import io.anuke.mindustry.world.BlockFlag;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.ucore.core.Effects;
|
||||
import io.anuke.ucore.core.Events;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.function.Listenable;
|
||||
import io.anuke.ucore.util.Geometry;
|
||||
import io.anuke.ucore.util.Log;
|
||||
import io.anuke.ucore.util.Mathf;
|
||||
|
||||
import static io.anuke.mindustry.Vars.state;
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
public class Pathfinder {
|
||||
private OptimizedPathFinder find;
|
||||
private static final float SQRT2 = Mathf.sqrt(2f);
|
||||
private static final float unitBlockCost = 4f;
|
||||
private static boolean avoid = false;
|
||||
|
||||
private AsyncExecutor executor = new AsyncExecutor(8);
|
||||
private PathSmoother<Tile, Vector2> smoother = new PathSmoother<>(new Raycaster());
|
||||
//private HierarchicalPathFinder<Tile> hfinder = new HierarchicalPathFinder<>();
|
||||
private float[][][] weights;
|
||||
private IntArray blocked = new IntArray();
|
||||
|
||||
public Pathfinder(){
|
||||
Events.on(WorldLoadEvent.class, this::clear);
|
||||
}
|
||||
|
||||
public void findPath(Tile start, Tile end, SmoothGraphPath path,
|
||||
OptimizedPathFinder finder, Listenable completed){
|
||||
executor.submit(() -> {
|
||||
finder.searchNodePath(start, end, path);
|
||||
smoother.smoothPath(path);
|
||||
completed.listen();
|
||||
return path;
|
||||
});
|
||||
public void update(){
|
||||
if(avoid) {
|
||||
|
||||
for (TeamData data : state.teams.getTeams()) {
|
||||
for (int i = 0; i < blocked.size; i++) {
|
||||
int c = blocked.get(i);
|
||||
weights[data.team.ordinal()][c % world.width()][c / world.width()] -= unitBlockCost;
|
||||
}
|
||||
}
|
||||
|
||||
blocked.clear();
|
||||
|
||||
Units.getAllUnits(unit -> {
|
||||
if (unit.isFlying()) return;
|
||||
int cx = world.toTile(unit.x), cy = world.toTile(unit.y);
|
||||
for (TeamData data : state.teams.getTeams()) {
|
||||
if (weights[data.team.ordinal()][cx][cy] < Float.MAX_VALUE)
|
||||
weights[data.team.ordinal()][cx][cy] += unitBlockCost;
|
||||
}
|
||||
blocked.add(cx + cy * world.width());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void test(Tile start, Tile end){
|
||||
SmoothGraphPath p2 = new SmoothGraphPath();
|
||||
public Tile getTargetTile(Team team, Tile tile){
|
||||
float[][] values = weights[team.ordinal()];
|
||||
|
||||
Timers.markNs();
|
||||
find.searchNodePath(start, end, p2);
|
||||
new PathSmoother<Tile, Vector2>(new Raycaster()).smoothPath(p2);
|
||||
if(values == null) return tile;
|
||||
|
||||
Log.info("UNOP elapsed: {0}", Timers.elapsedNs());
|
||||
float value = values[tile.x][tile.y];
|
||||
|
||||
for(Tile tile : p2){
|
||||
Effects.effect(Fx.place, tile.worldx(), tile.worldy());
|
||||
Tile target = null;
|
||||
float tl = 0f;
|
||||
for(GridPoint2 point : Geometry.d8) {
|
||||
int dx = tile.x + point.x, dy = tile.y + point.y;
|
||||
|
||||
if(!Mathf.inBounds(dx, dy, world.width(), world.height())) continue;
|
||||
|
||||
if(values[dx][dy] < value && (target == null || values[dx][dy] < tl)){
|
||||
target = world.tile(dx, dy);
|
||||
tl = values[dx][dy];
|
||||
}
|
||||
}
|
||||
|
||||
if(target == null || tl == Float.MAX_VALUE) return tile;
|
||||
|
||||
|
||||
return target;
|
||||
}
|
||||
|
||||
public void step(){
|
||||
//find.runStep(start, end);
|
||||
public float getDebugValue(int x, int y){
|
||||
return weights[Team.blue.ordinal()][x][y];
|
||||
}
|
||||
|
||||
private boolean passable(Tile tile){
|
||||
return (tile.getWallID() == 0 && !(tile.floor().liquid && (tile.floor().damageTaken > 0 || tile.floor().drownTime > 0))) || tile.breakable();
|
||||
}
|
||||
|
||||
private void clear(){
|
||||
find = new OptimizedPathFinder();
|
||||
Timers.markNs();
|
||||
|
||||
weights = new float[Team.values().length][0][0];
|
||||
blocked.clear();
|
||||
|
||||
for(TeamData data : state.teams.getTeams()){
|
||||
float[][] values = new float[world.width()][world.height()];
|
||||
weights[data.team.ordinal()] = values;
|
||||
|
||||
Queue<Tile> frontier = new Queue<>();
|
||||
frontier.ensureCapacity(world.width() * world.height() / 2);
|
||||
|
||||
for (int x = 0; x < world.width(); x++) {
|
||||
for (int y = 0; y < world.height(); y++) {
|
||||
Tile tile = world.tile(x, y);
|
||||
float min = Float.MAX_VALUE;
|
||||
|
||||
if (tile.block().flags != null && state.teams.areEnemies(tile.getTeam(), data.team)) {
|
||||
for (BlockFlag flag : tile.block().flags) {
|
||||
min = Math.min(flag.cost, min);
|
||||
}
|
||||
|
||||
frontier.addFirst(tile);
|
||||
}
|
||||
|
||||
values[x][y] = min;
|
||||
}
|
||||
}
|
||||
|
||||
while (frontier.size > 0) {
|
||||
Tile tile = frontier.removeLast();
|
||||
float cost = values[tile.x][tile.y];
|
||||
|
||||
if (cost < Float.MAX_VALUE) {
|
||||
for (GridPoint2 point : Geometry.d4) {
|
||||
|
||||
int dx = tile.x + point.x, dy = tile.y + point.y;
|
||||
Tile other = world.tile(dx, dy);
|
||||
|
||||
if (other != null && values[dx][dy] > cost + 1 && passable(other)) {
|
||||
|
||||
frontier.addFirst(world.tile(dx, dy));
|
||||
values[dx][dy] = cost + other.cost;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Log.info("Elapsed calculation time: {0}", Timers.elapsedNs());
|
||||
}
|
||||
}
|
||||
|
@ -117,6 +117,8 @@ public class Logic extends Module {
|
||||
runWave();
|
||||
}
|
||||
|
||||
world.pathfinder().update();
|
||||
|
||||
if(!Entities.defaultGroup().isEmpty()) throw new RuntimeException("Do not add anything to the default group!");
|
||||
|
||||
Entities.update(bulletGroup);
|
||||
|
@ -241,6 +241,7 @@ public class Renderer extends RendererModule{
|
||||
if(pixelate)
|
||||
Graphics.flushSurface();
|
||||
|
||||
//drawDebug();
|
||||
drawPlayerNames();
|
||||
|
||||
batch.end();
|
||||
@ -306,6 +307,29 @@ public class Renderer extends RendererModule{
|
||||
}
|
||||
}
|
||||
|
||||
void drawDebug(){
|
||||
int rangex = 50, rangey = 50;
|
||||
Draw.tscl(0.125f);
|
||||
|
||||
for(int x = -rangex; x <= rangex; x++) {
|
||||
for (int y = -rangey; y <= rangey; y++) {
|
||||
int worldx = Mathf.scl(camera.position.x, tilesize) + x;
|
||||
int worldy = Mathf.scl(camera.position.y, tilesize) + y;
|
||||
|
||||
if(world.tile(worldx, worldy) == null) continue;
|
||||
|
||||
float value = world.pathfinder().getDebugValue(worldx, worldy);
|
||||
if(value == Float.MAX_VALUE){
|
||||
Draw.text("R", worldx*tilesize, worldy*tilesize);
|
||||
}else{
|
||||
Draw.text(value + "", worldx*tilesize, worldy*tilesize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Draw.tscl(0.5f);
|
||||
}
|
||||
|
||||
void drawPlayerNames(){
|
||||
GlyphLayout layout = Pools.obtain(GlyphLayout.class);
|
||||
|
||||
|
@ -166,5 +166,21 @@ public class Units {
|
||||
});
|
||||
}
|
||||
|
||||
/**Iterates over all units.*/
|
||||
public static void getAllUnits(Consumer<Unit> cons){
|
||||
|
||||
for(Team team : Team.values()){
|
||||
EntityGroup<BaseUnit> group = unitGroups[team.ordinal()];
|
||||
for(Unit unit : group.all()){
|
||||
cons.accept(unit);
|
||||
}
|
||||
}
|
||||
|
||||
//now check all enemy players
|
||||
for(Unit unit : playerGroup.all()){
|
||||
cons.accept(unit);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,14 +1,12 @@
|
||||
package io.anuke.mindustry.entities.units;
|
||||
|
||||
import io.anuke.mindustry.ai.OptimizedPathFinder;
|
||||
import io.anuke.mindustry.ai.SmoothGraphPath;
|
||||
import io.anuke.mindustry.entities.Bullet;
|
||||
import io.anuke.mindustry.entities.BulletType;
|
||||
import io.anuke.mindustry.entities.TileEntity;
|
||||
import io.anuke.mindustry.entities.Unit;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.resource.Item;
|
||||
import io.anuke.mindustry.world.flags.BlockFlag;
|
||||
import io.anuke.mindustry.world.BlockFlag;
|
||||
import io.anuke.ucore.core.Effects;
|
||||
import io.anuke.ucore.core.Effects.Effect;
|
||||
import io.anuke.ucore.entities.Entity;
|
||||
@ -30,10 +28,6 @@ public class BaseUnit extends Unit{
|
||||
public StateMachine state = new StateMachine();
|
||||
public Entity target;
|
||||
|
||||
protected OptimizedPathFinder finder;
|
||||
protected SmoothGraphPath path;
|
||||
protected int node = -2;
|
||||
|
||||
public BaseUnit(UnitType type, Team team){
|
||||
this.type = type;
|
||||
this.team = team;
|
||||
@ -143,11 +137,6 @@ public class BaseUnit extends Unit{
|
||||
hitboxTile.setSize(type.hitsizeTile);
|
||||
state.set(this, type.getStartState());
|
||||
|
||||
if(!isFlying()){
|
||||
finder = new OptimizedPathFinder();
|
||||
path = new SmoothGraphPath();
|
||||
}
|
||||
|
||||
heal();
|
||||
}
|
||||
|
||||
|
@ -6,7 +6,7 @@ import io.anuke.mindustry.entities.Unit;
|
||||
import io.anuke.mindustry.entities.Units;
|
||||
import io.anuke.mindustry.resource.AmmoType;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.flags.BlockFlag;
|
||||
import io.anuke.mindustry.world.BlockFlag;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.graphics.Draw;
|
||||
import io.anuke.ucore.util.Angles;
|
||||
|
@ -3,6 +3,7 @@ package io.anuke.mindustry.entities.units;
|
||||
import com.badlogic.gdx.graphics.Color;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.utils.ObjectSet;
|
||||
import io.anuke.mindustry.entities.TileEntity;
|
||||
import io.anuke.mindustry.entities.Unit;
|
||||
import io.anuke.mindustry.entities.Units;
|
||||
import io.anuke.mindustry.game.TeamInfo.TeamData;
|
||||
@ -18,9 +19,6 @@ import static io.anuke.mindustry.Vars.state;
|
||||
import static io.anuke.mindustry.Vars.world;
|
||||
|
||||
public abstract class GroundUnitType extends UnitType{
|
||||
private static final int nodeStateNone = -2;
|
||||
private static final int nodeStateCalculating = -1;
|
||||
|
||||
//only use for drawing!
|
||||
protected Translator tr1 = new Translator();
|
||||
//only use for updating!
|
||||
@ -33,6 +31,7 @@ public abstract class GroundUnitType extends UnitType{
|
||||
maxVelocity = 1.1f;
|
||||
speed = 0.1f;
|
||||
drag = 0.4f;
|
||||
range = 40f;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -106,32 +105,20 @@ public abstract class GroundUnitType extends UnitType{
|
||||
|
||||
@Override
|
||||
public void behavior(BaseUnit unit) {
|
||||
//TODO actually pathfind
|
||||
if(unit.node == nodeStateNone){
|
||||
world.pathfinder().findPath(world.tileWorld(unit.x, unit.y), world.tileWorld(unit.target.x, unit.target.y), unit.path, unit.finder, () -> {
|
||||
unit.node = 0;
|
||||
});
|
||||
|
||||
unit.node = nodeStateCalculating;
|
||||
if(unit.target instanceof TileEntity && unit.distanceTo(unit.target) < range) {
|
||||
if(unit.timer.get(timerReload, reload)){
|
||||
//shoot(unit, BulletType.shot, tr2.angle(), 4f);
|
||||
}
|
||||
}else{
|
||||
Tile targetTile = world.pathfinder().getTargetTile(unit.team, world.tileWorld(unit.x, unit.y));
|
||||
|
||||
tr2.trns(unit.baseRotation, speed);
|
||||
|
||||
unit.baseRotation = Mathf.slerpDelta(unit.baseRotation, unit.angleTo(targetTile), 0.05f);
|
||||
unit.walkTime += Timers.delta();
|
||||
unit.velocity.add(tr2);
|
||||
}
|
||||
|
||||
if(!(unit.node >= 0 && unit.node < unit.path.nodes.size)) return;
|
||||
|
||||
Tile nodeTarget = unit.path.get(unit.node);
|
||||
|
||||
tr2.set(nodeTarget.worldx(), nodeTarget.worldy()).sub(unit.x, unit.y);
|
||||
|
||||
if(tr2.len() < jumpDistance){
|
||||
unit.node ++;
|
||||
}
|
||||
|
||||
tr2.limit(speed);
|
||||
unit.walkTime += Timers.delta();
|
||||
unit.velocity.add(tr2);
|
||||
|
||||
|
||||
if(unit.timer.get(timerReload, reload)){
|
||||
//shoot(unit, BulletType.shot, tr2.angle(), 4f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ import io.anuke.mindustry.entities.units.BaseUnit;
|
||||
import io.anuke.mindustry.entities.units.FlyingUnitType;
|
||||
import io.anuke.mindustry.entities.units.UnitState;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.mindustry.world.flags.BlockFlag;
|
||||
import io.anuke.mindustry.world.BlockFlag;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.graphics.Draw;
|
||||
import io.anuke.ucore.util.Angles;
|
||||
|
@ -7,7 +7,7 @@ import io.anuke.mindustry.entities.units.BaseUnit;
|
||||
import io.anuke.mindustry.entities.units.FlyingUnitType;
|
||||
import io.anuke.mindustry.entities.units.UnitState;
|
||||
import io.anuke.mindustry.graphics.Palette;
|
||||
import io.anuke.mindustry.world.flags.BlockFlag;
|
||||
import io.anuke.mindustry.world.BlockFlag;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.graphics.Draw;
|
||||
import io.anuke.ucore.util.Angles;
|
||||
|
@ -199,10 +199,6 @@ public class DesktopInput extends InputHandler{
|
||||
shooting = true;
|
||||
}
|
||||
|
||||
if(Inputs.keyTap(Input.P)){
|
||||
world.pathfinder().test(world.tileWorld(player.x, player.y), world.tileWorld(Graphics.mouseWorld().x, Graphics.mouseWorld().y));
|
||||
}
|
||||
|
||||
if(!ui.hasMouse()) {
|
||||
if (showCursor)
|
||||
Cursors.setHand();
|
||||
|
@ -20,7 +20,6 @@ import io.anuke.mindustry.net.NetEvents;
|
||||
import io.anuke.mindustry.resource.Item;
|
||||
import io.anuke.mindustry.resource.ItemStack;
|
||||
import io.anuke.mindustry.resource.Liquid;
|
||||
import io.anuke.mindustry.world.flags.BlockFlag;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.graphics.Draw;
|
||||
import io.anuke.ucore.graphics.Hue;
|
||||
|
14
core/src/io/anuke/mindustry/world/BlockFlag.java
Normal file
14
core/src/io/anuke/mindustry/world/BlockFlag.java
Normal file
@ -0,0 +1,14 @@
|
||||
package io.anuke.mindustry.world;
|
||||
|
||||
public enum BlockFlag {
|
||||
resupplyPoint(0),
|
||||
producer(Float.MAX_VALUE),
|
||||
repair(Float.MAX_VALUE);
|
||||
|
||||
public final float cost;
|
||||
|
||||
BlockFlag(float cost){
|
||||
if(cost < 0) throw new RuntimeException("Block flag costs cannot be < 0!");
|
||||
this.cost = cost;
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ import com.badlogic.gdx.utils.reflect.ClassReflection;
|
||||
import io.anuke.mindustry.content.blocks.Blocks;
|
||||
import io.anuke.mindustry.entities.TileEntity;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.world.blocks.types.Floor;
|
||||
import io.anuke.mindustry.world.blocks.types.modules.InventoryModule;
|
||||
import io.anuke.mindustry.world.blocks.types.modules.LiquidModule;
|
||||
import io.anuke.mindustry.world.blocks.types.modules.PowerModule;
|
||||
@ -29,8 +30,8 @@ public class Tile implements Position{
|
||||
* This is relative to the block it is linked to; negate coords to find the link.*/
|
||||
public byte link = 0;
|
||||
public short x, y;
|
||||
/**Whether this tile has any solid blocks near it.*/
|
||||
public boolean occluded = false;
|
||||
/**Tile traversal cost*/
|
||||
public float cost = 1f;
|
||||
public TileEntity entity;
|
||||
|
||||
public float pathDistance = -1;
|
||||
@ -118,8 +119,8 @@ public class Tile implements Position{
|
||||
return block().getPlaceOffset().y + worldy();
|
||||
}
|
||||
|
||||
public Block floor(){
|
||||
return Block.getByID(getFloorID());
|
||||
public Floor floor(){
|
||||
return (Floor)Block.getByID(getFloorID());
|
||||
}
|
||||
|
||||
public Block block(){
|
||||
@ -288,16 +289,21 @@ public class Tile implements Position{
|
||||
}
|
||||
|
||||
public void updateOcclusion(){
|
||||
occluded = false;
|
||||
cost = 0.5f;
|
||||
boolean occluded = false;
|
||||
outer:
|
||||
for(int dx = -1; dx <= 1; dx ++){
|
||||
for(int dy = -1; dy <= 1; dy ++){
|
||||
Tile tile = world.tile(x + dx, y + dy);
|
||||
if(tile != null && tile.solid()){
|
||||
occluded = true;
|
||||
break;
|
||||
break outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(occluded){
|
||||
cost += 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
public void changed(){
|
||||
|
@ -5,7 +5,7 @@ import io.anuke.mindustry.entities.TileEntity;
|
||||
import io.anuke.mindustry.world.Edges;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.blocks.types.PowerBlock;
|
||||
import io.anuke.mindustry.world.flags.BlockFlag;
|
||||
import io.anuke.mindustry.world.BlockFlag;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.util.EnumSet;
|
||||
|
||||
|
@ -5,7 +5,7 @@ import io.anuke.mindustry.entities.Units;
|
||||
import io.anuke.mindustry.net.Net;
|
||||
import io.anuke.mindustry.resource.Item;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.flags.BlockFlag;
|
||||
import io.anuke.mindustry.world.BlockFlag;
|
||||
import io.anuke.ucore.graphics.Draw;
|
||||
import io.anuke.ucore.graphics.Lines;
|
||||
import io.anuke.ucore.util.EnumSet;
|
||||
|
@ -8,7 +8,7 @@ import io.anuke.mindustry.entities.Units;
|
||||
import io.anuke.mindustry.graphics.Layer;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.flags.BlockFlag;
|
||||
import io.anuke.mindustry.world.BlockFlag;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.graphics.Draw;
|
||||
import io.anuke.ucore.graphics.Lines;
|
||||
|
@ -9,7 +9,7 @@ import io.anuke.mindustry.graphics.Layer;
|
||||
import io.anuke.mindustry.resource.Item;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.flags.BlockFlag;
|
||||
import io.anuke.mindustry.world.BlockFlag;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.graphics.Draw;
|
||||
import io.anuke.ucore.graphics.Lines;
|
||||
|
@ -1,5 +0,0 @@
|
||||
package io.anuke.mindustry.world.flags;
|
||||
|
||||
public enum BlockFlag {
|
||||
resupplyPoint, producer, repair
|
||||
}
|
Loading…
Reference in New Issue
Block a user