Smoothed enemy paths, AI should no longer get stuck on walls

This commit is contained in:
Anuken
2017-08-13 13:57:39 -04:00
parent cd4014f86a
commit 4da9d730bf
9 changed files with 159 additions and 17 deletions

View File

@@ -62,6 +62,8 @@ public class Control extends RendererModule{
"corexplode.wav", "break.wav", "spawn.wav", "flame.wav", "die.wav",
"respawn.wav", "purchase.wav", "flame2.wav");
Sounds.setFalloff(9000f);
Musics.load("1.mp3", "2.mp3", "3.mp3");
World.loadMaps();
@@ -80,8 +82,6 @@ public class Control extends RendererModule{
for(String map : maps)
Settings.defaults("hiscore"+map, 0);
Sounds.setFalloff(9000f);
player = new Player();
}
@@ -391,6 +391,12 @@ public class Control extends RendererModule{
Renderer.renderPixelOverlay();
}
@Override
public void dispose(){
super.dispose();
World.disposeMaps();
}
@Override
public void resize(int width, int height){
super.resize(width, height);

View File

@@ -435,10 +435,11 @@ public class UI extends SceneModule{
row();
if(Gdx.app.getType() != ApplicationType.WebGL)
new button("Exit", () -> {
Gdx.app.exit();
});
if(Gdx.app.getType() != ApplicationType.WebGL && !android){
new button("Exit", () -> {
Gdx.app.exit();
});
}
get().pad(Unit.dp.inPixels(20));
}};

View File

@@ -225,4 +225,14 @@ public class World{
public static int tiley(){
return Mathf.scl2(Graphics.mouseWorld().y, tilesize);
}
public static void disposeMaps(){
for(Pixmap pixmap : mapPixmaps){
pixmap.dispose();
}
for(Texture texture : mapTextures){
texture.dispose();
}
}
}

View File

@@ -16,6 +16,11 @@ public class MHueristic implements Heuristic<Tile>{
//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()){
cost += Vars.tilesize*2;
}
}
return cost;
}

View File

@@ -1,20 +1,23 @@
package io.anuke.mindustry.ai;
import com.badlogic.gdx.ai.pfa.DefaultGraphPath;
import com.badlogic.gdx.ai.pfa.PathFinder;
import com.badlogic.gdx.ai.pfa.PathSmoother;
import com.badlogic.gdx.ai.pfa.indexed.IndexedAStarPathFinder;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.World;
import io.anuke.mindustry.entities.enemies.Enemy;
import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.core.Effects;
public class Pathfind{
static MHueristic heuristic = new MHueristic();
static PassTileGraph passgraph = new PassTileGraph();
static PathFinder<Tile> passpathfinder;
static Array<DefaultGraphPath<Tile>> paths = new Array<>();
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){
@@ -53,19 +56,21 @@ public class Pathfind{
if(paths.size == 0){
pathSequences = new Tile[World.spawnpoints.size][0];
for(int i = 0; i < World.spawnpoints.size; i ++){
DefaultGraphPath<Tile> path = new DefaultGraphPath<>();
SmoothGraphPath path = new SmoothGraphPath();
paths.add(path);
}
}
for(int i = 0; i < paths.size; i ++){
DefaultGraphPath<Tile> path = paths.get(i);
SmoothGraphPath path = paths.get(i);
path.clear();
passpathfinder.searchNodePath(
World.spawnpoints.get(i),
World.core, heuristic, path);
smoother.smoothPath(path);
pathSequences[i] = new Tile[path.getCount()];
for(int node = 0; node < path.getCount(); node ++){
@@ -75,10 +80,10 @@ public class Pathfind{
}
//if(debug)
//for(Tile tile : path){
// Effects.effect("ind", tile.worldx(), tile.worldy());
//}
if(Vars.debug)
for(Tile tile : path){
Effects.effect("ind", tile.worldx(), tile.worldy());
}
}
}

View File

@@ -0,0 +1,86 @@
package io.anuke.mindustry.ai;
import com.badlogic.gdx.ai.utils.Collision;
import com.badlogic.gdx.ai.utils.Ray;
import com.badlogic.gdx.ai.utils.RaycastCollisionDetector;
import com.badlogic.gdx.math.Vector2;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.World;
import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.util.Geometry;
import io.anuke.ucore.util.Mathf;
public class Raycaster implements RaycastCollisionDetector<Vector2>{
private boolean found = false;
@Override
public boolean collides(Ray<Vector2> ray){
found = false;
Geometry.iterateLine(0f, ray.start.x, ray.start.y, ray.end.x, ray.end.y, Vars.tilesize, (x, y)->{
if(solid(x, y)){
found = true;
return;
}
});
return found;
}
@Override
public boolean findCollision(Collision<Vector2> collision, Ray<Vector2> ray){
Vector2 v = vectorCast(ray.start.x, ray.start.y, ray.end.x, ray.end.y);
if(v == null) return false;
collision.point = v;
collision.normal = v.nor();
return true;
}
Vector2 vectorCast(float x0f, float y0f, float x1f, float y1f){
int x0 = (int)x0f;
int y0 = (int)y0f;
int x1 = (int)x1f;
int y1 = (int)y1f;
int dx = Math.abs(x1 - x0);
int dy = Math.abs(y1 - y0);
int sx = x0 < x1 ? 1 : -1;
int sy = y0 < y1 ? 1 : -1;
int err = dx - dy;
int e2;
while(true){
if(solid(x0, y0)){
return new Vector2(x0, y0);
}
if(x0 == x1 && y0 == y1) break;
e2 = 2 * err;
if(e2 > -dy){
err = err - dy;
x0 = x0 + sx;
}
if(e2 < dx){
err = err + dx;
y0 = y0 + sy;
}
}
return null;
}
private boolean solid(float x, float y){
Tile tile = World.tile(Mathf.scl2(x, Vars.tilesize), Mathf.scl2(y, Vars.tilesize));
if(tile == null || tile.solid()) return true;
for(Tile near : tile.getNearby()){
if(near == null || near.solid()) return true;
}
return false;
}
}

View File

@@ -0,0 +1,28 @@
package io.anuke.mindustry.ai;
import com.badlogic.gdx.ai.pfa.DefaultGraphPath;
import com.badlogic.gdx.ai.pfa.SmoothableGraphPath;
import com.badlogic.gdx.math.Vector2;
import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.util.Tmp;
public class SmoothGraphPath extends DefaultGraphPath<Tile> implements SmoothableGraphPath<Tile, Vector2>{
@Override
public Vector2 getNodePosition(int index){
Tile tile = nodes.get(index);
return Tmp.v1.set(tile.worldx(), tile.worldy());
}
@Override
public void swapNodes(int index1, int index2){
nodes.swap(index1, index2);
}
@Override
public void truncatePath(int newLength){
nodes.truncate(newLength);
}
}