From 3dd07d2f4a070410f6f16e3360250ce07977b787 Mon Sep 17 00:00:00 2001 From: Anuken Date: Tue, 1 May 2018 21:34:30 -0400 Subject: [PATCH] Implemented fast dijkstra-map pathfinding --- .../io/anuke/mindustry/ai/BlockIndexer.java | 2 +- .../src/io/anuke/mindustry/ai/Heuristics.java | 4 +- .../mindustry/ai/OptimizedPathFinder.java | 6 +- .../src/io/anuke/mindustry/ai/Pathfinder.java | 143 ++++++++++++++---- core/src/io/anuke/mindustry/core/Logic.java | 2 + .../src/io/anuke/mindustry/core/Renderer.java | 24 +++ .../io/anuke/mindustry/entities/Units.java | 16 ++ .../mindustry/entities/units/BaseUnit.java | 13 +- .../entities/units/FlyingUnitType.java | 2 +- .../entities/units/GroundUnitType.java | 41 ++--- .../entities/units/types/Cruiser.java | 2 +- .../mindustry/entities/units/types/Vtol.java | 2 +- .../anuke/mindustry/input/DesktopInput.java | 4 - core/src/io/anuke/mindustry/world/Block.java | 1 - .../io/anuke/mindustry/world/BlockFlag.java | 14 ++ core/src/io/anuke/mindustry/world/Tile.java | 18 ++- .../blocks/types/power/PowerGenerator.java | 2 +- .../world/blocks/types/storage/CoreBlock.java | 2 +- .../world/blocks/types/units/RepairPoint.java | 2 +- .../blocks/types/units/ResupplyPoint.java | 2 +- .../mindustry/world/flags/BlockFlag.java | 5 - 21 files changed, 211 insertions(+), 96 deletions(-) create mode 100644 core/src/io/anuke/mindustry/world/BlockFlag.java delete mode 100644 core/src/io/anuke/mindustry/world/flags/BlockFlag.java diff --git a/core/src/io/anuke/mindustry/ai/BlockIndexer.java b/core/src/io/anuke/mindustry/ai/BlockIndexer.java index ec3b2866d7..84fe0d65c5 100644 --- a/core/src/io/anuke/mindustry/ai/BlockIndexer.java +++ b/core/src/io/anuke/mindustry/ai/BlockIndexer.java @@ -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; diff --git a/core/src/io/anuke/mindustry/ai/Heuristics.java b/core/src/io/anuke/mindustry/ai/Heuristics.java index 3a2e7885cb..ad5ff8b453 100644 --- a/core/src/io/anuke/mindustry/ai/Heuristics.java +++ b/core/src/io/anuke/mindustry/ai/Heuristics.java @@ -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(); diff --git a/core/src/io/anuke/mindustry/ai/OptimizedPathFinder.java b/core/src/io/anuke/mindustry/ai/OptimizedPathFinder.java index 7e164b2f33..1b8b59e5f4 100644 --- a/core/src/io/anuke/mindustry/ai/OptimizedPathFinder.java +++ b/core/src/io/anuke/mindustry/ai/OptimizedPathFinder.java @@ -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 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){ diff --git a/core/src/io/anuke/mindustry/ai/Pathfinder.java b/core/src/io/anuke/mindustry/ai/Pathfinder.java index afb8c5d3b0..5abc79965e 100644 --- a/core/src/io/anuke/mindustry/ai/Pathfinder.java +++ b/core/src/io/anuke/mindustry/ai/Pathfinder.java @@ -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 smoother = new PathSmoother<>(new Raycaster()); - //private HierarchicalPathFinder 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(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 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()); } } diff --git a/core/src/io/anuke/mindustry/core/Logic.java b/core/src/io/anuke/mindustry/core/Logic.java index c9ea33b3e6..83e6a6f79d 100644 --- a/core/src/io/anuke/mindustry/core/Logic.java +++ b/core/src/io/anuke/mindustry/core/Logic.java @@ -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); diff --git a/core/src/io/anuke/mindustry/core/Renderer.java b/core/src/io/anuke/mindustry/core/Renderer.java index dad85b252b..b21295587b 100644 --- a/core/src/io/anuke/mindustry/core/Renderer.java +++ b/core/src/io/anuke/mindustry/core/Renderer.java @@ -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); diff --git a/core/src/io/anuke/mindustry/entities/Units.java b/core/src/io/anuke/mindustry/entities/Units.java index fbb288b9b9..3c0b76c1c8 100644 --- a/core/src/io/anuke/mindustry/entities/Units.java +++ b/core/src/io/anuke/mindustry/entities/Units.java @@ -166,5 +166,21 @@ public class Units { }); } + /**Iterates over all units.*/ + public static void getAllUnits(Consumer cons){ + + for(Team team : Team.values()){ + EntityGroup 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); + } + } + } diff --git a/core/src/io/anuke/mindustry/entities/units/BaseUnit.java b/core/src/io/anuke/mindustry/entities/units/BaseUnit.java index e0c9164db0..96df837094 100644 --- a/core/src/io/anuke/mindustry/entities/units/BaseUnit.java +++ b/core/src/io/anuke/mindustry/entities/units/BaseUnit.java @@ -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(); } diff --git a/core/src/io/anuke/mindustry/entities/units/FlyingUnitType.java b/core/src/io/anuke/mindustry/entities/units/FlyingUnitType.java index 9f7ea0fb39..3aa6ab8587 100644 --- a/core/src/io/anuke/mindustry/entities/units/FlyingUnitType.java +++ b/core/src/io/anuke/mindustry/entities/units/FlyingUnitType.java @@ -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; diff --git a/core/src/io/anuke/mindustry/entities/units/GroundUnitType.java b/core/src/io/anuke/mindustry/entities/units/GroundUnitType.java index 512f37bd79..8768818ba8 100644 --- a/core/src/io/anuke/mindustry/entities/units/GroundUnitType.java +++ b/core/src/io/anuke/mindustry/entities/units/GroundUnitType.java @@ -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); - } } } diff --git a/core/src/io/anuke/mindustry/entities/units/types/Cruiser.java b/core/src/io/anuke/mindustry/entities/units/types/Cruiser.java index c09a84c8e1..6c7d32f126 100644 --- a/core/src/io/anuke/mindustry/entities/units/types/Cruiser.java +++ b/core/src/io/anuke/mindustry/entities/units/types/Cruiser.java @@ -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; diff --git a/core/src/io/anuke/mindustry/entities/units/types/Vtol.java b/core/src/io/anuke/mindustry/entities/units/types/Vtol.java index 4e10ad0c7c..47b3fbbdc3 100644 --- a/core/src/io/anuke/mindustry/entities/units/types/Vtol.java +++ b/core/src/io/anuke/mindustry/entities/units/types/Vtol.java @@ -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; diff --git a/core/src/io/anuke/mindustry/input/DesktopInput.java b/core/src/io/anuke/mindustry/input/DesktopInput.java index c0d3033728..db747fb1c6 100644 --- a/core/src/io/anuke/mindustry/input/DesktopInput.java +++ b/core/src/io/anuke/mindustry/input/DesktopInput.java @@ -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(); diff --git a/core/src/io/anuke/mindustry/world/Block.java b/core/src/io/anuke/mindustry/world/Block.java index 5040b030d0..7e59fd139c 100644 --- a/core/src/io/anuke/mindustry/world/Block.java +++ b/core/src/io/anuke/mindustry/world/Block.java @@ -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; diff --git a/core/src/io/anuke/mindustry/world/BlockFlag.java b/core/src/io/anuke/mindustry/world/BlockFlag.java new file mode 100644 index 0000000000..76738f2d1e --- /dev/null +++ b/core/src/io/anuke/mindustry/world/BlockFlag.java @@ -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; + } +} diff --git a/core/src/io/anuke/mindustry/world/Tile.java b/core/src/io/anuke/mindustry/world/Tile.java index 6ce6ccd81b..925098c0fd 100644 --- a/core/src/io/anuke/mindustry/world/Tile.java +++ b/core/src/io/anuke/mindustry/world/Tile.java @@ -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(){ diff --git a/core/src/io/anuke/mindustry/world/blocks/types/power/PowerGenerator.java b/core/src/io/anuke/mindustry/world/blocks/types/power/PowerGenerator.java index 441222ef2d..a5a7948739 100644 --- a/core/src/io/anuke/mindustry/world/blocks/types/power/PowerGenerator.java +++ b/core/src/io/anuke/mindustry/world/blocks/types/power/PowerGenerator.java @@ -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; diff --git a/core/src/io/anuke/mindustry/world/blocks/types/storage/CoreBlock.java b/core/src/io/anuke/mindustry/world/blocks/types/storage/CoreBlock.java index c634867c8f..6177ce0e40 100644 --- a/core/src/io/anuke/mindustry/world/blocks/types/storage/CoreBlock.java +++ b/core/src/io/anuke/mindustry/world/blocks/types/storage/CoreBlock.java @@ -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; diff --git a/core/src/io/anuke/mindustry/world/blocks/types/units/RepairPoint.java b/core/src/io/anuke/mindustry/world/blocks/types/units/RepairPoint.java index 41226e7d5e..e02d99e4df 100644 --- a/core/src/io/anuke/mindustry/world/blocks/types/units/RepairPoint.java +++ b/core/src/io/anuke/mindustry/world/blocks/types/units/RepairPoint.java @@ -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; diff --git a/core/src/io/anuke/mindustry/world/blocks/types/units/ResupplyPoint.java b/core/src/io/anuke/mindustry/world/blocks/types/units/ResupplyPoint.java index b70dfdc005..ae208b4aaa 100644 --- a/core/src/io/anuke/mindustry/world/blocks/types/units/ResupplyPoint.java +++ b/core/src/io/anuke/mindustry/world/blocks/types/units/ResupplyPoint.java @@ -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; diff --git a/core/src/io/anuke/mindustry/world/flags/BlockFlag.java b/core/src/io/anuke/mindustry/world/flags/BlockFlag.java deleted file mode 100644 index 7ead18f4fa..0000000000 --- a/core/src/io/anuke/mindustry/world/flags/BlockFlag.java +++ /dev/null @@ -1,5 +0,0 @@ -package io.anuke.mindustry.world.flags; - -public enum BlockFlag { - resupplyPoint, producer, repair -}