Implemented dynamic ground unit spawning

This commit is contained in:
Anuken 2018-06-20 20:23:43 -04:00
parent 1c80314cfd
commit 45da578756
7 changed files with 121 additions and 17 deletions

View File

@ -79,8 +79,12 @@ public class Pathfinder {
return paths[Team.red.ordinal()].weights[x][y]; return paths[Team.red.ordinal()].weights[x][y];
} }
public float getValueforTeam(Team team, int x, int y){
return paths == null ? 0 : paths[team.ordinal()].weights[x][y];
}
private boolean passable(Tile tile, Team team){ private boolean passable(Tile tile, Team team){
return (tile.getWallID() == 0 && !(tile.floor().isLiquid && (tile.floor().damageTaken > 0 || tile.floor().drownTime > 0))) return (tile.getWallID() == 0 && tile.cliffs == 0 && !(tile.floor().isLiquid && (tile.floor().damageTaken > 0 || tile.floor().drownTime > 0)))
|| (tile.breakable() && (tile.getTeam() != team)) || !tile.solid(); || (tile.breakable() && (tile.getTeam() != team)) || !tile.solid();
} }
@ -173,6 +177,8 @@ public class Pathfinder {
createFor(data.team); createFor(data.team);
} }
state.spawner.checkAllQuadrants();
Log.info("Elapsed calculation time: {0}", Timers.elapsed()); Log.info("Elapsed calculation time: {0}", Timers.elapsed());
} }

View File

