Broken attempt at per-enemy pathfinding; balancing

This commit is contained in:
Anuken
2017-11-23 20:58:32 -05:00
parent 88e4154ea3
commit b2cd95899c
12 changed files with 93 additions and 54 deletions

View File

@@ -6,7 +6,6 @@ import java.util.Date;
import com.badlogic.gdx.backends.android.AndroidApplication; import com.badlogic.gdx.backends.android.AndroidApplication;
import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration; import com.badlogic.gdx.backends.android.AndroidApplicationConfiguration;
import com.badlogic.gdx.utils.Array;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.os.Bundle; import android.os.Bundle;
@@ -35,9 +34,6 @@ public class AndroidLauncher extends AndroidApplication {
} }
}; };
//TODO
Mindustry.args = Array.with("-debug");
initialize(new Mindustry(), config); initialize(new Mindustry(), config);
} }
} }

Binary file not shown.

Before

Width:  |  Height:  |  Size: 261 B

After

Width:  |  Height:  |  Size: 279 B

View File

@@ -1,49 +1,47 @@
package io.anuke.mindustry.ai; package io.anuke.mindustry.ai;
import com.badlogic.gdx.ai.pfa.PathFinder; 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.PathSmoother;
import com.badlogic.gdx.ai.pfa.indexed.IndexedAStarPathFinder; import com.badlogic.gdx.ai.pfa.indexed.IndexedAStarPathFinder;
import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array; 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.entities.enemies.Enemy;
import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.World; import io.anuke.mindustry.world.World;
import io.anuke.ucore.core.Effects; import io.anuke.ucore.core.Timers;
public class Pathfind{ public class Pathfind{
static MHueristic heuristic = new MHueristic(); static MHueristic heuristic = new MHueristic();
static PassTileGraph passgraph = new PassTileGraph(); static PassTileGraph graph = new PassTileGraph();
static PathFinder<Tile> passpathfinder; static PathFinder<Tile> finder = new IndexedAStarPathFinder<Tile>(graph);
static Array<SmoothGraphPath> paths = new Array<>();
static Tile[][] pathSequences;
static PathSmoother<Tile, Vector2> smoother = new PathSmoother<Tile, Vector2>(new Raycaster()); static PathSmoother<Tile, Vector2> smoother = new PathSmoother<Tile, Vector2>(new Raycaster());
static Vector2 vector = new Vector2(); static Vector2 vector = new Vector2();
static public Vector2 find(Enemy enemy){ static public Vector2 find(Enemy enemy){
if(enemy.node == -1){ findNode(enemy);
findNode(enemy);
} if(enemy.node <= -1) return vector.set(enemy.x, enemy.y);
//-1 is only possible here if both pathfindings failed, which should NOT happen //-1 is only possible here if both pathfindings failed, which should NOT happen
//check graph code //check graph code
Tile[] path = enemy.path; //Tile[] path = enemy.path;
Array<Tile> path = enemy.gpath.nodes;
Tile target = path[enemy.node]; Tile target = path.get(enemy.node);
float dst = Vector2.dst(enemy.x, enemy.y, target.worldx(), target.worldy()); float dst = Vector2.dst(enemy.x, enemy.y, target.worldx(), target.worldy());
if(dst < 2){ if(dst < 2){
if(enemy.node <= path.length-2) if(enemy.node <= path.size-2)
enemy.node ++; enemy.node ++;
target = path[enemy.node]; target = path.get(enemy.node);
} }
//near the core, stop //near the core, stop
if(enemy.node == path.length - 1){ if(enemy.node == path.size - 1){
vector.set(target.worldx(), target.worldy()); vector.set(target.worldx(), target.worldy());
} }
@@ -51,13 +49,9 @@ public class Pathfind{
} }
static public void reset(){
paths.clear();
pathSequences = null;
passpathfinder = new IndexedAStarPathFinder<Tile>(passgraph);
}
static public void updatePath(){ static public void updatePath(){
/*
if(paths.size == 0 || paths.size != World.spawnpoints.size){ if(paths.size == 0 || paths.size != World.spawnpoints.size){
paths.clear(); paths.clear();
pathSequences = new Tile[World.spawnpoints.size][0]; pathSequences = new Tile[World.spawnpoints.size][0];
@@ -67,13 +61,6 @@ 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 ++){ for(int i = 0; i < paths.size; i ++){
SmoothGraphPath path = paths.get(i); SmoothGraphPath path = paths.get(i);
@@ -98,18 +85,47 @@ public class Pathfind{
Effects.effect(Fx.ind, tile.worldx(), tile.worldy()); Effects.effect(Fx.ind, tile.worldx(), tile.worldy());
} }
} }*/
} }
static void findNode(Enemy enemy){ static void findNode(Enemy enemy){
/*
enemy.path = pathSequences[enemy.spawn]; enemy.path = pathSequences[enemy.spawn];
Tile[] path = enemy.path; 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; Tile closest = null;
float ldst = 0f; float ldst = 0f;
int cindex = -1; int cindex = -1;
for(int i = 0; i < path.length; i ++){ for(int i = 0; i < path.size; i ++){
Tile tile = path[i]; Tile tile = path.get(i);
float dst = Vector2.dst(tile.worldx(), tile.worldy(), enemy.x, enemy.y); float dst = Vector2.dst(tile.worldx(), tile.worldy(), enemy.x, enemy.y);
if(closest == null || dst < ldst){ if(closest == null || dst < ldst){
@@ -118,6 +134,6 @@ public class Pathfind{
cindex = i; cindex = i;
} }
} }
enemy.node = cindex; enemy.node = cindex;*/
} }
} }

View File

@@ -12,7 +12,7 @@ public class SmoothGraphPath extends DefaultGraphPath<Tile> implements Smoothabl
@Override @Override
public Vector2 getNodePosition(int index){ public Vector2 getNodePosition(int index){
Tile tile = nodes.get(index); Tile tile = nodes.get(index);
return Tmp.v1.set(tile.worldx(), tile.worldy()); return Tmp.v3.set(tile.worldx(), tile.worldy());
} }
@Override @Override
@@ -25,4 +25,9 @@ public class SmoothGraphPath extends DefaultGraphPath<Tile> implements Smoothabl
nodes.truncate(newLength); nodes.truncate(newLength);
} }
@Override
public void add (Tile node) {
nodes.add(node);
}
} }

