Added terrain exporting and importing

This commit is contained in:
Anuken
2018-03-25 00:44:25 -04:00
parent 674d259df1
commit 59530909d6
19 changed files with 229 additions and 48 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 258 B

After

Width:  |  Height:  |  Size: 249 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 257 B

After

Width:  |  Height:  |  Size: 234 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 269 B

After

Width:  |  Height:  |  Size: 268 B

View File

@ -151,8 +151,8 @@ text.editor.generate=Generate
text.editor.resize=Resize
text.editor.loadmap=Load Map
text.editor.savemap=Save Map
text.editor.loadimage=Load Image
text.editor.saveimage=Save Image
text.editor.loadimage=Import Terrain
text.editor.saveimage=Export Terrain
text.editor.unsaved=[scarlet]You have unsaved changes![]\nAre you sure you want to exit?
text.editor.brushsize=Brush size: {0}
text.editor.noplayerspawn=This map has no player spawnpoint!

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

After

Width:  |  Height:  |  Size: 92 KiB

View File

@ -1,7 +1,7 @@
#Autogenerated file. Do not modify.
#Sat Mar 24 18:18:45 EDT 2018
#Sun Mar 25 00:43:28 EDT 2018
version=release
androidBuildCode=635
androidBuildCode=638
name=Mindustry
code=3.4
build=custom build

View File