@ -1,19 +1,25 @@
package io.anuke.mindustry.ai; package io.anuke.mindustry.ai;
import com.badlogic.gdx.utils.Array; import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.Bits;
import com.badlogic.gdx.utils.IntArray;
import io.anuke.mindustry.content.AmmoTypes; import io.anuke.mindustry.content.AmmoTypes;
import io.anuke.mindustry.content.UnitTypes; import io.anuke.mindustry.content.UnitTypes;
import io.anuke.mindustry.entities.units.BaseUnit; import io.anuke.mindustry.entities.units.BaseUnit;
import io.anuke.mindustry.entities.units.Squad; import io.anuke.mindustry.entities.units.Squad;
import io.anuke.mindustry.game.EventType.WorldLoadEvent; import io.anuke.mindustry.game.EventType.WorldLoadEvent;
import io.anuke.mindustry.game.Team; import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.core.Events; import io.anuke.ucore.core.Events;
import io.anuke.ucore.util.Mathf; import io.anuke.ucore.util.Mathf;
import static io.anuke.mindustry.Vars.*; import static io.anuke.mindustry.Vars.*;
public class WaveSpawner { public class WaveSpawner {
private static final int quadsize = 15; private static final int quadsize = 4;
private Bits quadrants;
private IntArray tmpArray = new IntArray();
private Array<FlyerSpawn> flySpawns = new Array<>(); private Array<FlyerSpawn> flySpawns = new Array<>();
private Array<GroundSpawn> groundSpawns = new Array<>(); private Array<GroundSpawn> groundSpawns = new Array<>();
@ -23,24 +29,45 @@ public class WaveSpawner {
} }
public void spawnEnemies(){ public void spawnEnemies(){
int spawned = 10; int spawned = Math.min(state.wave, 6);
int groundGroups = Math.min(1 + state.wave / 20, 4); int groundGroups = 1 + state.wave / 20;
int flyGroups = Math.min(1 + state.wave / 20, 4); int flyGroups = 1 + state.wave / 20;
//add extra groups if necessary //add extra groups if necessary
for (int i = 0; i < groundGroups - groundSpawns.size; i++) { for (int i = 0; i < groundGroups - groundSpawns.size; i++) {
GroundSpawn spawn = new GroundSpawn(); GroundSpawn spawn = new GroundSpawn();
findLocation(spawn);
groundSpawns.add(spawn);
} }
for (int i = 0; i < flyGroups - flySpawns.size; i++) { for (int i = 0; i < flyGroups - flySpawns.size; i++) {
FlyerSpawn spawn = new FlyerSpawn(); FlyerSpawn spawn = new FlyerSpawn();
spawn.angle = Mathf.random(360f); findLocation(spawn);
flySpawns.add(spawn); flySpawns.add(spawn);
} }
for(GroundSpawn spawn : groundSpawns){ if(state.wave % 20 == 0){
for(FlyerSpawn spawn : flySpawns) findLocation(spawn);
for(GroundSpawn spawn : groundSpawns) findLocation(spawn);
}
for(GroundSpawn spawn : groundSpawns){
checkQuadrant(spawn.x, spawn.y);
if(!getQuad(spawn.x, spawn.y)){
findLocation(spawn);
}
Squad squad = new Squad();
for(int i = 0; i < spawned; i ++){
BaseUnit unit = UnitTypes.scout.create(Team.red);
unit.inventory.addAmmo(AmmoTypes.bulletIron);
unit.setWave();
unit.setSquad(squad);
unit.set(spawn.x * quadsize * tilesize + quadsize * tilesize/2f + Mathf.range(quadsize*tilesize/3f),
spawn.y * quadsize * tilesize + quadsize * tilesize/2f + Mathf.range(quadsize*tilesize/3));
unit.add();
}
} }
for(FlyerSpawn spawn : flySpawns){ for(FlyerSpawn spawn : flySpawns){
@ -62,11 +89,26 @@ public class WaveSpawner {
} }
} }
public void calculateSpawn(){ public void checkAllQuadrants(){
for(int x = 0; x < quadWidth(); x ++){
for(int y = 0; y < quadHeight(); y ++){
checkQuadrant(x, y);
}
}
}
private void checkQuadrant(int quadx, int quady){
setQuad(quadx, quady, true);
for(int x = 0; x < world.width(); x += quadsize){ outer:
for(int y = 0; y < world.height(); y += quadsize){ for (int x = quadx * quadsize; x < world.width() && x < (quadx + 1)*quadsize; x++) {
//TODO quadrant operations, etc for (int y = quady * quadsize; y < world.height() && y < (quady + 1)*quadsize; y++) {
Tile tile = world.tile(x, y);
if(tile.solid() || world.pathfinder().getValueforTeam(Team.red, x, y) == Float.MAX_VALUE){
setQuad(quadx, quady, false);
break outer;
}
} }
} }
} }
@ -74,9 +116,53 @@ public class WaveSpawner {
private void reset(){ private void reset(){
flySpawns.clear(); flySpawns.clear();
groundSpawns.clear(); groundSpawns.clear();
quadrants = new Bits(quadWidth() * quadHeight());
}
private boolean getQuad(int quadx, int quady){
return quadrants.get(quadx + quady * quadWidth());
}
private void setQuad(int quadx, int quady, boolean valid){
if(valid){
quadrants.set(quadx + quady * quadWidth());
}else{
quadrants.clear(quadx + quady * quadWidth());
}
}
private void findLocation(GroundSpawn spawn){
spawn.x = -1;
spawn.y = -1;
int shellWidth = quadWidth()*2 + quadHeight() * 2 * 6;
shellWidth = Math.min(quadWidth() * quadHeight() / 4, shellWidth);
Mathf.traverseSpiral(quadWidth(), quadHeight(), Mathf.random(shellWidth), (x, y) -> {
if(getQuad(x, y)){
spawn.x = x;
spawn.y = y;
return true;
}
return false;
});
}
private void findLocation(FlyerSpawn spawn){
spawn.angle = Mathf.random(360f);
}
private int quadWidth(){
return Mathf.ceil(world.width() / (float)quadsize);
}
private int quadHeight(){
return Mathf.ceil(world.height() / (float)quadsize);
} }
private class FlyerSpawn{ private class FlyerSpawn{
//square angle
float angle; float angle;
FlyerSpawn(){ FlyerSpawn(){
@ -85,6 +171,8 @@ public class WaveSpawner {
} }
private class GroundSpawn{ private class GroundSpawn{
//quadrant spawn coordinates
int x, y;
GroundSpawn(){ GroundSpawn(){

View File

@ -24,7 +24,7 @@ public class UnitTypes implements ContentList {
scout = new UnitType("scout", team -> new Scout(scout, team)){{ scout = new UnitType("scout", team -> new Scout(scout, team)){{
maxVelocity = 1.1f; maxVelocity = 1.1f;
speed = 0.1f; speed = 0.2f;
drag = 0.4f; drag = 0.4f;
range = 40f; range = 40f;
setAmmo(AmmoTypes.bulletIron); setAmmo(AmmoTypes.bulletIron);

View File

@ -251,7 +251,7 @@ public abstract class Unit extends DestructibleEntity implements SaveTrait, Targ
drownTime = Mathf.clamp(drownTime); drownTime = Mathf.clamp(drownTime);
if(drownTime >= 1f){ if(drownTime >= 1f){
damage(health + 1, false); damage(health + 1);
} }
float px = x, py = y; float px = x, py = y;

View File

@ -111,6 +111,7 @@ public abstract class GroundUnit extends BaseUnit {
protected void moveToCore(){ protected void moveToCore(){
Tile tile = world.tileWorld(x, y); Tile tile = world.tileWorld(x, y);
if(tile == null) return;
Tile targetTile = world.pathfinder().getTargetTile(team, tile); Tile targetTile = world.pathfinder().getTargetTile(team, tile);
if(tile == targetTile) return; if(tile == targetTile) return;
@ -150,7 +151,7 @@ public abstract class GroundUnit extends BaseUnit {
} }
//TODO move toward resupply point //TODO move toward resupply point
if(inventory.totalAmmo() + 10 >= inventory.ammoCapacity()){ if(isWave || inventory.totalAmmo() + 10 >= inventory.ammoCapacity()){
state.set(attack); state.set(attack);
} }
} }

View File

@ -2,6 +2,7 @@ package io.anuke.mindustry.ui.fragments;
import com.badlogic.gdx.Gdx; import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle; import com.badlogic.gdx.files.FileHandle;
import io.anuke.mindustry.content.AmmoTypes;
import io.anuke.mindustry.content.UnitTypes; import io.anuke.mindustry.content.UnitTypes;
import io.anuke.mindustry.content.bullets.TurretBullets; import io.anuke.mindustry.content.bullets.TurretBullets;
import io.anuke.mindustry.entities.Player; import io.anuke.mindustry.entities.Player;
@ -79,6 +80,8 @@ public class DebugFragment implements Fragment {
new button("spawng", () ->{ new button("spawng", () ->{
BaseUnit unit = UnitTypes.scout.create(player.getTeam()); BaseUnit unit = UnitTypes.scout.create(player.getTeam());
unit.set(player.x, player.y); unit.set(player.x, player.y);
unit.inventory.addAmmo(AmmoTypes.bulletIron);
unit.setWave();
unit.add(); unit.add();
}); });
row(); row();

View File

@ -1,5 +1,6 @@
package io.anuke.mindustry.world.mapgen; package io.anuke.mindustry.world.mapgen;
import com.badlogic.gdx.math.Vector2;
import io.anuke.mindustry.content.blocks.Blocks; import io.anuke.mindustry.content.blocks.Blocks;
import io.anuke.mindustry.content.blocks.StorageBlocks; import io.anuke.mindustry.content.blocks.StorageBlocks;
import io.anuke.mindustry.game.Team; import io.anuke.mindustry.game.Team;
@ -30,11 +31,16 @@ public class ProcGen {
double r = sim2.octaveNoise2D(1, 0.6, 1f/70, x, y); double r = sim2.octaveNoise2D(1, 0.6, 1f/70, x, y);
double elevation = sim.octaveNoise2D(3, 0.5, 1f/70, x, y) * 4 - 1.2; double elevation = sim.octaveNoise2D(3, 0.5, 1f/70, x, y) * 4 - 1.2;
double edgeDist = Math.max(data.width()/2, data.height()/2) - Math.max(Math.abs(x - data.width()/2), Math.abs(y - data.height()/2)); double edgeDist = Math.max(data.width()/2, data.height()/2) - Math.max(Math.abs(x - data.width()/2), Math.abs(y - data.height()/2));
double dst = Vector2.dst(data.width()/2, data.height()/2, x, y);
double border = 10; double border = 14;
if(edgeDist < border){ if(edgeDist < border){
elevation += (border - edgeDist)/4.0; elevation += (border - edgeDist)/6.0;
}
if(dst < 20){
elevation = 0;
} }
if(r > 0.9){ if(r > 0.9){