diff --git a/android/src/io/anuke/mindustry/AndroidLauncher.java b/android/src/io/anuke/mindustry/AndroidLauncher.java index 6b971c5447..6a32a21744 100644 --- a/android/src/io/anuke/mindustry/AndroidLauncher.java +++ b/android/src/io/anuke/mindustry/AndroidLauncher.java @@ -99,7 +99,7 @@ public class AndroidLauncher extends AndroidApplication{ @Override public boolean isDebug() { - return false; + return true; } @Override diff --git a/core/assets/version.properties b/core/assets/version.properties index f42e562b9c..6de554e714 100644 --- a/core/assets/version.properties +++ b/core/assets/version.properties @@ -1,7 +1,7 @@ #Autogenerated file. Do not modify. -#Sat Apr 21 11:52:24 EDT 2018 +#Sat Apr 21 14:21:33 EDT 2018 version=release -androidBuildCode=1079 +androidBuildCode=1083 name=Mindustry code=3.5 build=custom build diff --git a/core/src/io/anuke/mindustry/ai/HGraph.java b/core/src/io/anuke/mindustry/ai/HGraph.java new file mode 100644 index 0000000000..5fa0c45056 --- /dev/null +++ b/core/src/io/anuke/mindustry/ai/HGraph.java @@ -0,0 +1,29 @@ +package io.anuke.mindustry.ai; + +import com.badlogic.gdx.ai.pfa.Connection; +import com.badlogic.gdx.ai.pfa.HierarchicalGraph; +import com.badlogic.gdx.utils.Array; +import io.anuke.mindustry.world.Tile; + +public class HGraph implements HierarchicalGraph { + + @Override + public int getLevelCount() { + return 0; + } + + @Override + public void setLevel(int level) { + + } + + @Override + public Tile convertNodeBetweenLevels(int inputLevel, Tile node, int outputLevel) { + return null; + } + + @Override + public Array> getConnections(Tile fromNode) { + return null; + } +} diff --git a/core/src/io/anuke/mindustry/ai/OptimizedPathFinder.java b/core/src/io/anuke/mindustry/ai/OptimizedPathFinder.java index 2a122a3051..7e164b2f33 100644 --- a/core/src/io/anuke/mindustry/ai/OptimizedPathFinder.java +++ b/core/src/io/anuke/mindustry/ai/OptimizedPathFinder.java @@ -22,6 +22,7 @@ public class OptimizedPathFinder { NodeRecord current; private int searchId; + private Tile end; private static final byte UNVISITED = 0; private static final byte OPEN = 1; @@ -29,14 +30,12 @@ public class OptimizedPathFinder { private static final boolean debug = false; - public static boolean unop = false; - public static boolean step = true; - public OptimizedPathFinder() { this.openList = new BinaryHeap<>(); } public boolean searchNodePath(Tile startNode, Tile endNode, GraphPath outPath) { + this.end = endNode; // Perform AStar boolean found = search(startNode, endNode); @@ -135,13 +134,13 @@ public class OptimizedPathFinder { protected void visitChildren(Tile endNode) { if(debug) Effects.effect(Fx.node3, current.node.worldx(), current.node.worldy()); - jps(current.node, current.from == null ? -1 : relDirection(current.node, current.from), endNode, node -> { + nodes(current.node, node -> { float addCost = estimate(current.node, node); float nodeCost = current.costSoFar + addCost; float nodeHeuristic; - NodeRecord nodeRecord = getNodeRecord(node);; + NodeRecord nodeRecord = getNodeRecord(node); if (nodeRecord.category == CLOSED) { // The node is closed @@ -182,19 +181,17 @@ public class OptimizedPathFinder { }); } + protected void nodes(Tile current, Consumer cons){ + if(obstacle(current)) return; + for(int i = 0; i < 4; i ++){ + Tile n = current.getNearby(i); + if(!obstacle(n)) cons.accept(n); + } + } protected void jps(Tile current, int direction, Tile end, Consumer cons){ if(obstacle(current)) return; //skip solid or off-the-screen stuff - //Log.info("jps {0} {1} // {2}", current.x, current.y, direction); - - if(unop){ - for(int i = 0; i < 4; i ++){ - if(!obstacle(current.getNearby(i))) cons.accept(current.getNearby(i)); - } - return; - } - //if there's no start point, scan everything. if(direction == -1){ for(int i = 0; i < 8; i ++){ @@ -267,7 +264,6 @@ public class OptimizedPathFinder { } protected Tile scanDir(Tile tile, Tile end, int direction){ - while(!obstacle(tile)){ if(debug) Effects.effect(Fx.node2, tile.worldx(), tile.worldy()); if(tile == end) return tile; @@ -303,12 +299,12 @@ public class OptimizedPathFinder { } protected boolean obstacle(Tile tile){ - return tile == null || tile.solid(); + return tile == null || (tile.solid() && end.target() != tile && tile.target() != end); } protected float estimate(Tile tile, Tile other){ return Math.abs(tile.worldx() - other.worldx()) + Math.abs(tile.worldy() - other.worldy()) + - (tile.occluded ? tilesize*2 : 0) + (other.occluded ? tilesize*2 : 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 59e35f7dfd..afb8c5d3b0 100644 --- a/core/src/io/anuke/mindustry/ai/Pathfinder.java +++ b/core/src/io/anuke/mindustry/ai/Pathfinder.java @@ -1,46 +1,42 @@ package io.anuke.mindustry.ai; -import com.badlogic.gdx.ai.pfa.DefaultGraphPath; import com.badlogic.gdx.ai.pfa.PathSmoother; import com.badlogic.gdx.math.Vector2; +import com.badlogic.gdx.utils.async.AsyncExecutor; import io.anuke.mindustry.content.fx.Fx; import io.anuke.mindustry.game.EventType.WorldLoadEvent; 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.Log; public class Pathfinder { - OptimizedPathFinder find = new OptimizedPathFinder(); - OptimizedPathFinder find2 = new OptimizedPathFinder(); - Tile start, end; + private OptimizedPathFinder find; + private AsyncExecutor executor = new AsyncExecutor(8); + private PathSmoother smoother = new PathSmoother<>(new Raycaster()); + //private HierarchicalPathFinder hfinder = new HierarchicalPathFinder<>(); 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 test(Tile start, Tile end){ - this.start = start; - this.end = end; - - DefaultGraphPath p = new DefaultGraphPath<>(); - - OptimizedPathFinder.unop = false; - Timers.markNs(); - find.searchNodePath(start, end, p); - - Log.info("JSFSAF elapsed: {0}", Timers.elapsedNs()); - - for(Tile tile : p){ - Effects.effect(Fx.breakBlock, tile.worldx(), tile.worldy()); - } - SmoothGraphPath p2 = new SmoothGraphPath(); - OptimizedPathFinder.unop = true; Timers.markNs(); - find2.searchNodePath(start, end, p2); + find.searchNodePath(start, end, p2); new PathSmoother(new Raycaster()).smoothPath(p2); Log.info("UNOP elapsed: {0}", Timers.elapsedNs()); @@ -56,6 +52,6 @@ public class Pathfinder { } private void clear(){ - + find = new OptimizedPathFinder(); } } diff --git a/core/src/io/anuke/mindustry/entities/units/BaseUnit.java b/core/src/io/anuke/mindustry/entities/units/BaseUnit.java index d70225a5b6..84b265449c 100644 --- a/core/src/io/anuke/mindustry/entities/units/BaseUnit.java +++ b/core/src/io/anuke/mindustry/entities/units/BaseUnit.java @@ -1,6 +1,10 @@ package io.anuke.mindustry.entities.units; -import io.anuke.mindustry.entities.*; +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.Unit; import io.anuke.mindustry.game.Team; import io.anuke.ucore.entities.Entity; import io.anuke.ucore.util.Mathf; @@ -19,6 +23,10 @@ public class BaseUnit extends Unit{ public float walkTime = 0f; 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; @@ -97,6 +105,11 @@ public class BaseUnit extends Unit{ hitbox.setSize(type.hitsize); hitboxTile.setSize(type.hitsizeTile); + if(!isFlying()){ + finder = new OptimizedPathFinder(); + path = new SmoothGraphPath(); + } + heal(); } diff --git a/core/src/io/anuke/mindustry/entities/units/GroundUnitType.java b/core/src/io/anuke/mindustry/entities/units/GroundUnitType.java index 4e3fe0e970..512f37bd79 100644 --- a/core/src/io/anuke/mindustry/entities/units/GroundUnitType.java +++ b/core/src/io/anuke/mindustry/entities/units/GroundUnitType.java @@ -15,19 +15,23 @@ import io.anuke.ucore.util.Mathf; import io.anuke.ucore.util.Translator; 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! protected Translator tr2 = new Translator(); - protected float stopDistance = 30f; + protected float jumpDistance = 4f; public GroundUnitType(String name) { super(name); maxVelocity = 1.1f; - speed = 0.05f; + speed = 0.1f; drag = 0.4f; } @@ -103,16 +107,29 @@ public abstract class GroundUnitType extends UnitType{ @Override public void behavior(BaseUnit unit) { //TODO actually pathfind - tr2.set(unit.target.x, unit.target.y).sub(unit.x, unit.y); + 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; + }); - if(tr2.len() > stopDistance){ - tr2.limit(speed); - - unit.walkTime += Timers.delta(); - - unit.velocity.add(tr2); + unit.node = nodeStateCalculating; } + 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/graphics/MinimapRenderer.java b/core/src/io/anuke/mindustry/graphics/MinimapRenderer.java index e2f4a1075c..c0f21f3537 100644 --- a/core/src/io/anuke/mindustry/graphics/MinimapRenderer.java +++ b/core/src/io/anuke/mindustry/graphics/MinimapRenderer.java @@ -5,7 +5,7 @@ import com.badlogic.gdx.graphics.Pixmap.Format; import com.badlogic.gdx.graphics.Texture; import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.math.Rectangle; -import com.sun.media.jfxmediaimpl.MediaDisposer.Disposable; +import com.badlogic.gdx.utils.Disposable; import io.anuke.mindustry.entities.Units; import io.anuke.mindustry.game.EventType.TileChangeEvent; import io.anuke.mindustry.game.EventType.WorldLoadEvent; diff --git a/core/src/io/anuke/mindustry/input/DesktopInput.java b/core/src/io/anuke/mindustry/input/DesktopInput.java index 22c9f58593..29efffda5c 100644 --- a/core/src/io/anuke/mindustry/input/DesktopInput.java +++ b/core/src/io/anuke/mindustry/input/DesktopInput.java @@ -194,10 +194,6 @@ public class DesktopInput extends InputHandler{ world.pathfinder().test(world.tileWorld(player.x, player.y), world.tileWorld(Graphics.mouseWorld().x, Graphics.mouseWorld().y)); } - if(Inputs.keyTap(Input.L)){ - world.pathfinder().step(); - } - if(!ui.hasMouse()) { if (showCursor) Cursors.setHand(); diff --git a/core/src/io/anuke/mindustry/world/Tile.java b/core/src/io/anuke/mindustry/world/Tile.java index c8d41d57f7..b72868923d 100644 --- a/core/src/io/anuke/mindustry/world/Tile.java +++ b/core/src/io/anuke/mindustry/world/Tile.java @@ -23,7 +23,6 @@ public class Tile{ private byte floor, wall; private byte rotation; private byte dump; - private byte extra; private byte team; /**The coordinates of the core tile this is linked to, in the form of two bytes packed into one. * This is relative to the block it is linked to; negate coords to find the link.*/ @@ -32,6 +31,9 @@ public class Tile{ /**Whether this tile has any solid blocks near it.*/ public boolean occluded = false; public TileEntity entity; + + public float pathDistance = -1; + public float vecx, vecy; public Tile(int x, int y){ this.x = (short)x; @@ -167,10 +169,6 @@ public class Tile{ this.dump = dump; } - public void setExtra(byte extra){ - this.extra = extra; - } - public byte getRotation(){ return rotation; } @@ -178,10 +176,6 @@ public class Tile{ public byte getDump(){ return dump; } - - public byte getExtra(){ - return extra; - } public boolean passable(){ Block block = block(); diff --git a/core/src/io/anuke/mindustry/world/blocks/types/distribution/Router.java b/core/src/io/anuke/mindustry/world/blocks/types/distribution/Router.java index 0086e40c12..27dd5d7704 100644 --- a/core/src/io/anuke/mindustry/world/blocks/types/distribution/Router.java +++ b/core/src/io/anuke/mindustry/world/blocks/types/distribution/Router.java @@ -48,7 +48,6 @@ public class Router extends Block{ public void handleItem(Item item, Tile tile, Tile source){ super.handleItem(item, tile, source); tile.entity.wakeUp(); - tile.setExtra(tile.relativeTo(source.x, source.y)); } @Override diff --git a/core/src/io/anuke/mindustry/world/blocks/types/storage/Vault.java b/core/src/io/anuke/mindustry/world/blocks/types/storage/Vault.java index 81b5edae05..4cb76911cc 100644 --- a/core/src/io/anuke/mindustry/world/blocks/types/storage/Vault.java +++ b/core/src/io/anuke/mindustry/world/blocks/types/storage/Vault.java @@ -27,7 +27,6 @@ public class Vault extends StorageBlock { @Override public void handleItem(Item item, Tile tile, Tile source){ super.handleItem(item, tile, source); - tile.setExtra(tile.relativeTo(source.x, source.y)); } @Override