Fixed many pathfinding issues
This commit is contained in:
@@ -4,22 +4,29 @@ import com.badlogic.gdx.ai.pfa.Heuristic;
|
||||
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.World;
|
||||
|
||||
public class MHueristic implements Heuristic<Tile>{
|
||||
//so this means that the cost of going through solids is 10x going through non solids
|
||||
float multiplier = 10f;
|
||||
static float multiplier = 10f;
|
||||
|
||||
@Override
|
||||
public float estimate(Tile node, Tile other){
|
||||
return estimateStatic(node, other);
|
||||
}
|
||||
|
||||
public static float estimateStatic(Tile node, Tile other){
|
||||
float cost = Math.abs(node.worldx() - other.worldx()) + Math.abs(node.worldy() - other.worldy());
|
||||
|
||||
//TODO balance multiplier
|
||||
if(node.breakable() && node.block().solid) cost += Vars.tilesize*multiplier;
|
||||
if(other.breakable() && other.block().solid) cost += Vars.tilesize*multiplier;
|
||||
for(Tile tile : node.getNearby()){
|
||||
if(tile != null && tile.solid()){
|
||||
//don't go near solid tiles!
|
||||
cost += Vars.tilesize*3;
|
||||
for(int dx = -1; dx <= 1; dx ++){
|
||||
for(int dy = -1; dy <= 1; dy ++){
|
||||
Tile tile = World.tile(node.x + dx, node.y + dy);
|
||||
if(tile != null && tile.solid()){
|
||||
cost += Vars.tilesize*5;
|
||||
}
|
||||
}
|
||||
}
|
||||
return cost;
|
||||
|
||||
@@ -1,57 +1,88 @@
|
||||
package io.anuke.mindustry.ai;
|
||||
|
||||
import com.badlogic.gdx.ai.pfa.PathFinder;
|
||||
import com.badlogic.gdx.ai.pfa.PathFinderRequest;
|
||||
import com.badlogic.gdx.ai.pfa.PathSmoother;
|
||||
import com.badlogic.gdx.ai.pfa.indexed.IndexedAStarPathFinder;
|
||||
import com.badlogic.gdx.math.MathUtils;
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.entities.effect.Fx;
|
||||
import io.anuke.mindustry.entities.enemies.Enemy;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.World;
|
||||
import io.anuke.ucore.core.Timers;
|
||||
import io.anuke.ucore.core.Effects;
|
||||
import io.anuke.ucore.util.Angles;
|
||||
import io.anuke.ucore.util.Tmp;
|
||||
public class Pathfind{
|
||||
static MHueristic heuristic = new MHueristic();
|
||||
static PassTileGraph graph = new PassTileGraph();
|
||||
static PathFinder<Tile> finder = new IndexedAStarPathFinder<Tile>(graph);
|
||||
static PassTileGraph passgraph = new PassTileGraph();
|
||||
static PathFinder<Tile> passpathfinder;
|
||||
static Array<SmoothGraphPath> paths = new Array<>();
|
||||
static Tile[][] pathSequences;
|
||||
static PathSmoother<Tile, Vector2> smoother = new PathSmoother<Tile, Vector2>(new Raycaster());
|
||||
static Vector2 vector = new Vector2();
|
||||
|
||||
static public Vector2 find(Enemy enemy){
|
||||
findNode(enemy);
|
||||
|
||||
if(enemy.node <= -1) return vector.set(enemy.x, enemy.y);
|
||||
if(enemy.node == -1){
|
||||
findNode(enemy);
|
||||
}
|
||||
|
||||
//-1 is only possible here if both pathfindings failed, which should NOT happen
|
||||
//check graph code
|
||||
|
||||
//Tile[] path = enemy.path;
|
||||
Array<Tile> path = enemy.gpath.nodes;
|
||||
Tile[] path = enemy.path;
|
||||
|
||||
Tile prev = path[enemy.node - 1];
|
||||
|
||||
Tile target = path.get(enemy.node);
|
||||
Tile target = path[enemy.node];
|
||||
|
||||
float projectLen = Vector2.dst(prev.worldx(), prev.worldy(), target.worldx(), target.worldy()) / 6f;
|
||||
|
||||
Vector2 projection = projectPoint(prev.worldx(), prev.worldy(),
|
||||
target.worldx(), target.worldy(), enemy.x, enemy.y);
|
||||
|
||||
boolean canProject = true;
|
||||
|
||||
if(projectLen < 8 || !onLine(projection, prev.worldx(), prev.worldy(), target.worldx(), target.worldy())){
|
||||
canProject = false;
|
||||
}else{
|
||||
projection.add(Angles.translation(Angles.angle(prev.worldx(), prev.worldy(),
|
||||
target.worldx(), target.worldy()), projectLen));
|
||||
}
|
||||
|
||||
float dst = Vector2.dst(enemy.x, enemy.y, target.worldx(), target.worldy());
|
||||
|
||||
if(dst < 2){
|
||||
if(enemy.node <= path.size-2)
|
||||
if(dst < 8){
|
||||
if(enemy.node <= path.length-2)
|
||||
enemy.node ++;
|
||||
|
||||
target = path.get(enemy.node);
|
||||
target = path[enemy.node];
|
||||
}
|
||||
|
||||
if(canProject && projection.dst(enemy.x, enemy.y) < Vector2.dst(target.x, target.y, enemy.x, enemy.y)){
|
||||
vector.set(projection);
|
||||
}else{
|
||||
vector.set(target.worldx(), target.worldy());
|
||||
}
|
||||
|
||||
//near the core, stop
|
||||
if(enemy.node == path.size - 1){
|
||||
if(enemy.node == path.length - 1){
|
||||
vector.set(target.worldx(), target.worldy());
|
||||
}
|
||||
|
||||
return vector.set(target.worldx(), target.worldy());
|
||||
return vector;
|
||||
|
||||
}
|
||||
|
||||
static public void reset(){
|
||||
paths.clear();
|
||||
pathSequences = null;
|
||||
passpathfinder = new IndexedAStarPathFinder<Tile>(passgraph);
|
||||
}
|
||||
|
||||
static public void updatePath(){
|
||||
|
||||
/*
|
||||
if(paths.size == 0 || paths.size != World.spawnpoints.size){
|
||||
paths.clear();
|
||||
pathSequences = new Tile[World.spawnpoints.size][0];
|
||||
@@ -61,6 +92,13 @@ public class Pathfind{
|
||||
}
|
||||
}
|
||||
|
||||
//TODO make this work?
|
||||
/*
|
||||
PathFinderRequest<Tile> request = new PathFinderRequest<Tile>();
|
||||
request.startNode = World.spawnpoints.get(0);
|
||||
request.endNode = World.core;
|
||||
passpathfinder.search(request, 1000); */
|
||||
|
||||
for(int i = 0; i < paths.size; i ++){
|
||||
SmoothGraphPath path = paths.get(i);
|
||||
|
||||
@@ -85,47 +123,18 @@ public class Pathfind{
|
||||
Effects.effect(Fx.ind, tile.worldx(), tile.worldy());
|
||||
}
|
||||
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
static void findNode(Enemy enemy){
|
||||
/*
|
||||
enemy.path = pathSequences[enemy.spawn];
|
||||
Tile[] path = enemy.path;
|
||||
*/
|
||||
|
||||
|
||||
|
||||
if(enemy.node == -1 || (Timers.get(enemy, "pathfind", 120) && enemy.request.pathFound)){
|
||||
|
||||
enemy.gpath = new SmoothGraphPath();
|
||||
enemy.finder = new IndexedAStarPathFinder<Tile>(graph);
|
||||
enemy.gpath.clear();
|
||||
|
||||
enemy.request = new PathFinderRequest<Tile>(World.tileWorld(enemy.x, enemy.y),
|
||||
World.core,
|
||||
heuristic, enemy.gpath);
|
||||
enemy.request.statusChanged = true;
|
||||
|
||||
enemy.node = -2;
|
||||
}
|
||||
|
||||
if(enemy.gpath != null && !enemy.request.pathFound){
|
||||
enemy.request.executionFrames ++;
|
||||
if(enemy.finder.search(enemy.request, 1000000 / 5)){
|
||||
smoother.smoothPath(enemy.gpath);
|
||||
enemy.node = 1;
|
||||
//UCore.log("done in " + enemy.request.executionFrames + " frames with path of size " + enemy.gpath.getCount());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Tile closest = null;
|
||||
float ldst = 0f;
|
||||
int cindex = -1;
|
||||
|
||||
for(int i = 0; i < path.size; i ++){
|
||||
Tile tile = path.get(i);
|
||||
for(int i = 0; i < path.length; i ++){
|
||||
Tile tile = path[i];
|
||||
float dst = Vector2.dst(tile.worldx(), tile.worldy(), enemy.x, enemy.y);
|
||||
|
||||
if(closest == null || dst < ldst){
|
||||
@@ -134,6 +143,17 @@ public class Pathfind{
|
||||
cindex = i;
|
||||
}
|
||||
}
|
||||
enemy.node = cindex;*/
|
||||
enemy.node = Math.max(cindex, 1);
|
||||
}
|
||||
|
||||
private static boolean onLine(Vector2 vector, float x1, float y1, float x2, float y2){
|
||||
return MathUtils.isEqual(vector.dst(x1, y1) + vector.dst(x2, y2), Vector2.dst(x1, y1, x2, y2), 0.01f);
|
||||
}
|
||||
|
||||
private static Vector2 projectPoint(float x1, float y1, float x2, float y2, float pointx, float pointy){
|
||||
float px = x2-x1, py = y2-y1, dAB = px*px + py*py;
|
||||
float u = ((pointx - x1) * px + (pointy - y1) * py) / dAB;
|
||||
float x = x1 + u * px, y = y1 + u * py;
|
||||
return Tmp.v3.set(x, y); //this is D
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,7 +4,7 @@ import com.badlogic.gdx.ai.pfa.Connection;
|
||||
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
|
||||
public class TileConnection implements Connection{
|
||||
public class TileConnection implements Connection<Tile>{
|
||||
Tile a, b;
|
||||
|
||||
public TileConnection(Tile a, Tile b){
|
||||
@@ -14,16 +14,16 @@ public class TileConnection implements Connection{
|
||||
|
||||
@Override
|
||||
public float getCost(){
|
||||
return Math.abs(a.worldx() - b.worldx()) + Math.abs(a.worldy() - b.worldy());
|
||||
return MHueristic.estimateStatic(a, b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getFromNode(){
|
||||
public Tile getFromNode(){
|
||||
return a;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getToNode(){
|
||||
public Tile getToNode(){
|
||||
return b;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user