From 95f10aeb060fb14be310a399efe7bb4b9f8d2bdd Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 21 Apr 2018 11:55:32 -0400 Subject: [PATCH] Attempts to further optimize pathfinding --- core/assets/version.properties | 4 +- .../mindustry/ai/OptimizedPathFinder.java | 37 ++++++------------- .../src/io/anuke/mindustry/ai/Pathfinder.java | 24 ++++++++++-- 3 files changed, 35 insertions(+), 30 deletions(-) diff --git a/core/assets/version.properties b/core/assets/version.properties index fbb0082b40..f42e562b9c 100644 --- a/core/assets/version.properties +++ b/core/assets/version.properties @@ -1,7 +1,7 @@ #Autogenerated file. Do not modify. -#Sat Apr 21 01:07:37 EDT 2018 +#Sat Apr 21 11:52:24 EDT 2018 version=release -androidBuildCode=1077 +androidBuildCode=1079 name=Mindustry code=3.5 build=custom build diff --git a/core/src/io/anuke/mindustry/ai/OptimizedPathFinder.java b/core/src/io/anuke/mindustry/ai/OptimizedPathFinder.java index 834d48e803..2a122a3051 100644 --- a/core/src/io/anuke/mindustry/ai/OptimizedPathFinder.java +++ b/core/src/io/anuke/mindustry/ai/OptimizedPathFinder.java @@ -13,6 +13,8 @@ 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<>(); @@ -20,7 +22,6 @@ public class OptimizedPathFinder { NodeRecord current; private int searchId; - private Tile cameFrom = null; private static final byte UNVISITED = 0; private static final byte OPEN = 1; @@ -63,30 +64,12 @@ public class OptimizedPathFinder { visitChildren(endNode); - cameFrom = current.node; - } while (openList.size > 0); // We've run out of nodes without finding the goal, so there's no solution return false; } - public void runStep(Tile startNode, Tile endNode){ - if(openList.size > 0) { - // Retrieve the node with smallest estimated total cost from the open list - current = openList.pop(); - current.category = CLOSED; - - // Terminate if we reached the goal node - if (current.node == endNode) return; - - visitChildren(endNode); - - cameFrom = current.node; - - } - } - public boolean search(PathFinderRequest request, long timeToRun) { long lastTime = TimeUtils.nanoTime(); @@ -138,7 +121,6 @@ public class OptimizedPathFinder { // Initialize the open list openList.clear(); - cameFrom = null; // Initialize the record for the start node and add it to the open list NodeRecord startRecord = getNodeRecord(startNode); @@ -233,11 +215,11 @@ public class OptimizedPathFinder { }else{ //moving diagonal //forced neighbor in the diagonal pattern if(obstacle(rel(current, direction + 3)) && !obstacle(rel(current, direction + 2)) && !obstacle(rel(current, direction -2))) { - cons.accept(rel(current, direction + 2));//jps(rel(current, direction + 2), Mathf.mod(direction + 2, 8), end, cons); + cons.accept(rel(current, direction + 2)); } if(obstacle(rel(current, direction - 3)) && !obstacle(rel(current, direction - 2))&& !obstacle(rel(current, direction + 2))){ - cons.accept(rel(current, direction - 2));//jps(rel(current, direction - 2), Mathf.mod(direction - 2, 8), end, cons); + cons.accept(rel(current, direction - 2)); } } @@ -246,10 +228,10 @@ public class OptimizedPathFinder { //moving straight if(direction % 2 == 0){ Tile sf = scanDir(rel(current, direction), end, direction); //check if there's anything of interest going straight - if(sf != null){ //if there is, jump to that location immediately and stop + if(sf != null){ //if there is, jump to that location immediately and stop. else, nothing must be there, end. cons.accept(sf); - return; } + return; }else{ //moving diagonal Tile sl = scanDir(rel(current, Mathf.mod(direction - 1, 8)), end, Mathf.mod(direction - 1, 8)); @@ -285,13 +267,16 @@ 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; if(direction % 2 == 0){ + //forced neighbor in the straight pattern if((obstacle(rel(tile, direction + 2)) && !obstacle(rel(tile, direction + 1))) || (obstacle(rel(tile, direction - 2)) && !obstacle(rel(tile, direction - 1)))){ + //Log.info("Found forced linear neighbor {0} {1} // {2}", tile.x, tile.y, direction); if(debug) Effects.effect(Fx.node4, tile.worldx(), tile.worldy()); return tile; } @@ -300,6 +285,7 @@ public class OptimizedPathFinder { if((obstacle(rel(tile, direction + 3)) && !obstacle(rel(tile, direction + 2)) && !obstacle(rel(tile, direction - 2))) || (obstacle(rel(tile, direction - 3)) && !obstacle(rel(tile, direction - 2)) && !obstacle(rel(tile, direction + 2)))) { if(debug) Effects.effect(Fx.node4, tile.worldx(), tile.worldy()); + //Log.info("Found forced diagonal neighbor {0} {1} // {2}", tile.x, tile.y, direction); return tile; }else{ return null; @@ -321,7 +307,8 @@ public class OptimizedPathFinder { } protected float estimate(Tile tile, Tile other){ - return Math.abs(tile.worldx() - other.worldx()) + Math.abs(tile.worldy() - other.worldy()); + return Math.abs(tile.worldx() - other.worldx()) + Math.abs(tile.worldy() - other.worldy()) + + (tile.occluded ? tilesize*2 : 0) + (other.occluded ? tilesize*2 : 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 a7b3b2bed6..59e35f7dfd 100644 --- a/core/src/io/anuke/mindustry/ai/Pathfinder.java +++ b/core/src/io/anuke/mindustry/ai/Pathfinder.java @@ -1,6 +1,8 @@ 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 io.anuke.mindustry.content.fx.Fx; import io.anuke.mindustry.game.EventType.WorldLoadEvent; import io.anuke.mindustry.world.Tile; @@ -11,6 +13,7 @@ import io.anuke.ucore.util.Log; public class Pathfinder { OptimizedPathFinder find = new OptimizedPathFinder(); + OptimizedPathFinder find2 = new OptimizedPathFinder(); Tile start, end; public Pathfinder(){ @@ -20,21 +23,36 @@ public class Pathfinder { 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.node1, tile.worldx(), tile.worldy()); + Effects.effect(Fx.breakBlock, tile.worldx(), tile.worldy()); + } + + SmoothGraphPath p2 = new SmoothGraphPath(); + + OptimizedPathFinder.unop = true; + Timers.markNs(); + find2.searchNodePath(start, end, p2); + new PathSmoother(new Raycaster()).smoothPath(p2); + + Log.info("UNOP elapsed: {0}", Timers.elapsedNs()); + + for(Tile tile : p2){ + Effects.effect(Fx.place, tile.worldx(), tile.worldy()); } - Log.info("JSFSAF elapsed: {0}", Timers.elapsedNs()); } public void step(){ - find.runStep(start, end); + //find.runStep(start, end); } private void clear(){