Implemented inefficient pathfinding

This commit is contained in:
Anuken
2018-04-21 14:26:05 -04:00
parent 95f10aeb06
commit 5012313dc4
12 changed files with 107 additions and 68 deletions

View File

@@ -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<Tile> {
@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<Connection<Tile>> getConnections(Tile fromNode) {
return null;
}
}

View File

@@ -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<Tile> 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<Tile> 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<Tile> 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){

View File

@@ -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<Tile, Vector2> smoother = new PathSmoother<>(new Raycaster());
//private HierarchicalPathFinder<Tile> 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<Tile> 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<Tile, Vector2>(new Raycaster()).smoothPath(p2);
Log.info("UNOP elapsed: {0}", Timers.elapsedNs());
@@ -56,6 +52,6 @@ public class Pathfinder {
}
private void clear(){
find = new OptimizedPathFinder();
}
}