Major refactoring; implemented multi-frame pathfinding

This commit is contained in:
Anuken
2017-11-26 18:59:03 -05:00
parent 25952985dd
commit 07ac552495
60 changed files with 767 additions and 498 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 223 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 248 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 194 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 207 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 206 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 237 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 238 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 241 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 237 B

After

Width:  |  Height:  |  Size: 237 B

View File

Before

Width:  |  Height:  |  Size: 218 B

After

Width:  |  Height:  |  Size: 218 B

View File

Before

Width:  |  Height:  |  Size: 235 B

After

Width:  |  Height:  |  Size: 235 B

View File

Before

Width:  |  Height:  |  Size: 236 B

After

Width:  |  Height:  |  Size: 236 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 189 B

After

Width:  |  Height:  |  Size: 189 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 189 B

After

Width:  |  Height:  |  Size: 189 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 219 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 214 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 216 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 215 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 208 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 208 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

After

Width:  |  Height:  |  Size: 49 KiB

View File

@ -9,6 +9,7 @@ import io.anuke.mindustry.core.*;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.io.Formatter;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.World;
import io.anuke.mindustry.world.blocks.*;
import io.anuke.ucore.core.Inputs;
import io.anuke.ucore.core.Timers;
@ -41,6 +42,7 @@ public class Mindustry extends ModuleCore {
@Override
public void init(){
module(Vars.world = new World());
module(Vars.control = new Control());
module(Vars.renderer = new Renderer());
module(Vars.ui = new UI());

View File

@ -7,6 +7,7 @@ import io.anuke.mindustry.core.Control;
import io.anuke.mindustry.core.Renderer;
import io.anuke.mindustry.core.UI;
import io.anuke.mindustry.entities.Player;
import io.anuke.mindustry.world.World;
import io.anuke.ucore.scene.ui.layout.Unit;
public class Vars{
@ -59,6 +60,7 @@ public class Vars{
public static Control control;
public static Renderer renderer;
public static UI ui;
public static World world;
public static Player player;

View File

@ -4,7 +4,6 @@ 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
@ -23,7 +22,7 @@ public class MHueristic implements Heuristic<Tile>{
if(other.breakable() && other.block().solid) cost += Vars.tilesize*multiplier;
for(int dx = -1; dx <= 1; dx ++){
for(int dy = -1; dy <= 1; dy ++){
Tile tile = World.tile(node.x + dx, node.y + dy);
Tile tile = Vars.world.tile(node.x + dx, node.y + dy);
if(tile != null && tile.solid()){
cost += Vars.tilesize*5;
}

View File

@ -4,8 +4,8 @@ import com.badlogic.gdx.ai.pfa.Connection;
import com.badlogic.gdx.ai.pfa.indexed.IndexedGraph;
import com.badlogic.gdx.utils.Array;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.World;
/**Tilegraph that ignores player-made tiles.*/
public class PassTileGraph implements IndexedGraph<Tile>{
private Array<Connection<Tile>> tempConnections = new Array<Connection<Tile>>();
@ -27,11 +27,11 @@ public class PassTileGraph implements IndexedGraph<Tile>{
@Override
public int getIndex(Tile node){
return node.x+node.y*World.worldsize;
return node.id();
}
@Override
public int getNodeCount(){
return World.worldsize*World.worldsize;
return Vars.world.width() * Vars.world.height();
}
}

View File

@ -1,40 +1,41 @@
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.SpawnPoint;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.World;
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 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();
private static final long ms = 1000000;
static public Vector2 find(Enemy enemy){
MHueristic heuristic = new MHueristic();
PassTileGraph graph = new PassTileGraph();
PathSmoother<Tile, Vector2> smoother = new PathSmoother<Tile, Vector2>(new Raycaster());
Vector2 vector = new Vector2();
public Vector2 find(Enemy enemy){
if(enemy.node == -1){
findNode(enemy);
}
if(enemy.path == null){
return vector.set(enemy.x, enemy.y);
}
//-1 is only possible here if both pathfindings failed, which should NOT happen
//check graph code
Tile[] path = enemy.path;
//REPRODUCE BUG: load in test map, then load save 1
//REPRODUCE BUG: load in test map, then load save 1?
Tile prev = path[enemy.node - 1];
Tile target = path[enemy.node];
@ -77,19 +78,41 @@ public class Pathfind{
}
static public void reset(){
paths.clear();
pathSequences = null;
passpathfinder = new IndexedAStarPathFinder<Tile>(passgraph);
public void update(){
for(SpawnPoint point : Vars.control.getSpawnPoints()){
if(!point.request.pathFound){
if(point.finder.search(point.request, ms*2)){
smoother.smoothPath(point.path);
point.pathTiles = point.path.nodes.toArray(Tile.class);
}
}
}
}
static public void updatePath(){
public void updatePath(){
for(SpawnPoint point : Vars.control.getSpawnPoints()){
if(point.finder == null){
point.finder = new IndexedAStarPathFinder<Tile>(graph);
}
point.path.clear();
point.pathTiles = null;
point.request = new PathFinderRequest<Tile>(point.start, Vars.control.getCore(), heuristic, point.path);
point.request.statusChanged = true; //IMPORTANT!
}
/*
if(paths.size == 0 || paths.size != World.spawnpoints.size){
paths.clear();
finders.clear();
pathSequences = new Tile[World.spawnpoints.size][0];
for(int i = 0; i < World.spawnpoints.size; i ++){
SmoothGraphPath path = new SmoothGraphPath();
paths.add(path);
finders.add(new IndexedAStarPathFinder(graph));
}
}
@ -97,7 +120,7 @@ public class Pathfind{
SmoothGraphPath path = paths.get(i);
path.clear();
passpathfinder.searchNodePath(
finders.get(i).searchNodePath(
World.spawnpoints.get(i),
World.core, heuristic, path);
@ -117,11 +140,15 @@ public class Pathfind{
Effects.effect(Fx.ind, tile.worldx(), tile.worldy());
}
}
}*/
}
static void findNode(Enemy enemy){
enemy.path = pathSequences[enemy.spawn];
void findNode(Enemy enemy){
if(Vars.control.getSpawnPoints().get(enemy.spawn).pathTiles == null){
return;
}
enemy.path = Vars.control.getSpawnPoints().get(enemy.spawn).pathTiles;
Tile[] path = enemy.path;
Tile closest = null;
float ldst = 0f;

View File

@ -7,7 +7,6 @@ import com.badlogic.gdx.math.Vector2;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.World;
import io.anuke.ucore.util.Geometry;
import io.anuke.ucore.util.Mathf;
@ -72,7 +71,7 @@ public class Raycaster implements RaycastCollisionDetector<Vector2>{
}
private boolean solid(float x, float y){
Tile tile = World.tile(Mathf.scl2(x, Vars.tilesize), Mathf.scl2(y, Vars.tilesize));
Tile tile = Vars.world.tile(Mathf.scl2(x, Vars.tilesize), Mathf.scl2(y, Vars.tilesize));
if(tile == null || tile.solid()) return true;

View File

@ -13,7 +13,6 @@ import com.badlogic.gdx.utils.reflect.Constructor;
import io.anuke.mindustry.Mindustry;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.ai.Pathfind;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.entities.*;
import io.anuke.mindustry.entities.effect.Fx;
@ -53,6 +52,9 @@ public class Control extends Module{
float extrawavetime;
int enemies = 0;
Tile core;
Array<SpawnPoint> spawnpoints = new Array<>();
float respawntime;
public Control(){
@ -87,8 +89,6 @@ public class Control extends Module{
Musics.load("1.mp3", "2.mp3", "3.mp3", "4.mp3");
World.loadMaps();
KeyBinds.defaults(
"up", Keys.W,
"left", Keys.A,
@ -178,7 +178,7 @@ public class Control extends Module{
player.heal();
clearItems();
World.spawnpoints.clear();
spawnpoints.clear();
respawntime = -1;
hiscore = false;
@ -189,8 +189,8 @@ public class Control extends Module{
public void play(){
Vars.renderer.clearTiles();
player.x = World.core.worldx();
player.y = World.core.worldy() - Vars.tilesize*2 - ((int)(Gdx.graphics.getWidth() / (float)Core.cameraScale * 2) % 2 == 0 ? 0.5f : 0);
player.x = core.worldx();
player.y = core.worldy() - Vars.tilesize*2 - ((int)(Gdx.graphics.getWidth() / (float)Core.cameraScale * 2) % 2 == 0 ? 0.5f : 0);
Core.camera.position.set(player.x, player.y, 0);
@ -200,17 +200,35 @@ public class Control extends Module{
GameState.set(State.playing);
}
public Tile getCore(){
return core;
}
public Array<SpawnPoint> getSpawnPoints(){
return spawnpoints;
}
public void setCore(Tile tile){
this.core = tile;
}
public void addSpawnPoint(Tile tile){
SpawnPoint point = new SpawnPoint();
point.start = tile;
spawnpoints.add(point);
}
public void playMap(Map map){
Vars.ui.showLoading();
Timers.run(16, ()->{
Vars.control.reset();
World.loadMap(map);
Vars.control.play();
reset();
world.loadMap(map);
play();
});
Timers.run(18, ()->{
Vars.ui.hideLoading();
ui.hideLoading();
});
}
@ -236,12 +254,12 @@ public class Control extends Module{
public void runWave(){
Sounds.play("spawn");
Pathfind.updatePath();
world.pathfinder().updatePath();
for(EnemySpawn spawn : spawns){
for(int lane = 0; lane < World.spawnpoints.size; lane ++){
for(int lane = 0; lane < spawnpoints.size; lane ++){
int fl = lane;
Tile tile = World.spawnpoints.get(lane);
Tile tile = spawnpoints.get(lane).start;
int spawnamount = spawn.evaluate(wave, lane);
for(int i = 0; i < spawnamount; i ++){
@ -268,10 +286,10 @@ public class Control extends Module{
wave ++;
int last = Settings.getInt("hiscore" + World.getMap().name());
int last = Settings.getInt("hiscore" + world.getMap().name());
if(wave > last){
Settings.putInt("hiscore" + World.getMap().name(), wave);
Settings.putInt("hiscore" + world.getMap().name(), wave);
Settings.save();
hiscore = true;
}
@ -301,7 +319,6 @@ public class Control extends Module{
public void coreDestroyed(){
Effects.shake(5, 6, Core.camera.position.x, Core.camera.position.y);
Sounds.play("corexplode");
Tile core = World.core;
for(int i = 0; i < 16; i ++){
Timers.run(i*2, ()->{
Effects.effect(Fx.explosion, core.worldx()+Mathf.range(40), core.worldy()+Mathf.range(40));
@ -401,7 +418,7 @@ public class Control extends Module{
Entities.initPhysics();
Entities.setCollider(tilesize, (x, y)->{
return World.solid(x, y);
return world.solid(x, y);
});
}
@ -454,7 +471,7 @@ public class Control extends Module{
respawntime -= delta();
if(respawntime <= 0){
player.set(World.core.worldx(), World.core.worldy()-Vars.tilesize*2);
player.set(core.worldx(), core.worldy()-Vars.tilesize*2);
player.heal();
player.add();
Effects.sound("respawn");
@ -497,10 +514,5 @@ public class Control extends Module{
}
}
}
@Override
public void dispose(){
World.disposeMaps();
}
}

View File

@ -20,8 +20,8 @@ import io.anuke.mindustry.entities.enemies.Enemy;
import io.anuke.mindustry.input.AndroidInput;
import io.anuke.mindustry.input.Input;
import io.anuke.mindustry.input.PlaceMode;
import io.anuke.mindustry.world.SpawnPoint;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.World;
import io.anuke.mindustry.world.blocks.Blocks;
import io.anuke.mindustry.world.blocks.ProductionBlocks;
import io.anuke.ucore.UCore;
@ -80,7 +80,7 @@ public class Renderer extends RendererModule{
}else{
boolean smoothcam = Settings.getBool("smoothcam");
if(World.core.block() == ProductionBlocks.core){
if(control.core.block() == ProductionBlocks.core){
if(!smoothcam){
setCamera(player.x, player.y);
@ -88,7 +88,7 @@ public class Renderer extends RendererModule{
smoothCamera(player.x, player.y, android ? 0.3f : 0.14f);
}
}else{
smoothCamera(World.core.worldx(), World.core.worldy(), 0.4f);
smoothCamera(control.core.worldx(), control.core.worldy(), 0.4f);
}
if(Settings.getBool("pixelate"))
@ -98,7 +98,8 @@ public class Renderer extends RendererModule{
updateShake(0.75f);
float prevx = camera.position.x, prevy = camera.position.y;
clampCamera(-tilesize / 2f, -tilesize / 2f + 1, World.pixsize - tilesize / 2f, World.pixsize - tilesize / 2f);
clampCamera(-tilesize / 2f, -tilesize / 2f + 1, world.width() * tilesize - tilesize / 2f,
world.height() * tilesize - tilesize / 2f);
float deltax = camera.position.x - prex, deltay = camera.position.y - prey;
@ -212,7 +213,7 @@ public class Renderer extends RendererModule{
}
void renderTiles(){
int chunksx = World.width() / chunksize, chunksy = World.height() / chunksize;
int chunksx = world.width() / chunksize, chunksy = world.height() / chunksize;
//render the entire map
if(floorCache == null || floorCache.length != chunksx || floorCache[0].length != chunksy){
@ -271,11 +272,11 @@ public class Renderer extends RendererModule{
int worldx = Mathf.scl(camera.position.x, tilesize) + x;
int worldy = Mathf.scl(camera.position.y, tilesize) + y;
if(World.tile(worldx, worldy) != null){
Tile tile = World.tile(worldx, worldy);
if(world.tile(worldx, worldy) != null){
Tile tile = world.tile(worldx, worldy);
if(l == 0){
if(tile.block() != Blocks.air && World.isAccessible(worldx, worldy)){
Draw.rect(tile.block().shadow, worldx * tilesize, worldy * tilesize);
if(tile.block() != Blocks.air && world.isAccessible(worldx, worldy)){
tile.block().drawShadow(tile);
}
}else if(l == 1){
tile.block().draw(tile);
@ -315,7 +316,7 @@ public class Renderer extends RendererModule{
for(int tilex = cx * chunksize; tilex < (cx + 1) * chunksize; tilex++){
for(int tiley = cy * chunksize; tiley < (cy + 1) * chunksize; tiley++){
Tile tile = World.tile(tilex, tiley);
Tile tile = world.tile(tilex, tiley);
tile.floor().drawCache(tile);
}
@ -332,8 +333,8 @@ public class Renderer extends RendererModule{
//draw tutorial placement point
if(Vars.control.tutorial.showBlock()){
int x = World.core.x + Vars.control.tutorial.getPlacePoint().x;
int y = World.core.y + Vars.control.tutorial.getPlacePoint().y;
int x = control.core.x + Vars.control.tutorial.getPlacePoint().x;
int y = control.core.y + Vars.control.tutorial.getPlacePoint().y;
int rot = Vars.control.tutorial.getPlaceRotation();
Draw.thick(1f);
@ -368,7 +369,7 @@ public class Renderer extends RendererModule{
x = tilex * tilesize;
y = tiley * tilesize;
boolean valid = World.validPlace(tilex, tiley, player.recipe.result) && (android || Input.cursorNear());
boolean valid = world.validPlace(tilex, tiley, player.recipe.result) && (android || Input.cursorNear());
Vector2 offset = player.recipe.result.getPlaceOffset();
@ -388,8 +389,8 @@ public class Renderer extends RendererModule{
Draw.thickness(1f);
Draw.color("scarlet");
for(Tile spawn : World.spawnpoints){
Draw.dashcircle(spawn.worldx(), spawn.worldy(), enemyspawnspace);
for(SpawnPoint spawn : control.getSpawnPoints()){
Draw.dashcircle(spawn.start.worldx(), spawn.start.worldy(), enemyspawnspace);
}
if(valid)
@ -401,8 +402,8 @@ public class Renderer extends RendererModule{
}
//block breaking
if(Inputs.buttonDown(Buttons.RIGHT) && World.validBreak(Input.tilex(), Input.tiley())){
Tile tile = World.tile(Input.tilex(), Input.tiley());
if(Inputs.buttonDown(Buttons.RIGHT) && world.validBreak(Input.tilex(), Input.tiley())){
Tile tile = world.tile(Input.tilex(), Input.tiley());
if(tile.isLinked())
tile = tile.getLinked();
Vector2 offset = tile.block().getPlaceOffset();
@ -413,8 +414,8 @@ public class Renderer extends RendererModule{
}else if(android && player.breaktime > 0){ //android block breaking
Vector2 vec = Graphics.world(Gdx.input.getX(0), Gdx.input.getY(0));
if(World.validBreak(Mathf.scl2(vec.x, tilesize), Mathf.scl2(vec.y, tilesize))){
Tile tile = World.tile(Mathf.scl2(vec.x, tilesize), Mathf.scl2(vec.y, tilesize));
if(world.validBreak(Mathf.scl2(vec.x, tilesize), Mathf.scl2(vec.y, tilesize))){
Tile tile = world.tile(Mathf.scl2(vec.x, tilesize), Mathf.scl2(vec.y, tilesize));
float fract = player.breaktime / tile.getBreakTime();
Draw.color(Color.YELLOW, Color.SCARLET, fract);
@ -425,7 +426,7 @@ public class Renderer extends RendererModule{
//draw selected block health
if(player.recipe == null && !ui.hasMouse()){
Tile tile = World.tile(Input.tilex(), Input.tiley());
Tile tile = world.tile(Input.tilex(), Input.tiley());
if(tile != null && tile.block() != Blocks.air){
Tile target = tile;

View File

@ -1,12 +1,16 @@
package io.anuke.mindustry.core;
import static io.anuke.mindustry.Vars.*;
import com.badlogic.gdx.math.GridPoint2;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.resource.Item;
import io.anuke.mindustry.resource.Weapon;
import io.anuke.mindustry.world.*;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Map;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.*;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.scene.builders.button;
@ -29,7 +33,7 @@ public class Tutorial{
}
public boolean active(){
return World.getMap() == Map.tutorial && !GameState.is(State.menu);
return world.getMap() == Map.tutorial && !GameState.is(State.menu);
}
public void buildUI(table table){
@ -71,7 +75,7 @@ public class Tutorial{
//info.setText(stage.text);
if(stage.showBlock){
Tile tile = World.tile(World.core.x + stage.blockPlaceX, World.core.y + stage.blockPlaceY);
Tile tile = world.tile(control.core.x + stage.blockPlaceX, control.core.y + stage.blockPlaceY);
if(tile.block() == stage.targetBlock && (tile.rotation == stage.blockRotation || stage.blockRotation == -1)){
move(true);
@ -151,9 +155,9 @@ public class Tutorial{
}
public void setDefaultBlocks(int corex, int corey){
World.tile(corex, corey - 1).setBlock(Blocks.air);
World.tile(corex, corey - 2).setBlock(Blocks.air);
World.tile(corex, corey - 2).setFloor(Blocks.stone);
world.tile(corex, corey - 1).setBlock(Blocks.air);
world.tile(corex, corey - 2).setBlock(Blocks.air);
world.tile(corex, corey - 2).setFloor(Blocks.stone);
}
enum Stage{
@ -288,11 +292,11 @@ public class Tutorial{
void onSwitch(){
for(int flip : new int[]{1, -1}){
World.tile(World.core.x + flip, World.core.y - 1).setBlock(DistributionBlocks.conveyor, 2 * flip);
World.tile(World.core.x + flip*2, World.core.y - 1).setBlock(DistributionBlocks.conveyor, 2 * flip);
World.tile(World.core.x + flip*2, World.core.y - 2).setBlock(DistributionBlocks.conveyor, 1);
World.tile(World.core.x + flip*2, World.core.y - 3).setFloor(Blocks.stone);
World.tile(World.core.x + flip*2, World.core.y - 3).setBlock(ProductionBlocks.stonedrill);
world.tile(control.core.x + flip, control.core.y - 1).setBlock(DistributionBlocks.conveyor, 2 * flip);
world.tile(control.core.x + flip*2, control.core.y - 1).setBlock(DistributionBlocks.conveyor, 2 * flip);
world.tile(control.core.x + flip*2, control.core.y - 2).setBlock(DistributionBlocks.conveyor, 1);
world.tile(control.core.x + flip*2, control.core.y - 3).setFloor(Blocks.stone);
world.tile(control.core.x + flip*2, control.core.y - 3).setBlock(ProductionBlocks.stonedrill);
}
}
@ -463,7 +467,7 @@ public class Tutorial{
void onSwitch(){
Vars.ui.<ImageButton>find("sectionbuttondistribution").fireClick();
World.tile(blockPlaceX + World.core.x, blockPlaceY + World.core.y).setBlock(Blocks.air);
world.tile(blockPlaceX + control.core.x, blockPlaceY + control.core.y).setBlock(Blocks.air);
}
},
conduitUse2{
@ -480,7 +484,7 @@ public class Tutorial{
}
void onSwitch(){
World.tile(blockPlaceX + World.core.x, blockPlaceY + World.core.y).setBlock(Blocks.air);
world.tile(blockPlaceX + control.core.x, blockPlaceY + control.core.y).setBlock(Blocks.air);
}
},
conduitUse3{
@ -497,7 +501,7 @@ public class Tutorial{
}
void onSwitch(){
World.tile(blockPlaceX + World.core.x, blockPlaceY + World.core.y).setBlock(Blocks.air);
world.tile(blockPlaceX + control.core.x, blockPlaceY + control.core.y).setBlock(Blocks.air);
}
},
extractor{
@ -513,7 +517,7 @@ public class Tutorial{
}
void onSwitch(){
World.tile(blockPlaceX + World.core.x, blockPlaceY + World.core.y).setBlock(Blocks.air);
world.tile(blockPlaceX + control.core.x, blockPlaceY + control.core.y).setBlock(Blocks.air);
Vars.ui.<ImageButton>find("sectionbuttonproduction").fireClick();
Vars.control.addItem(Item.steel, 60);
Vars.control.addItem(Item.iron, 60);
@ -527,19 +531,19 @@ public class Tutorial{
void onSwitch(){
for(int i = -2; i <= 2; i ++){
World.tile(World.core.x + i + 4, World.core.y + 2).setBlock(ProductionBlocks.stonedrill);
World.tile(World.core.x + i + 4, World.core.y + 2).setFloor(Blocks.stone);
world.tile(control.core.x + i + 4, control.core.y + 2).setBlock(ProductionBlocks.stonedrill);
world.tile(control.core.x + i + 4, control.core.y + 2).setFloor(Blocks.stone);
}
for(int i = 0; i < 3; i ++){
World.tile(World.core.x + 4 - 1 - i, World.core.y).setBlock(DistributionBlocks.conveyor, 2);
world.tile(control.core.x + 4 - 1 - i, control.core.y).setBlock(DistributionBlocks.conveyor, 2);
}
World.tile(World.core.x + 2, World.core.y + 1).setBlock(DistributionBlocks.conveyor, 0);
World.tile(World.core.x + 3, World.core.y + 1).setBlock(DistributionBlocks.conveyor, 0);
World.tile(World.core.x + 4, World.core.y + 1).setBlock(DistributionBlocks.conveyor, 3);
World.tile(World.core.x + 5, World.core.y + 1).setBlock(DistributionBlocks.conveyor, 2);
World.tile(World.core.x + 6, World.core.y + 1).setBlock(DistributionBlocks.conveyor, 2);
world.tile(control.core.x + 2, control.core.y + 1).setBlock(DistributionBlocks.conveyor, 0);
world.tile(control.core.x + 3, control.core.y + 1).setBlock(DistributionBlocks.conveyor, 0);
world.tile(control.core.x + 4, control.core.y + 1).setBlock(DistributionBlocks.conveyor, 3);
world.tile(control.core.x + 5, control.core.y + 1).setBlock(DistributionBlocks.conveyor, 2);
world.tile(control.core.x + 6, control.core.y + 1).setBlock(DistributionBlocks.conveyor, 2);
}
},

View File

@ -2,8 +2,8 @@ package io.anuke.mindustry.entities;
import static io.anuke.mindustry.Vars.tilesize;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.World;
import io.anuke.ucore.entities.*;
import io.anuke.ucore.util.Mathf;
@ -29,7 +29,7 @@ public class Bullet extends BulletEntity{
int tilex = Mathf.scl2(x, tilesize);
int tiley = Mathf.scl2(y, tilesize);
Tile tile = World.tile(tilex, tiley);
Tile tile = Vars.world.tile(tilex, tiley);
TileEntity targetEntity = null;
if(tile != null){

View File

@ -5,7 +5,6 @@ import com.badlogic.gdx.math.Vector2;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.entities.enemies.Enemy;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.World;
import io.anuke.ucore.entities.Entities;
import io.anuke.ucore.util.Mathf;
@ -29,7 +28,7 @@ public class DamageArea{
int trad = (int)(radius / Vars.tilesize);
for(int dx = -trad; dx <= trad; dx ++){
for(int dy= -trad; dy <= trad; dy ++){
Tile tile = World.tile(Mathf.scl2(x, Vars.tilesize) + dx, Mathf.scl2(y, Vars.tilesize) + dy);
Tile tile = Vars.world.tile(Mathf.scl2(x, Vars.tilesize) + dx, Mathf.scl2(y, Vars.tilesize) + dy);
if(tile != null && tile.entity != null && Vector2.dst(dx, dy, 0, 0) <= trad){
int amount = calculateDamage(x, y, tile.worldx(), tile.worldy(), radius, damage);
tile.entity.damage(amount);

View File

@ -6,7 +6,6 @@ import com.badlogic.gdx.utils.Array;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.World;
import io.anuke.mindustry.world.blocks.types.PowerAcceptor;
import io.anuke.ucore.core.Draw;
import io.anuke.ucore.core.Effects;
@ -36,7 +35,7 @@ public class EMP extends TimedEntity{
for(int dx = -radius; dx <= radius; dx ++){
for(int dy = -radius; dy <= radius; dy ++){
if(Vector2.dst(dx, dy, 0, 0) < radius){
Tile tile = World.tile(worldx + dx, worldy + dy);
Tile tile = Vars.world.tile(worldx + dx, worldy + dy);
if(tile != null && tile.block().destructible){
array.add(tile);

View File

@ -5,14 +5,12 @@ import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.reflect.ClassReflection;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.ai.Pathfind;
import io.anuke.mindustry.entities.Bullet;
import io.anuke.mindustry.entities.BulletType;
import io.anuke.mindustry.entities.Player;
import io.anuke.mindustry.entities.effect.Fx;
import io.anuke.mindustry.entities.effect.Shaders;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.World;
import io.anuke.ucore.core.*;
import io.anuke.ucore.entities.*;
import io.anuke.ucore.util.Mathf;
@ -57,15 +55,17 @@ public class Enemy extends DestructibleEntity{
}
void move(){
boolean nearCore = distanceTo(World.core.worldx(), World.core.worldy()) <= range - 18f;
Tile core = Vars.control.getCore();
boolean nearCore = distanceTo(core.worldx(), core.worldy()) <= range - 18f;
Vector2 vec;
if(nearCore){
vec = Tmp.v2.setZero();
target = World.core.entity;
target = core.entity;
}else{
vec = Pathfind.find(this);
vec = Vars.world.pathfinder().find(this);
vec.sub(x, y).setLength(speed);
}
@ -94,8 +94,13 @@ public class Enemy extends DestructibleEntity{
move(vec.x * Timers.delta(), vec.y * Timers.delta());
updateTargeting(nearCore);
}
void updateTargeting(boolean nearCore){
if(Timers.get(this, "target", 15) && !nearCore){
target = World.findTileTarget(x, y, null, range, false);
target = Vars.world.findTileTarget(x, y, null, range, false);
//no tile found
if(target == null){
@ -126,7 +131,7 @@ public class Enemy extends DestructibleEntity{
}
public void findClosestNode(){
Pathfind.find(this);
Vars.world.pathfinder().find(this);
int index = 0;
int cindex = -1;
@ -150,7 +155,7 @@ public class Enemy extends DestructibleEntity{
int x2 = path[node].x, y2 = path[node].y;
//if the enemy can't move to that node right now, set its position to it
if(World.raycast(Mathf.scl2(x, Vars.tilesize), Mathf.scl2(y, Vars.tilesize), x2, y2) != null){
if(Vars.world.raycast(Mathf.scl2(x, Vars.tilesize), Mathf.scl2(y, Vars.tilesize), x2, y2) != null){
Timers.run(Mathf.random(15f), () -> {
set(x2 * Vars.tilesize, y2 * Vars.tilesize);
});

View File

@ -1,11 +1,11 @@
package io.anuke.mindustry.entities.enemies;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Vector2;
import io.anuke.mindustry.ai.Pathfind;
import io.anuke.mindustry.entities.BulletType;
import io.anuke.mindustry.entities.effect.Shaders;
import io.anuke.ucore.core.Draw;
import io.anuke.ucore.core.Graphics;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.entities.Entities;
import io.anuke.ucore.graphics.Hue;
@ -28,12 +28,7 @@ public class HealerEnemy extends Enemy{
}
@Override
void move(){
Vector2 vec = Pathfind.find(this);
vec.sub(x, y).setLength(speed);
move(vec.x*Timers.delta(), vec.y*Timers.delta());
void updateTargeting(boolean nearCore){
if(Timers.get(this, "target", 15)){
target = Entities.getClosest(Entities.getGroup(Enemy.class),
x, y, range, e -> e instanceof Enemy && e != this && ((Enemy)e).healthfrac() < 1f);
@ -62,12 +57,14 @@ public class HealerEnemy extends Enemy{
Angles.translation(this.angleTo(enemy), 5f);
Graphics.shader();
if(enemy != null && enemy.health < enemy.maxhealth){
Draw.color(Hue.rgb(138, 244, 138, (MathUtils.sin(Timers.time()) + 1f) / 13f));
Draw.alpha(0.9f);
Draw.laser("laser", "laserend", x + Angles.x(), y + Angles.y(), enemy.x - Angles.x()/1.5f, enemy.y - Angles.y()/1.5f);
Draw.color();
}
Graphics.shader(Shaders.outline);
}
}

View File

@ -10,7 +10,6 @@ import com.badlogic.gdx.math.Vector2;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.resource.ItemStack;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.World;
import io.anuke.ucore.core.Graphics;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.scene.ui.layout.Unit;
@ -51,7 +50,7 @@ public class AndroidInput extends InputAdapter{
public static Tile selected(){
Vector2 vec = Graphics.world(mousex, mousey);
return World.tile(Mathf.scl2(vec.x, tilesize), Mathf.scl2(vec.y, tilesize));
return Vars.world.tile(Mathf.scl2(vec.x, tilesize), Mathf.scl2(vec.y, tilesize));
}
public static void breakBlock(){
@ -60,7 +59,7 @@ public class AndroidInput extends InputAdapter{
if(player.breaktime >= tile.block().breaktime){
brokeBlock = true;
World.breakBlock(tile.x, tile.y);
Vars.world.breakBlock(tile.x, tile.y);
player.breaktime = 0f;
}
}
@ -72,9 +71,9 @@ public class AndroidInput extends InputAdapter{
int tiley = Mathf.scl2(vec.y, tilesize);
if(player.recipe != null &&
World.validPlace(tilex, tiley, player.recipe.result)){
Vars.world.validPlace(tilex, tiley, player.recipe.result)){
World.placeBlock(tilex, tiley, player.recipe.result, player.rotation);
Vars.world.placeBlock(tilex, tiley, player.recipe.result, player.rotation);
for(ItemStack stack : player.recipe.requirements){
Vars.control.removeItem(stack);
@ -97,7 +96,7 @@ public class AndroidInput extends InputAdapter{
if(sel == null) return;
if(warmup > warmupDelay && World.validBreak(sel.x, sel.y)){
if(warmup > warmupDelay && Vars.world.validBreak(sel.x, sel.y)){
player.breaktime += Timers.delta();
if(player.breaktime > selected().block().breaktime){

View File

@ -10,7 +10,6 @@ import io.anuke.mindustry.Vars;
import io.anuke.mindustry.resource.ItemStack;
import io.anuke.mindustry.resource.Weapon;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.World;
import io.anuke.mindustry.world.blocks.types.Configurable;
import io.anuke.ucore.core.Graphics;
import io.anuke.ucore.core.Inputs;
@ -46,13 +45,13 @@ public class Input{
}
}
Tile cursor = World.tile(tilex(), tiley());
Tile cursor = Vars.world.tile(tilex(), tiley());
if(Inputs.buttonUp(Buttons.LEFT) && player.recipe != null &&
World.validPlace(tilex(), tiley(), player.recipe.result) && !ui.hasMouse() && cursorNear() &&
Vars.world.validPlace(tilex(), tiley(), player.recipe.result) && !ui.hasMouse() && cursorNear() &&
Vars.control.hasItems(player.recipe.requirements)){
World.placeBlock(tilex(), tiley(), player.recipe.result, player.rotation);
Vars.world.placeBlock(tilex(), tiley(), player.recipe.result, player.rotation);
for(ItemStack stack : player.recipe.requirements){
Vars.control.removeItem(stack);
@ -80,11 +79,11 @@ public class Input{
}
//block breaking
if(Inputs.buttonDown(Buttons.RIGHT) && cursor != null && World.validBreak(tilex(), tiley())){
if(Inputs.buttonDown(Buttons.RIGHT) && cursor != null && Vars.world.validBreak(tilex(), tiley())){
Tile tile = cursor;
player.breaktime += Timers.delta();
if(player.breaktime >= tile.getBreakTime()){
World.breakBlock(cursor.x, cursor.y);
Vars.world.breakBlock(cursor.x, cursor.y);
player.breaktime = 0f;
}
}else{

View File

@ -19,7 +19,9 @@ import io.anuke.mindustry.Vars;
import io.anuke.mindustry.entities.enemies.*;
import io.anuke.mindustry.resource.Item;
import io.anuke.mindustry.resource.Weapon;
import io.anuke.mindustry.world.*;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Map;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.Blocks;
import io.anuke.ucore.core.Core;
import io.anuke.ucore.entities.Entities;
@ -203,16 +205,16 @@ public class SaveIO{
//--MAP DATA--
//map ID
stream.writeByte(World.getMap().ordinal());
stream.writeByte(Vars.world.getMap().ordinal());
//seed
stream.writeInt(World.getSeed());
stream.writeInt(Vars.world.getSeed());
int totalblocks = 0;
for(int x = 0; x < World.width(); x ++){
for(int y = 0; y < World.height(); y ++){
Tile tile = World.tile(x, y);
for(int x = 0; x < Vars.world.width(); x ++){
for(int y = 0; y < Vars.world.height(); y ++){
Tile tile = Vars.world.tile(x, y);
if(tile.breakable()){
totalblocks ++;
@ -223,13 +225,13 @@ public class SaveIO{
//tile amount
stream.writeInt(totalblocks);
for(int x = 0; x < World.width(); x ++){
for(int y = 0; y < World.height(); y ++){
Tile tile = World.tile(x, y);
for(int x = 0; x < Vars.world.width(); x ++){
for(int y = 0; y < Vars.world.height(); y ++){
Tile tile = Vars.world.tile(x, y);
if(tile.breakable()){
stream.writeInt(x + y*World.width()); //tile pos
stream.writeInt(x + y*Vars.world.width()); //tile pos
stream.writeByte(tile.link);
stream.writeBoolean(tile.entity != null); //whether it has a tile entity
stream.writeInt(tile.block().id); //block ID
@ -349,20 +351,20 @@ public class SaveIO{
int seed = stream.readInt();
int tiles = stream.readInt();
World.loadMap(Map.values()[mapid], seed);
Vars.world.loadMap(Map.values()[mapid], seed);
Vars.renderer.clearTiles();
for(Enemy enemy : enemiesToUpdate){
enemy.findClosestNode();
}
for(int x = 0; x < World.width(); x ++){
for(int y = 0; y < World.height(); y ++){
Tile tile = World.tile(x, y);
for(int x = 0; x < Vars.world.width(); x ++){
for(int y = 0; y < Vars.world.height(); y ++){
Tile tile = Vars.world.tile(x, y);
//remove breakables like rocks
if(tile.breakable()){
World.tile(x, y).setBlock(Blocks.air);
Vars.world.tile(x, y).setBlock(Blocks.air);
}
}
}
@ -373,7 +375,7 @@ public class SaveIO{
boolean hasEntity = stream.readBoolean();
int blockid = stream.readInt();
Tile tile = World.tile(pos % World.width(), pos / World.width());
Tile tile = Vars.world.tile(pos % Vars.world.width(), pos / Vars.world.width());
tile.setBlock(Block.getByID(blockid));
tile.link = link;

View File

@ -4,7 +4,6 @@ import com.badlogic.gdx.graphics.g2d.TextureRegion;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.world.Map;
import io.anuke.mindustry.world.World;
import io.anuke.ucore.core.Core;
import io.anuke.ucore.core.Settings;
import io.anuke.ucore.core.Timers;
@ -50,7 +49,7 @@ public class LevelDialog extends FloatingDialog{
float images = 154f;
ImageButton image = new ImageButton(new TextureRegion(World.getTexture(map)), "togglemap");
ImageButton image = new ImageButton(new TextureRegion(Vars.world.getTexture(map)), "togglemap");
image.row();
image.add(inset).width(images+6).units(Unit.dp);
image.clicked(()->{

View File

@ -15,6 +15,7 @@ import io.anuke.mindustry.resource.Liquid;
import io.anuke.ucore.core.Draw;
import io.anuke.ucore.core.Effects;
import io.anuke.ucore.core.Effects.Effect;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.Tmp;
public class Block{
private static int lastid;
@ -48,10 +49,12 @@ public class Block{
public int health = 40;
/**the shadow drawn under the block*/
public String shadow = "shadow";
/**whether to display a different shadow per variant*/
public boolean varyShadow = false;
/**edge fallback, used mainly for ores*/
public String edge = "stone";
/**whether this block has 3 variants*/
public boolean vary = true;
/**number of block variants, 0 to disable*/
public int variants = 0;
/**stuff that drops when broken*/
public ItemStack drops = null;
/**liquids that drop from this block, used for pumps*/
@ -203,10 +206,12 @@ public class Block{
public void draw(Tile tile){
//note: multiblocks do not support rotation
if(!isMultiblock()){
Draw.rect(name(), tile.worldx(), tile.worldy(), rotate ? tile.rotation * 90 : 0);
Draw.rect(variants > 0 ? (name() + Mathf.randomSeed(tile.id(), 1, variants)) : name(),
tile.worldx(), tile.worldy(), rotate ? tile.rotation * 90 : 0);
}else{
//if multiblock, make sure to draw even block sizes offset, since the core block is at the BOTTOM LEFT
Vector2 offset = getPlaceOffset();
Draw.rect(name(), tile.worldx() + offset.x, tile.worldy() + offset.y);
}
@ -216,6 +221,15 @@ public class Block{
}
}
public void drawShadow(Tile tile){
if(varyShadow && variants > 0){
Draw.rect(shadow + (Mathf.randomSeed(tile.id(), 1, variants)), tile.worldx(), tile.worldy());
}else{
Draw.rect(shadow, tile.worldx(), tile.worldy());
}
}
/**Offset for placing and drawing multiblocks.*/
public Vector2 getPlaceOffset(){
return Tmp.v3.set(((width + 1) % 2) * Vars.tilesize/2, ((height + 1) % 2) * Vars.tilesize/2);

View File

@ -7,6 +7,7 @@ import com.badlogic.gdx.utils.ObjectMap;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.entities.enemies.TargetEnemy;
import io.anuke.mindustry.world.blocks.Blocks;
import io.anuke.mindustry.world.blocks.types.Floor;
import io.anuke.ucore.graphics.Hue;
import io.anuke.ucore.noise.Noise;
import io.anuke.ucore.util.Mathf;
@ -23,14 +24,16 @@ public class Generator{
Hue.rgb(110, 80, 30), Blocks.dirt,
Hue.rgb(160, 120, 70), Blocks.dirtblock,
Hue.rgb(100, 100, 100), Blocks.stoneblock,
Color.valueOf("414141"), Blocks.blackstoneblock,
Color.valueOf("252525"), Blocks.blackstone,
Color.valueOf("ed5334"), Blocks.lava,
Color.valueOf("292929"), Blocks.oil
);
/**Returns world size.*/
public static void generate(Pixmap pixmap){
public static void generate(Pixmap pixmap, Tile[][] tiles){
Noise.setSeed(World.getSeed());
Noise.setSeed(Vars.world.getSeed());
for(int x = 0; x < pixmap.getWidth(); x ++){
for(int y = 0; y < pixmap.getHeight(); y ++){
@ -41,23 +44,29 @@ public class Generator{
if(colors.containsKey(color)){
//TODO less hacky method
if(colors.get(color).name().contains("block")){
if(!(colors.get(color) instanceof Floor)){
block = colors.get(color);
}else{
floor = colors.get(color);
}
}else if(color == start){
World.core = World.tile(x, y);
Vars.control.setCore(Vars.world.tile(x, y));
}else if(color == spawn){
World.spawnpoints.add(World.tile(x, y));
Vars.control.addSpawnPoint(Vars.world.tile(x, y));
floor = Blocks.dirt;
}else{
if(Mathf.chance(0.02)){
block = Mathf.choose(Blocks.rock, Blocks.rock2);
}
if(block == Blocks.air){
if(floor == Blocks.stone && Mathf.chance(0.02)){
block = Blocks.rock;
}
if(floor == Blocks.blackstone && Mathf.chance(0.03)){
block = Blocks.blackrock;
}
}
if(floor == Blocks.stone || floor == Blocks.grass){
if(floor == Blocks.stone || floor == Blocks.grass || floor == Blocks.blackstone){
if(Noise.nnoise(x, y, 8, 1) > 0.2){
floor = Blocks.iron;
}
@ -77,11 +86,6 @@ public class Generator{
if(block == Blocks.grassblock){
floor = Blocks.grass;
block = Mathf.choose(Blocks.grassblock, Blocks.grassblock2);
}
if(block == Blocks.stoneblock){
block = Mathf.choose(Blocks.stoneblock, Blocks.stoneblock2, Blocks.stoneblock3);
}
if(floor == Blocks.grass && Mathf.chance(0.02) && block == Blocks.air){
@ -98,10 +102,8 @@ public class Generator{
// block = Mathf.choose(ProductionBlocks.stonedrill, DistributionBlocks.conveyor);
//}
World.tile(x, y).setBlock(block);
World.tile(x, y).setFloor(floor);
tiles[x][y].setBlock(block, 0);
tiles[x][y].setFloor(floor);
}
}
}

View File

@ -2,27 +2,31 @@ package io.anuke.mindustry.world;
public enum Map{
delta("Starting map."),
canyon("Badly drawn map."),
pit("Eck."),
maze("it's okay."),
maze2("test"),
maze3("test"),
maze4("test"),
maze5("test"),
maze("it's okay."),
volcano("desc"),
tutorial(false),
test1(false),
test2(false);
public final boolean visible;
public final boolean sandbox;
public final String description;
public int width, height;
private Map(boolean visible){
this.visible = visible;
this.sandbox = false;
this.description = "Test map!";
}
private Map(String description){
this(description, false);
}
private Map(String description, boolean sandbox){
this.visible = true;
this.sandbox = sandbox;
this.description = description;
}
}

View File

@ -0,0 +1,14 @@
package io.anuke.mindustry.world;
import com.badlogic.gdx.ai.pfa.PathFinder;
import com.badlogic.gdx.ai.pfa.PathFinderRequest;
import io.anuke.mindustry.ai.SmoothGraphPath;
public class SpawnPoint{
public Tile start;
public Tile[] pathTiles;
public PathFinder<Tile> finder;
public SmoothGraphPath path = new SmoothGraphPath();
public PathFinderRequest<Tile> request;
}

View File

@ -5,6 +5,7 @@ import static io.anuke.mindustry.Vars.tilesize;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.Array;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.world.blocks.Blocks;
import io.anuke.ucore.util.Bits;
@ -52,7 +53,7 @@ public class Tile{
float dst = Vector2.dst(dx, dy, 0, 0);
if(dst > rad || (dx == 0 && dy == 0)) continue;
Tile other = World.tile(x + dx, y + dy);
Tile other = Vars.world.tile(x + dx, y + dy);
if(other.entity != null){
other.entity.damage((int)(amount * Mathf.lerp(1f-dst/rad, 1f, falloff)));
}
@ -61,7 +62,7 @@ public class Tile{
}
public int id(){
return x + y * World.worldsize;
return x + y * Vars.world.width();
}
public float worldx(){
@ -139,7 +140,7 @@ public class Tile{
int offsety = -(block.height-1)/2;
for(int dx = 0; dx < block.width; dx ++){
for(int dy = 0; dy < block.height; dy ++){
Tile other = World.tile(x + dx + offsetx, y + dy + offsety);
Tile other = Vars.world.tile(x + dx + offsetx, y + dy + offsety);
tmpArray.add(other);
}
}
@ -154,12 +155,12 @@ public class Tile{
}else{
byte dx = Bits.getLeftByte(link);
byte dy = Bits.getRightByte(link);
return World.tile(x - (dx - 8), y - (dy - 8));
return Vars.world.tile(x - (dx - 8), y - (dy - 8));
}
}
public Tile[] getNearby(){
return World.getNearby(x, y);
return Vars.world.getNearby(x, y);
}
public void changed(){

View File

@ -18,61 +18,81 @@ import io.anuke.ucore.core.Sounds;
import io.anuke.ucore.entities.Entities;
import io.anuke.ucore.entities.Entity;
import io.anuke.ucore.entities.SolidEntity;
import io.anuke.ucore.modules.Module;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.Tmp;
public class World{
public static int worldsize = 128;
public static int pixsize = worldsize*tilesize;
private static int seed;
public class World extends Module{
private int seed;
private static Pixmap[] mapPixmaps;
private static Texture[] mapTextures;
private static Map currentMap;
private static Tile[][] tiles = new Tile[worldsize][worldsize];
private static Tile[] temptiles = new Tile[4];
private Pixmap[] mapPixmaps;
private Texture[] mapTextures;
private Map currentMap;
private Tile[][] tiles;
private Tile[] temptiles = new Tile[4];
private Pathfind pathfind = new Pathfind();
public static Tile core;
//TODO move this to control?
public static Array<Tile> spawnpoints = new Array<Tile>();
public World(){
loadMaps();
}
public static boolean solid(int x, int y){
@Override
public void update(){
pathfind.update();
}
@Override
public void dispose(){
for(Texture texture : mapTextures){
texture.dispose();
}
for(Pixmap pix : mapPixmaps){
pix.dispose();
}
}
public Pathfind pathfinder(){
return pathfind;
}
public boolean solid(int x, int y){
Tile tile = tile(x, y);
return tile == null || tile.block().solid || (tile.floor().solid && (tile.block() == Blocks.air));
}
public static boolean wallSolid(int x, int y){
public boolean wallSolid(int x, int y){
Tile tile = tile(x, y);
return tile == null || tile.block().solid;
}
public static boolean isAccessible(int x, int y){
public boolean isAccessible(int x, int y){
return !wallSolid(x, y-1) || !wallSolid(x, y+1) || !wallSolid(x-1, y) ||!wallSolid(x+1, y);
}
public static Map getMap(){
public Map getMap(){
return currentMap;
}
public static int width(){
return mapPixmaps[currentMap.ordinal()].getWidth();
public int width(){
return currentMap.width;
}
public static int height(){
return mapPixmaps[currentMap.ordinal()].getHeight();
public int height(){
return currentMap.height;
}
public static Tile tile(int x, int y){
public Tile tile(int x, int y){
if(!Mathf.inBounds(x, y, tiles)) return null;
return tiles[x][y];
}
public static Tile tileWorld(float x, float y){
public 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 Tile[] getNearby(int x, int y){
temptiles[0] = tile(x+1, y);
temptiles[1] = tile(x, y+1);
temptiles[2] = tile(x-1, y);
@ -80,11 +100,11 @@ public class World{
return temptiles;
}
public static Texture getTexture(Map map){
public Texture getTexture(Map map){
return mapTextures[map.ordinal()];
}
public static void loadMaps(){
public void loadMaps(){
Map[] maps = Map.values();
mapPixmaps = new Pixmap[maps.length];
@ -94,10 +114,12 @@ public class World{
Pixmap pix = new Pixmap(Gdx.files.internal("maps/"+maps[i]+".png"));
mapPixmaps[i] = pix;
mapTextures[i] = new Texture(pix);
maps[i].width = pix.getWidth();
maps[i].height = pix.getHeight();
}
}
private static void createTiles(){
private void createTiles(){
for(int x = 0; x < tiles.length; x ++){
for(int y = 0; y < tiles[0].length; y ++){
if(tiles[x][y] == null){
@ -107,7 +129,7 @@ public class World{
}
}
private static void clearTileEntities(){
private void clearTileEntities(){
for(int x = 0; x < tiles.length; x ++){
for(int y = 0; y < tiles[0].length; y ++){
if(tiles[x][y] != null && tiles[x][y].entity != null){
@ -117,57 +139,48 @@ public class World{
}
}
public static void loadMap(Map map){
public void loadMap(Map map){
loadMap(map, MathUtils.random(0, 99999));
}
public static void loadMap(Map map, int seed){
spawnpoints.clear();
int size = mapPixmaps[map.ordinal()].getWidth();
worldsize = size;
pixsize = worldsize*tilesize;
public void loadMap(Map map, int seed){
currentMap = map;
if(tiles != null){
clearTileEntities();
if(tiles.length != worldsize || tiles[0].length != worldsize){
tiles = new Tile[worldsize][worldsize];
if(tiles.length != map.width || tiles[0].length != map.height){
tiles = new Tile[map.width][map.height];
}
createTiles();
}else{
tiles = new Tile[worldsize][worldsize];
tiles = new Tile[map.width][map.height];
createTiles();
}
Entities.resizeTree(0, 0, pixsize, pixsize);
Entities.resizeTree(0, 0, map.width * tilesize, map.height * tilesize);
World.seed = seed;
Generator.generate(mapPixmaps[map.ordinal()]);
Pathfind.reset();
this.seed = seed;
Generator.generate(mapPixmaps[map.ordinal()], tiles);
//TODO multiblock core
placeBlock(core.x, core.y, ProductionBlocks.core, 0);
placeBlock(control.getCore().x, control.getCore().y, ProductionBlocks.core, 0);
if(map != Map.tutorial){
setDefaultBlocks();
}else{
Vars.control.getTutorial().setDefaultBlocks(core.x, core.y);
Vars.control.getTutorial().setDefaultBlocks(control.getCore().x, control.getCore().y);
}
Pathfind.updatePath();
pathfind.updatePath();
}
static void setDefaultBlocks(){
int x = core.x, y = core.y;
void setDefaultBlocks(){
int x = control.getCore().x, y = control.getCore().y;
//set(x, y-1, DistributionBlocks.conveyor, 1);
set(x, y-2, DistributionBlocks.conveyor, 1);
set(x, y-3, DistributionBlocks.conveyor, 1);
@ -183,28 +196,26 @@ public class World{
set(x+2*d, y-3, DistributionBlocks.conveyor, 2*d);
set(x+2*d, y-4, DistributionBlocks.conveyor, 1);
set(x+2*d, y-5, DistributionBlocks.conveyor, 1);
//set(x+2*d, y-6, DistributionBlocks.conveyor, 1);
//set(x+3*d, y-6, ProductionBlocks.stonedrill, 0);
set(x+3*d, y-5, ProductionBlocks.stonedrill, 0);
set(x+3*d, y-4, ProductionBlocks.stonedrill, 0);
set(x+3*d, y-3, ProductionBlocks.stonedrill, 0);
}
}
static void set(int x, int y, Block type, int rot){
void set(int x, int y, Block type, int rot){
if(type == ProductionBlocks.stonedrill){
tiles[x][y].setFloor(Blocks.stone);
}
tiles[x][y].setBlock(type, rot);
}
public static int getSeed(){
public int getSeed(){
return seed;
}
//TODO move to control or player?
public static void placeBlock(int x, int y, Block result, int rotation){
public void placeBlock(int x, int y, Block result, int rotation){
Tile tile = tile(x, y);
//just in case
@ -239,10 +250,10 @@ public class World{
}
//TODO move this to control?
public static boolean validPlace(int x, int y, Block type){
public boolean validPlace(int x, int y, Block type){
for(Tile spawn : spawnpoints){
if(Vector2.dst(x * tilesize, y * tilesize, spawn.worldx(), spawn.worldy()) < enemyspawnspace){
for(SpawnPoint spawn : control.getSpawnPoints()){
if(Vector2.dst(x * tilesize, y * tilesize, spawn.start.worldx(), spawn.start.worldy()) < enemyspawnspace){
return false;
}
}
@ -270,7 +281,8 @@ public class World{
int rotation = Vars.control.getTutorial().getPlaceRotation();
Block block = Vars.control.getTutorial().getPlaceBlock();
if(type != block || point.x != x - core.x || point.y != y - core.y || (rotation != -1 && rotation != Vars.player.rotation)){
if(type != block || point.x != x - control.getCore().x || point.y != y - control.getCore().y
|| (rotation != -1 && rotation != Vars.player.rotation)){
return false;
}
}else if(Vars.control.getTutorial().active()){
@ -298,7 +310,7 @@ public class World{
}
}
public static void breakBlock(int x, int y){
public void breakBlock(int x, int y){
Tile tile = tile(x, y);
if(tile == null) return;
@ -324,7 +336,7 @@ public class World{
}
}
public static boolean validBreak(int x, int y){
public boolean validBreak(int x, int y){
Tile tile = tile(x, y);
if(tile == null || tile.block() == ProductionBlocks.core) return false;
@ -340,7 +352,8 @@ public class World{
int rotation = Vars.control.getTutorial().getPlaceRotation();
Block block = Vars.control.getTutorial().getPlaceBlock();
if(block != Blocks.air || point.x != x - core.x || point.y != y - core.y || (rotation != -1 && rotation != Vars.player.rotation)){
if(block != Blocks.air || point.x != x - control.getCore().x || point.y != y - control.getCore().y
|| (rotation != -1 && rotation != Vars.player.rotation)){
return false;
}
}else{
@ -351,11 +364,7 @@ public class World{
return tile.breakable();
}
//public static Rectangle getCollider(int x, int y){
// return Rectangle.tmp2.setSize(tilesize).setCenter(x * tilesize, y * tilesize);
//}
public static TileEntity findTileTarget(float x, float y, Tile tile, float range, boolean damaged){
public TileEntity findTileTarget(float x, float y, Tile tile, float range, boolean damaged){
Entity closest = null;
float dst = 0;
@ -389,21 +398,11 @@ public class World{
return (TileEntity) closest;
}
public static void disposeMaps(){
for(Pixmap pixmap : mapPixmaps){
pixmap.dispose();
}
for(Texture texture : mapTextures){
texture.dispose();
}
}
/**
* Input is in block coordinates, not world coordinates.
* @return null if no collisions found, block position otherwise.
*/
public static Vector2 raycast(int x0f, int y0f, int x1f, int y1f){
public Vector2 raycast(int x0f, int y0f, int x1f, int y1f){
int x0 = (int)x0f;
int y0 = (int)y0f;
int x1 = (int)x1f;

View File

@ -31,20 +31,20 @@ public class Blocks{
blockpart = new BlockPart(),
deepwater = new Floor("deepwater"){{
vary = false;
variants = 0;
solid = true;
liquidDrop = Liquid.water;
}},
water = new Floor("water"){{
vary = false;
variants = 0;
solid = true;
liquidDrop = Liquid.water;
}},
lava = new Floor("lava"){
{
vary = false;
variants = 0;
solid = true;
liquidDrop = Liquid.lava;
}
@ -63,7 +63,7 @@ public class Blocks{
oil = new Floor("oil"){
{
vary = false;
variants = 0;
solid = true;
liquidDrop = Liquid.oil;
}
@ -80,6 +80,10 @@ public class Blocks{
drops = new ItemStack(Item.stone, 1);
}},
blackstone = new Floor("blackstone"){{
drops = new ItemStack(Item.stone, 1);
}},
iron = new Floor("iron"){{
drops = new ItemStack(Item.iron, 1);
}},
@ -100,24 +104,38 @@ public class Blocks{
grass = new Floor("grass"),
stoneblock = new Block("stoneblock"){{
solid = true;
}},
stoneblock = new Block("stoneblock"){
{
solid = true;
variants = 3;
}
@Override
public void draw(Tile tile){
// Draw.colorl(0.9f + Mathf.randomSeed(tile.id()*9999, 1, 10)/10f / 10f);
super.draw(tile);
// Draw.color();
}
},
stoneblock2 = new Block("stoneblock2"){{
solid = true;
}},
stoneblock3 = new Block("stoneblock3"){{
solid = true;
}},
blackstoneblock = new Block("blackstoneblock"){
{
solid = true;
variants = 3;
}
@Override
public void draw(Tile tile){
// float f = 0.15f;
// Draw.colorl(1f - f + Mathf.randomSeed(tile.id()*9999, 1, 10)/10f / (1f / f));
super.draw(tile);
// Draw.color();
}
},
grassblock = new Block("grassblock"){{
solid = true;
}},
grassblock2 = new Block("grassblock2"){{
solid = true;
variants = 2;
}},
mossblock = new Block("mossblock"){{
@ -134,13 +152,17 @@ public class Blocks{
shadow = "rockshadow";
breakable = true;
breaktime = 15;
variants = 2;
varyShadow = true;
drops = new ItemStack(Item.stone, 3);
}},
rock2 = new Block("rock2"){{
shadow = "rock2shadow";
blackrock = new Block("blackrock"){{
shadow = "blackrockshadow";
breakable = true;
breaktime = 15;
variants = 1;
varyShadow = true;
drops = new ItemStack(Item.stone, 3);
}},

View File

@ -0,0 +1,31 @@
package io.anuke.mindustry.world.blocks.types;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile;
import io.anuke.ucore.core.Draw;
import io.anuke.ucore.function.Predicate;
import io.anuke.ucore.util.Mathf;
public class BlendBlock extends Block{
protected String edge;
protected Predicate<Block> blend = block -> block == this;
public BlendBlock(String name) {
super(name);
edge = name + "-edge";
}
@Override
public void draw(Tile tile){
Draw.rect(variants > 0 ? (name() + Mathf.randomSeed(tile.id(), 1, variants)) : name(),
tile.worldx(), tile.worldy());
Tile[] nearby = tile.getNearby();
for(int i = 0; i < 4; i ++){
if(nearby[i] != null && !blend.test(nearby[i].block())){
Draw.rect(edge + "-" + i, tile.worldx(), tile.worldy());
}
}
}
}

View File

@ -3,9 +3,9 @@ package io.anuke.mindustry.world.blocks.types;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.math.MathUtils;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.World;
import io.anuke.ucore.core.Draw;
import io.anuke.ucore.graphics.Caches;
import io.anuke.ucore.util.Mathf;
@ -14,20 +14,21 @@ public class Floor extends Block{
public Floor(String name) {
super(name);
variants = 3;
}
@Override
public void drawCache(Tile tile){
MathUtils.random.setSeed(tile.id());
Caches.draw(vary ? (name() + MathUtils.random(1, 3)) : name(), tile.worldx(), tile.worldy());
Caches.draw(variants > 0 ? (name() + MathUtils.random(1, variants)) : name(), tile.worldx(), tile.worldy());
for(int dx = -1; dx <= 1; dx ++){
for(int dy = -1; dy <= 1; dy ++){
if(dx == 0 && dy == 0) continue;
Tile other = World.tile(tile.x+dx, tile.y+dy);
Tile other = Vars.world.tile(tile.x+dx, tile.y+dy);
if(other == null) continue;

View File

@ -0,0 +1,11 @@
package io.anuke.mindustry.world.blocks.types.defense;
import io.anuke.mindustry.world.blocks.types.Wall;
public class Door extends Wall{
public Door(String name) {
super(name);
}
}

View File

@ -4,8 +4,8 @@ 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.world.Tile;
import io.anuke.mindustry.world.World;
import io.anuke.ucore.core.Draw;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.graphics.Hue;
@ -39,7 +39,7 @@ public class RepairTurret extends PowerTurret{
TurretEntity entity = tile.entity();
if(Timers.get(entity, "blocktarget", targetInterval)){
entity.blockTarget = World.findTileTarget(tile.worldx(), tile.worldy(), tile, range, true);
entity.blockTarget = Vars.world.findTileTarget(tile.worldx(), tile.worldy(), tile, range, true);
}
if(entity.blockTarget != null){

View File

@ -8,7 +8,6 @@ import com.badlogic.gdx.utils.Array;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.entities.effect.Fx;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.World;
import io.anuke.mindustry.world.blocks.types.PowerAcceptor;
import io.anuke.mindustry.world.blocks.types.PowerBlock;
import io.anuke.ucore.core.Draw;
@ -140,7 +139,7 @@ public class Generator extends PowerBlock{
int i = 0;
for(i = 1; i < laserRange; i++){
Tile other = World.tile(tile.x + i * point.x, tile.y + i * point.y);
Tile other = Vars.world.tile(tile.x + i * point.x, tile.y + i * point.y);
if(other != null && other.block() instanceof PowerAcceptor){
Tile linked = other.getLinked();
@ -173,7 +172,7 @@ public class Generator extends PowerBlock{
}
if(Vector2.dst(x, y, 0, 0) < powerRange){
Tile dest = World.tile(tile.x + x, tile.y + y);
Tile dest = Vars.world.tile(tile.x + x, tile.y + y);
if(dest != null && dest.block() instanceof PowerAcceptor && ((PowerAcceptor) dest.block()).acceptsPower(dest)){
if(i == 1){
PowerAcceptor block = (PowerAcceptor) dest.block();