@ -87,7 +87,7 @@ public class Logic extends Module {
world.pathfinder().update();
if(world.getAllyCores().size == 0 && !state.gameOver && false){ //TODO gameover state
if(world.getAllyCores().size == 0 && !state.gameOver){ //TODO gameover state
state.gameOver = true;
if(Net.server()) NetEvents.handleGameOver();
Events.fire(GameOverEvent.class);

View File

@ -179,7 +179,7 @@ public class World extends Module{
Entities.resizeTree(0, 0, width * tilesize, height * tilesize);
WorldGenerator.generate(tiles, MapIO.readTileData(map));
WorldGenerator.generate(tiles, MapIO.readTileData(map), allyCores);
}
void set(int x, int y, Block type, int rot){

View File

@ -1,5 +1,6 @@
package io.anuke.mindustry.editor;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.io.MapTileData;
import io.anuke.mindustry.io.MapTileData.TileDataMarker;
import io.anuke.mindustry.world.Block;
@ -16,6 +17,7 @@ public class MapEditor{
private int brushSize = 1;
private Block drawBlock = Blocks.stone;
private Team drawTeam = Team.none;
public MapEditor(){
@ -31,7 +33,15 @@ public class MapEditor{
this.brushSize = 1;
renderer.resize(map.width(), map.height());
}
public void setDrawTeam(Team team){
this.drawTeam = team;
}
public Team getDrawTeam() {
return drawTeam;
}
public Block getDrawBlock(){
return drawBlock;
}
@ -60,6 +70,10 @@ public class MapEditor{
writer.wall = (byte)drawBlock.id;
}
if(drawBlock.hasEntity()){
writer.team = (byte)drawTeam.ordinal();
}
for(int rx = -brushSize + 1; rx <= brushSize - 1; rx ++){
for(int ry = -brushSize + 1; ry <= brushSize - 1; ry ++){
if(Mathf.dst(rx, ry) <= brushSize){

View File

@ -3,8 +3,10 @@ package io.anuke.mindustry.editor;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.utils.ObjectMap;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.io.MapIO;
import io.anuke.mindustry.io.MapTileData;
import io.anuke.mindustry.io.Platform;
@ -18,6 +20,7 @@ import io.anuke.ucore.core.Core;
import io.anuke.ucore.core.Graphics;
import io.anuke.ucore.core.Inputs;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.graphics.Pixmaps;
import io.anuke.ucore.scene.Element;
import io.anuke.ucore.scene.actions.Actions;
import io.anuke.ucore.scene.builders.build;
@ -42,7 +45,7 @@ public class MapEditorDialog extends Dialog{
private MapResizeDialog resizeDialog;
private ScrollPane pane;
private FloatingDialog menu;
private FileChooser openFile, saveFile;
private FileChooser openFile, saveFile, openImage, saveImage;
private ObjectMap<String, String> tags = new ObjectMap<>();
private boolean saved = false;
@ -56,7 +59,7 @@ public class MapEditorDialog extends Dialog{
dialog = new MapGenerateDialog(editor);
view = new MapView(editor);
saveFile = new FileChooser("$saveimage", false, file -> {
saveFile = new FileChooser("$text.saveimage", false, file -> {
file = file.parent().child(file.nameWithoutExtension() + "." + mapExtension);
FileHandle result = file;
ui.loadfrag.show();
@ -88,6 +91,38 @@ public class MapEditorDialog extends Dialog{
});
});
saveImage = new FileChooser("$text.saveimage", false, file -> {
file = file.parent().child(file.nameWithoutExtension() + ".png");
FileHandle result = file;
ui.loadfrag.show();
Timers.run(3f, () -> {
try{
Pixmaps.write(MapIO.generatePixmap(editor.getMap()), result);
}catch (Exception e){
ui.showError(Bundles.format("text.editor.errorimagesave", Strings.parseException(e, false)));
Log.err(e);
}
ui.loadfrag.hide();
});
});
openImage = new FileChooser("$text.loadimage", FileChooser.pngFilter, true, file -> {
ui.loadfrag.show();
Timers.run(3f, () -> {
try{
MapTileData data = MapIO.readPixmap(new Pixmap(file));
editor.beginEdit(data);
view.clearStack();
}catch (Exception e){
ui.showError(Bundles.format("text.editor.errorimageload", Strings.parseException(e, false)));
Log.err(e);
}
ui.loadfrag.hide();
});
});
menu = new FloatingDialog("$text.menu");
menu.addCloseButton();
@ -118,6 +153,19 @@ public class MapEditorDialog extends Dialog{
menu.hide();
});
menu.content().row();
menu.content().addImageTextButton("$text.editor.saveimage", "icon-save-map", isize, () -> {
saveImage.show();
menu.hide();
});
menu.content().row();
menu.content().addImageTextButton("$text.editor.loadimage", "icon-load-map", isize, () -> {
openImage.show();
menu.hide();
});
/*
@ -284,7 +332,22 @@ public class MapEditorDialog extends Dialog{
if (tool == EditorTool.pencil)
button.setChecked(true);
tools.add(button).padBottom(-6f);
tools.add(button).padBottom(-5.1f);
if(i++ % 2 == 1) tools.row();
}
ButtonGroup<ImageButton> teamgroup = new ButtonGroup<>();
for(Team team : Team.values()){
ImageButton button = new ImageButton("white", "toggle");
button.margin(4f, 4f, 10f, 4f);
button.getImageCell().grow();
button.getStyle().imageUpColor = team.color;
button.clicked(() -> editor.setDrawTeam(team));
button.update(() -> button.setChecked(editor.getDrawTeam() == team));
teamgroup.add(button);
tools.add(button).padBottom(-5.1f);
if(i++ % 2 == 1) tools.row();
}
@ -351,44 +414,9 @@ public class MapEditorDialog extends Dialog{
}
}
private boolean verifyMap(){
//TODO make sure both teams have cores or something
/*
int psc = ColorMapper.getColor(SpecialBlocks.playerSpawn);
int esc = ColorMapper.getColor(SpecialBlocks.enemySpawn);
int playerSpawns = 0;
int enemySpawns = 0;
Pixmap pix = editor.pixmap();
for(int x = 0; x < pix.getWidth(); x ++){
for(int y = 0; y < pix.getHeight(); y ++){
int i = pix.getPixel(x, y);
if(i == psc) playerSpawns ++;
if(i == esc) enemySpawns ++;
}
}
if(playerSpawns == 0){
ui.showError("$text.editor.noplayerspawn");
return false;
}else if(playerSpawns > 1){
ui.showError("$text.editor.manyplayerspawns");
return false;
}
if(enemySpawns > MapEditor.maxSpawnpoints){
ui.showError(Bundles.format("text.editor.manyenemyspawns", MapEditor.maxSpawnpoints));
return false;
}*/
return true;
}
private void addBlockSelection(Table table){
Table content = new Table();
pane = new ScrollPane(content, "volume");
//pane.setScrollingDisabled(true, false);
pane.setFadeScrollBars(false);
pane.setOverscroll(true, false);
ButtonGroup<ImageButton> group = new ButtonGroup<>();

View File

@ -0,0 +1,25 @@
package io.anuke.mindustry.entities.units;
import io.anuke.mindustry.entities.Unit;
import io.anuke.ucore.graphics.Draw;
public class FlyingUnitType extends UnitType {
public FlyingUnitType(String name) {
super(name);
}
@Override
public void draw(BaseUnit unit) {
Draw.alpha(unit.hitTime / Unit.hitDuration);
Draw.rect(name, unit.x, unit.y, unit.rotation);
Draw.alpha(1f);
}
@Override
public void behavior(BaseUnit unit) {
}
}

View File

@ -5,7 +5,8 @@ import com.badlogic.gdx.graphics.Color;
public enum Team {
none(Color.DARK_GRAY),
blue(Color.ROYAL),
red(Color.valueOf("e84737"));
red(Color.valueOf("e84737")),
green(Color.valueOf("1dc645"));
public final Color color;

View File

@ -9,6 +9,8 @@ import com.badlogic.gdx.utils.ObjectMap.Entry;
import io.anuke.mindustry.io.MapTileData.TileDataMarker;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.ColorMapper;
import io.anuke.mindustry.world.ColorMapper.BlockPair;
import io.anuke.mindustry.world.blocks.Blocks;
import java.io.DataInputStream;
import java.io.DataOutputStream;
@ -25,6 +27,7 @@ public class MapIO {
public static Pixmap generatePixmap(MapTileData data){
Pixmap pixmap = new Pixmap(data.width(), data.height(), Format.RGBA8888);
data.position(0, 0);
for(int x = 0; x < data.width(); x ++){
for(int y = 0; y < data.height(); y ++){
@ -39,6 +42,31 @@ public class MapIO {
return pixmap;
}
public static MapTileData readPixmap(Pixmap pixmap){
MapTileData data = new MapTileData(pixmap.getWidth(), pixmap.getHeight());
data.position(0, 0);
TileDataMarker marker = data.getMarker();
for(int x = 0; x < data.width(); x ++){
for(int y = 0; y < data.height(); y ++){
BlockPair pair = ColorMapper.get(pixmap.getPixel(y, pixmap.getWidth() - 1 - x));
if(pair == null){
marker.floor = (byte)Blocks.stone.id;
marker.wall = (byte)Blocks.air.id;
}else{
marker.floor = (byte)pair.floor.id;
marker.wall = (byte)pair.wall.id;
}
data.write();
}
}
return data;
}
public static void writeMap(FileHandle file, ObjectMap<String, String> tags, MapTileData data) throws IOException{
MapMeta meta = new MapMeta(version, tags, data.width(), data.height());

View File

@ -39,6 +39,10 @@ public class MapTileData {
return height;
}
public TileDataMarker getMarker() {
return tile;
}
/**Reads and returns the next tile data.*/
public TileDataMarker read(){
tile.read(buffer);
@ -52,6 +56,11 @@ public class MapTileData {
return tile;
}
/**Writes and returns the next tile data.*/
public void write(){
tile.write(buffer);
}
/**Writes tile data at a specified position.*/
public void write(int x, int y, TileDataMarker writer){
position(x, y);

View File

@ -220,6 +220,10 @@ public class Block extends BaseBlock {
region.setRegionHeight(8);
return region;
}
public boolean hasEntity(){
return destructible || update;
}
public TileEntity getEntity(){
return new TileEntity();

View File

@ -305,7 +305,7 @@ public class Tile{
Block block = block();
if (block.destructible || block.update) {
if (block.hasEntity()) {
entity = block.getEntity().init(this, block.update);
if(block.hasInventory) entity.inventory = new InventoryModule();
if(block.hasLiquids) entity.liquid = new LiquidModule();

View File

@ -1,11 +1,13 @@
package io.anuke.mindustry.world;
import com.badlogic.gdx.utils.Array;
import com.badlogic.gdx.utils.IntArray;
import com.badlogic.gdx.utils.ObjectMap;
import io.anuke.mindustry.game.Team;
import io.anuke.mindustry.io.MapTileData;
import io.anuke.mindustry.io.MapTileData.TileDataMarker;
import io.anuke.mindustry.world.blocks.Blocks;
import io.anuke.mindustry.world.blocks.ProductionBlocks;
import io.anuke.ucore.noise.Noise;
import static io.anuke.mindustry.Vars.world;
@ -20,7 +22,7 @@ public class WorldGenerator {
}};
/**Should fill spawns with the correct spawnpoints.*/
public static void generate(Tile[][] tiles, MapTileData data){
public static void generate(Tile[][] tiles, MapTileData data, Array<Tile> cores){
Noise.setSeed(world.getSeed());
IntArray multiblocks = new IntArray();
@ -34,6 +36,10 @@ public class WorldGenerator {
multiblocks.add(tiles[x][y].packedPosition());
}
if(tiles[x][y].block() == ProductionBlocks.core){
cores.add(tiles[x][y]);
}
//TODO ores, plants, extra decoration?
}
}

View File

@ -1,14 +1,80 @@
package io.anuke.mindustry.world.blocks.types.production;
import io.anuke.mindustry.entities.TileEntity;
import io.anuke.mindustry.entities.units.BaseUnit;
import io.anuke.mindustry.entities.units.UnitType;
import io.anuke.mindustry.resource.ItemStack;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.types.modules.InventoryModule;
import io.anuke.ucore.core.Timers;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
public class UnitFactory extends Block {
protected UnitType type;
protected ItemStack[] requirements;
protected float produceTime = 1000f;
protected float powerUse = 0.1f;
public UnitFactory(String name) {
super(name);
solid = true;
update = true;
hasPower = true;
}
@Override
public void update(Tile tile) {
UnitFactoryEntity entity = tile.entity();
float used = Math.min(powerUse * Timers.delta(), powerCapacity);
if(hasRequirements(entity.inventory, entity.buildTime/produceTime) &&
entity.power.amount >= used){
entity.buildTime += Timers.delta();
entity.power.amount -= used;
if(entity.buildTime >= produceTime){
BaseUnit unit = new BaseUnit(type, tile.getTeam());
unit.set(tile.drawx(), tile.drawy());
entity.buildTime = 0f;
for(ItemStack stack : requirements){
entity.inventory.removeItem(stack.item, stack.amount);
}
}
}
}
@Override
public TileEntity getEntity() {
return new UnitFactoryEntity();
}
protected boolean hasRequirements(InventoryModule inv, float fraction){
for(ItemStack stack : requirements){
if(!inv.hasItem(stack.item, (int)(fraction * stack.amount))){
return false;
}
}
return true;
}
public static class UnitFactoryEntity extends TileEntity{
public float buildTime;
@Override
public void write(DataOutputStream stream) throws IOException {
stream.writeFloat(buildTime);
}
@Override
public void read(DataInputStream stream) throws IOException {
buildTime = stream.readFloat();
}
}
}