View File

@@ -47,7 +47,7 @@ public abstract class BulletType extends BaseBulletType<Bullet>{
Draw.reset(); Draw.reset();
} }
}, },
sniper = new BulletType(3f, 23){ sniper = new BulletType(3f, 25){
public void draw(Bullet b){ public void draw(Bullet b){
Draw.color(Color.LIGHT_GRAY); Draw.color(Color.LIGHT_GRAY);
Draw.thick(1f); Draw.thick(1f);
@@ -223,7 +223,7 @@ public abstract class BulletType extends BaseBulletType<Bullet>{
Draw.reset(); Draw.reset();
} }
}, },
flame = new BulletType(0.6f, 4){ flame = new BulletType(0.6f, 5){
public void draw(Bullet b){ public void draw(Bullet b){
Draw.color(Color.YELLOW, Color.SCARLET, b.time/lifetime); Draw.color(Color.YELLOW, Color.SCARLET, b.time/lifetime);
float size = 6f-b.time/lifetime*5f; float size = 6f-b.time/lifetime*5f;
@@ -250,7 +250,7 @@ public abstract class BulletType extends BaseBulletType<Bullet>{
Draw.reset(); Draw.reset();
} }
}, },
shot = new BulletType(2.4f, 2){ shot = new BulletType(2.4f, 4){
{lifetime = 40;} {lifetime = 40;}
public void draw(Bullet b){ public void draw(Bullet b){
Draw.color(lightGold); Draw.color(lightGold);
@@ -258,7 +258,7 @@ public abstract class BulletType extends BaseBulletType<Bullet>{
Draw.reset(); Draw.reset();
} }
}, },
multishot = new BulletType(2.5f, 2){ multishot = new BulletType(2.5f, 3){
{lifetime=40;} {lifetime=40;}
public void draw(Bullet b){ public void draw(Bullet b){
Draw.color(Color.SKY); Draw.color(Color.SKY);

View File

@@ -1,5 +1,7 @@
package io.anuke.mindustry.entities.enemies; package io.anuke.mindustry.entities.enemies;
import com.badlogic.gdx.ai.pfa.PathFinder;
import com.badlogic.gdx.ai.pfa.PathFinderRequest;
import com.badlogic.gdx.graphics.Color; import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Array;
@@ -7,6 +9,7 @@ import com.badlogic.gdx.utils.reflect.ClassReflection;
import io.anuke.mindustry.Vars; import io.anuke.mindustry.Vars;
import io.anuke.mindustry.ai.Pathfind; import io.anuke.mindustry.ai.Pathfind;
import io.anuke.mindustry.ai.SmoothGraphPath;
import io.anuke.mindustry.entities.Bullet; import io.anuke.mindustry.entities.Bullet;
import io.anuke.mindustry.entities.BulletType; import io.anuke.mindustry.entities.BulletType;
import io.anuke.mindustry.entities.Player; import io.anuke.mindustry.entities.Player;
@@ -34,9 +37,11 @@ public class Enemy extends DestructibleEntity{
protected String shootsound = "enemyshoot"; protected String shootsound = "enemyshoot";
protected int damage; protected int damage;
public Tile[] path; public PathFinderRequest<Tile> request = new PathFinderRequest<>();;
public SmoothGraphPath gpath;
public int spawn; public int spawn;
public int node = -1; public int node = -1;
public PathFinder<Tile> finder;
public Vector2 direction = new Vector2(); public Vector2 direction = new Vector2();
public float xvelocity, yvelocity; public float xvelocity, yvelocity;
@@ -122,6 +127,7 @@ public class Enemy extends DestructibleEntity{
public void findClosestNode(){ public void findClosestNode(){
Pathfind.find(this); Pathfind.find(this);
/*
int index = 0; int index = 0;
int cindex = -1; int cindex = -1;
@@ -147,7 +153,7 @@ public class Enemy extends DestructibleEntity{
Timers.run(Mathf.random(15f), ()->{ Timers.run(Mathf.random(15f), ()->{
set(x2 * Vars.tilesize, y2 * Vars.tilesize); set(x2 * Vars.tilesize, y2 * Vars.tilesize);
}); });
} }*/
} }
@Override @Override

View File

@@ -68,6 +68,10 @@ public class World{
return tiles[x][y]; return tiles[x][y];
} }
public static Tile tileWorld(float x, float y){
return tile(Mathf.scl2(x, tilesize), Mathf.scl2(y, tilesize));
}
public static Tile[] getNearby(int x, int y){ public static Tile[] getNearby(int x, int y){
temptiles[0] = tile(x+1, y); temptiles[0] = tile(x+1, y);
temptiles[1] = tile(x, y+1); temptiles[1] = tile(x, y+1);
@@ -146,8 +150,6 @@ public class World{
World.seed = seed; World.seed = seed;
Generator.generate(mapPixmaps[map.ordinal()]); Generator.generate(mapPixmaps[map.ordinal()]);
Pathfind.reset();
//TODO multiblock core //TODO multiblock core
placeBlock(core.x, core.y, ProductionBlocks.core, 0); placeBlock(core.x, core.y, ProductionBlocks.core, 0);

View File

@@ -71,7 +71,7 @@ public class DefenseBlocks{
{ {
fullDescription = "Repairs nearby damaged blocks in range at a slow rate. " fullDescription = "Repairs nearby damaged blocks in range at a slow rate. "
+ "Uses small amounts of power."; + "Uses small amounts of power.";
formalName = "heal turret"; formalName = "repair turret";
range = 30; range = 30;
reload = 40f; reload = 40f;
health = 60; health = 60;
@@ -82,7 +82,7 @@ public class DefenseBlocks{
{ {
fullDescription = "Repairs nearby damaged blocks in range at a decent rate. " fullDescription = "Repairs nearby damaged blocks in range at a decent rate. "
+ "Uses power."; + "Uses power.";
formalName = "heal turret II"; formalName = "repair turret II";
range = 44; range = 44;
reload = 20f; reload = 20f;
health = 90; health = 90;

View File

@@ -14,6 +14,7 @@ import io.anuke.mindustry.world.blocks.types.PowerBlock;
import io.anuke.ucore.core.Draw; import io.anuke.ucore.core.Draw;
import io.anuke.ucore.core.Effects; import io.anuke.ucore.core.Effects;
import io.anuke.ucore.core.Timers; import io.anuke.ucore.core.Timers;
import io.anuke.ucore.graphics.Hue;
import io.anuke.ucore.util.Angles; import io.anuke.ucore.util.Angles;
import io.anuke.ucore.util.Geometry; import io.anuke.ucore.util.Geometry;
import io.anuke.ucore.util.Mathf; import io.anuke.ucore.util.Mathf;
@@ -80,9 +81,13 @@ public class Generator extends PowerBlock{
public void drawOver(Tile tile){ public void drawOver(Tile tile){
PowerEntity entity = tile.entity(); PowerEntity entity = tile.entity();
if(entity.power > powerSpeed){ if(entity.power > powerSpeed){
for(int i = 0; i < laserDirections; i++){ Draw.alpha(1f);
drawLaserTo(tile, (tile.rotation + i) - laserDirections/2); }else{
} Draw.alpha(0.75f);
}
for(int i = 0; i < laserDirections; i++){
drawLaserTo(tile, (tile.rotation + i) - laserDirections/2);
} }
} }
@@ -114,10 +119,9 @@ public class Generator extends PowerBlock{
Tile target = laserTarget(tile, rotation); Tile target = laserTarget(tile, rotation);
if(target != null){ if(target != null){
Angles.translation(rotation * 90, 6f); Angles.translation(rotation * 90, width * Vars.tilesize/2 + 2f);
Draw.color(Color.GRAY, Color.WHITE, 0.902f + Mathf.sin(Timers.time(), 1.7f, 0.08f)); Draw.tint(Hue.mix(Color.GRAY, Color.WHITE, 0.902f + Mathf.sin(Timers.time(), 1.7f, 0.08f)));
Draw.alpha(1f);
float r = 0f; float r = 0f;

View File

@@ -36,7 +36,7 @@ public class LiquidPowerGenerator extends Generator implements LiquidAcceptor{
public void getStats(Array<String> list){ public void getStats(Array<String> list){
super.getStats(list); super.getStats(list);
list.add("[liquidinfo]Liquid Capacity: " + (int)liquidCapacity); list.add("[liquidinfo]Liquid Capacity: " + (int)liquidCapacity);
list.add("[liquidinfo]Generation: " + Strings.toFixed(generatePower / inputLiquid, 3) + "power units/liquid unit"); list.add("[liquidinfo]Generation: " + Strings.toFixed(generatePower / inputLiquid, 2) + " power/liquid");
list.add("[liquidinfo]Input: " + generateLiquid); list.add("[liquidinfo]Input: " + generateLiquid);
} }

View File

@@ -0,0 +1,10 @@
package io.anuke.mindustry.world.blocks.types.production;
public class NuclearReactor extends LiquidItemPowerGenerator{
//TODO make it explode when broken
public NuclearReactor(String name) {
super(name);
}
}

Binary file not shown.