Scale waves based on difficulty; improve map editor

This commit is contained in:
Anuken
2017-12-18 17:37:14 -05:00
parent 1ae875ebf4
commit 7953a21073
34 changed files with 857 additions and 714 deletions

View File

@ -79,7 +79,7 @@ project(":core") {
apply plugin: "java"
dependencies {
compile 'com.github.anuken:ucore:283ecacfef'
compile 'com.github.anuken:ucore:9c523c4'
compile "com.badlogicgames.gdx:gdx:$gdxVersion"
compile "com.badlogicgames.gdx:gdx-ai:1.8.1"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 252 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 247 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 236 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 245 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 238 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 244 B

File diff suppressed because it is too large Load Diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 77 KiB

After

Width:  |  Height:  |  Size: 79 KiB

View File

@ -16,8 +16,8 @@ import io.anuke.mindustry.core.GameState.State;
import io.anuke.mindustry.entities.*;
import io.anuke.mindustry.entities.effect.Fx;
import io.anuke.mindustry.entities.effect.Shield;
import io.anuke.mindustry.entities.enemies.BlastEnemy;
import io.anuke.mindustry.entities.enemies.Enemy;
import io.anuke.mindustry.entities.enemies.FortressEnemy;
import io.anuke.mindustry.entities.enemies.HealerEnemy;
import io.anuke.mindustry.input.AndroidInput;
import io.anuke.mindustry.input.DesktopInput;
@ -471,7 +471,7 @@ public class Control extends Module{
new HealerEnemy().set(player.x, player.y).add();
}else{
float px = player.x, py = player.y;
Timers.run(30f, ()-> new BlastEnemy().set(px, py).add());
Timers.run(30f, ()-> new FortressEnemy().set(px, py).add());
}
}
}

View File

@ -546,7 +546,7 @@ public class Renderer extends RendererModule{
Draw.dashCircle(spawn.start.worldx(), spawn.start.worldy(), enemyspawnspace);
}
}else if(player.breakMode.delete && control.input.drawPlace()){
}else if(player.breakMode.delete && control.input.drawPlace() && player.recipe == null){ //TODO test!
player.breakMode.draw(control.input.getBlockX(), control.input.getBlockY(),
control.input.getBlockEndX(), control.input.getBlockEndY());
}

View File

@ -448,6 +448,14 @@ public class UI extends SceneModule{
public void showEditor(){
editorDialog.show();
}
public MapEditorDialog getEditor(){
return editorDialog;
}
public boolean isEditing(){
return editorDialog.getScene() != null;
}
public void updateItems(){
((HudFragment)hudfrag).updateItems();

View File

@ -1,15 +0,0 @@
package io.anuke.mindustry.editor;
import io.anuke.ucore.modules.ModuleCore;
public class Editor extends ModuleCore{
public static EditorControl control;
public static EditorUI ui;
@Override
public void init(){
module(control = new EditorControl());
module(ui = new EditorUI());
}
}

View File

@ -1,267 +0,0 @@
package io.anuke.mindustry.editor;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Keys;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.utils.*;
import com.badlogic.gdx.utils.reflect.ClassReflection;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.Generator;
import io.anuke.mindustry.world.blocks.Blocks;
import io.anuke.mindustry.world.blocks.types.Floor;
import io.anuke.ucore.core.Core;
import io.anuke.ucore.core.Inputs;
import io.anuke.ucore.graphics.Pixmaps;
import io.anuke.ucore.modules.Module;
import io.anuke.ucore.noise.RidgedPerlin;
import io.anuke.ucore.noise.Simplex;
import io.anuke.ucore.util.Mathf;
public class EditorControl extends Module{
private ObjectIntMap<Block> colors = new ObjectIntMap<>();
Pixmap pixmap;
Texture texture;
Simplex sim = new Simplex();
RidgedPerlin rid = new RidgedPerlin(1, 10, 20f);
RidgedPerlin rid2 = new RidgedPerlin(1, 6, 1f);
RidgedPerlin rid3 = new RidgedPerlin(1, 6, 1f);
String map = "fortress";
ObjectMap<String, Boolean> prefs = new OrderedMap<String, Boolean>(){
{
put("replace", true);
put("terrain", false);
put("circle", false);
put("distort", false);
put("sand", false);
put("grass", false);
put("stone", false);
put("allgrass", false);
put("allsnow", false);
put("allsand", false);
put("lavarock", false);
put("water", false);
put("oil", false);
put("lavariver", false);
put("slavariver", false);
put("river", false);
put("iceriver", false);
put("oilriver", false);
}
};
public EditorControl() {
IntMap.Keys keys = Generator.colors.keys();
for(int key = keys.next(); keys.hasNext; key = keys.next()){
colors.put(Generator.colors.get(key), key);
}
loadMap(map);
}
@Override
public void update(){
clearScreen();
if(Inputs.keyUp(Keys.ESCAPE)){
Gdx.app.exit();
}
if(Core.scene.getKeyboardFocus() == null){
if(Inputs.keyUp(Keys.R)){
randomize();
loadMap(map);
}
if(Inputs.keyUp(Keys.E)){
try{
ClassReflection.getMethod(ClassReflection.forName("com.badlogic.gdx.graphics.PixmapIO"), "writePNG", FileHandle.class, Pixmap.class)
.invoke(Gdx.files.absolute("/home/anuke/Pictures/maps/out-" + TimeUtils.millis() + ".png"), pixmap);
}catch (Exception e){
throw new RuntimeException(e);
}
}
}
}
public void randomize(){
sim.setSeed(Mathf.random(999999));
rid.setSeed(Mathf.random(999999));
rid2.setSeed(Mathf.random(999999));
rid3.setSeed(Mathf.random(999999));
}
public void reload(){
loadMap(map);
}
public void loadMap(String name){
if(pixmap != null)
pixmap.dispose();
pixmap = new Pixmap(Gdx.files.internal("maps/" + name + ".png"));
process();
}
public void process(){
if(prefs.get("terrain")){
for(int x = 0; x < pixmap.getWidth(); x++){
for(int y = 0; y < pixmap.getHeight(); y++){
float dist = Vector2.dst((float) x / pixmap.getWidth(), (float) y / pixmap.getHeight(), 0.5f, 0.5f) * 2f;
double noise = sim.octaveNoise2D(6, 0.6, 1 / 180.0, x, y + 9999) / (prefs.get("circle") ? 1.7 : 1f) + dist / 10f;
if(dist > 0.8){
noise += 2 * (dist - 0.8);
}
Block block = noise > 0.6 ? Blocks.stoneblock : Blocks.stone;
pixmap.drawPixel(x, y, colors.get(block, 0));
}
}
}
Pixmap src = Pixmaps.copy(pixmap);
for(int x = 0; x < pixmap.getWidth(); x++){
for(int y = 0; y < pixmap.getHeight(); y++){
int dx = 0, dy = 0;
if(prefs.get("distort")){
double intensity = 12;
double scale = 80;
double octaves = 4;
double falloff = 0.6;
double nx = (sim.octaveNoise2D(octaves, falloff, 1 / scale, x, y) - 0.5f) * intensity;
double ny = (sim.octaveNoise2D(octaves, falloff, 1 / scale, x, y + 99999) - 0.5f) * intensity;
dx = (int) nx;
dy = (int) ny;
}
int pix = src.getPixel(x + dx, y + dy);
Block block = Generator.colors.get(pix);
if(block == null)
continue;
boolean floor = block instanceof Floor;
double noise = sim.octaveNoise2D(4, 0.6, 1 / 170.0, x, y) + sim.octaveNoise2D(1, 1.0, 1 / 5.0, x, y) / 18.0;
double nwater = sim.octaveNoise2D(1, 1.0, 1 / 130.0, x, y);
noise += nwater / 5.0;
double noil = sim.octaveNoise2D(1, 1.0, 1 / 150.0, x + 9999, y) + sim.octaveNoise2D(1, 1.0, 1 / 2.0, x, y) / 290.0;
if(!floor || prefs.get("replace")){
if(prefs.get("allgrass")){
block = floor ? Blocks.grass : Blocks.grassblock;
}else if(prefs.get("allsnow")){
block = floor ? Blocks.snow : Blocks.snowblock;
}else if(prefs.get("allsand")){
block = floor ? Blocks.sand : Blocks.sandblock;
}else if(prefs.get("replace")){
block = floor ? Blocks.stone : Blocks.stoneblock;
}
if(noise > 0.7 && prefs.get("grass")){
block = floor ? Blocks.grass : Blocks.grassblock;
}
if(noise > 0.7 && prefs.get("lavarock")){
block = floor ? Blocks.blackstone : Blocks.blackstoneblock;
}
if(noise > 0.7 && prefs.get("sand")){
block = floor ? Blocks.sand : Blocks.sandblock;
}
if(noise > 0.8 && prefs.get("stone")){
block = floor ? Blocks.stone : Blocks.stoneblock;
}
}
if(floor){
if(nwater > 0.93 && prefs.get("water")){
block = Blocks.water;
if(nwater > 0.943){
block = Blocks.deepwater;
}
}
if(noil > 0.95 && prefs.get("oil")){
block = Blocks.dirt;
if(noil > 0.955){
block = Blocks.oil;
}
}
}
if(floor && prefs.get("lavariver")){
double lava = rid.getValue(x, y, 1 / 100f);
double t = 0.6;
if(lava > t){
block = Blocks.lava;
}else if(lava > t - 0.2){
block = Blocks.blackstone;
}
}
if(floor && prefs.get("slavariver")){
double lava = rid.getValue(x, y, 1 / 40f);
double t = 0.7;
if(lava > t){
block = Blocks.lava;
}else if(lava > t - 0.3){
block = Blocks.blackstone;
}
}
if(floor && prefs.get("oilriver")){
double lava = rid3.getValue(x, y, 1 / 100f);
double t = 0.9;
if(lava > t){
block = Blocks.oil;
}else if(lava > t - 0.2){
block = Blocks.dirt;
}
}
if(floor && prefs.get("river")){
double riv = rid2.getValue(x, y, 1 / 140f);
double t = 0.4;
if(riv > t + 0.1){
block = Blocks.deepwater;
}else if(riv > t){
block = Blocks.water;
}else if(riv > t - 0.2){
block = Blocks.grass;
}
}
if(floor && prefs.get("iceriver")){
double riv = rid2.getValue(x, y, 1 / 140f);
double t = 0.4;
if(riv > t + 0.1){
block = Blocks.ice;
}else if(riv > t){
block = Blocks.ice;
}else if(riv > t - 0.2){
block = Blocks.snow;
}
}
pixmap.drawPixel(x, y, colors.get(block, 0));
}
}
src.dispose();
if(texture != null){
texture.dispose();
}
texture = new Texture(pixmap);
}
}

View File

@ -1,65 +0,0 @@
package io.anuke.mindustry.editor;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input.Buttons;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.utils.Scaling;
import io.anuke.ucore.core.Graphics;
import io.anuke.ucore.core.Inputs;
import io.anuke.ucore.graphics.Atlas;
import io.anuke.ucore.modules.SceneModule;
import io.anuke.ucore.scene.Skin;
import io.anuke.ucore.scene.builders.*;
import io.anuke.ucore.scene.style.TextureRegionDrawable;
import io.anuke.ucore.scene.ui.Image;
import io.anuke.ucore.scene.ui.TextField;
public class EditorUI extends SceneModule{
@Override
public void init(){
build.begin();
new table(){{
Image image = new Image();
image.update(()-> image.setDrawable(new TextureRegionDrawable(new TextureRegion(Editor.control.texture))));
image.setScaling(Scaling.fit);
add(image).size(256 * 3);
new table("button"){{
new field(Editor.control.map, text->{
if(Gdx.files.internal("maps/" + text + ".png").exists()){
Editor.control.map = text;
Editor.control.reload();
}
});
row();
for(String key : Editor.control.prefs.keys()){
new checkbox(key, Editor.control.prefs.get(key), b->{
Editor.control.prefs.put(key, b);
Editor.control.reload();
}).left();
row();
}
margin(16);
}}.end();
}}.end();
build.end();
}
@Override
public void update(){
super.update();
if(Inputs.buttonUp(Buttons.LEFT)){
if(!hasMouse() || !(scene.hit(Graphics.mouse().x, Graphics.mouse().y, true) instanceof TextField)){
scene.setKeyboardFocus(null);
}
}
}
@Override
protected void loadSkin(){
skin = new Skin(Gdx.files.internal("ui/uiskin.json"), new Atlas(Gdx.files.internal("sprites/sprites.atlas")));
}
}

View File

@ -1,9 +1,12 @@
package io.anuke.mindustry.entities;
import io.anuke.mindustry.entities.enemies.Enemy;
import io.anuke.ucore.core.Settings;
import io.anuke.ucore.util.Mathf;
public class EnemySpawn{
private static float[] scalings = {2f, 1.5f, 1f};
/**The enemy type spawned*/
public final Class<? extends Enemy> type;
/**When this spawns should end*/
@ -33,6 +36,8 @@ public class EnemySpawn{
if(wave < after || wave > before || (wave - after) % spacing != 0){
return 0;
}
float scaling = this.scaling * scalings[(Settings.getInt("difficulty"))];
return Math.min(amount-1 + 1 * Math.max((int)((wave / spacing) / scaling), 1) - (tier(wave, lane)-1) * tierscaleback, max);
}

View File

@ -331,6 +331,15 @@ public class Fx{
Draw.reset();
}),
shieldhit = new Effect(9, e -> {
Draw.thickness(1f);
Draw.color(Color.WHITE, Color.SKY, e.ifract());
Draw.spikes(e.x, e.y, e.ifract() * 5f, 2, 6);
Draw.thickness(4f*e.fract());
Draw.circle(e.x, e.y, e.ifract()*14f);
Draw.reset();
}),
shoot = new Effect(8, e -> {
Draw.thickness(1f);
Draw.color(Color.WHITE, Color.GOLD, e.ifract());

View File

@ -78,7 +78,7 @@ public class AndroidInput extends InputHandler{
if(!GameState.is(State.menu)){
Tile cursor = world.tile(Mathf.scl2(Graphics.mouseWorld().x, tilesize), Mathf.scl2(Graphics.mouseWorld().y, tilesize));
if(cursor != null && !ui.hasMouse()){
if(cursor != null && !ui.hasMouse(screenX, screenY)){
Tile linked = cursor.isLinked() ? cursor.getLinked() : cursor;
if(linked != null && linked.block() instanceof Configurable){
ui.showConfig(linked);
@ -155,7 +155,7 @@ public class AndroidInput extends InputHandler{
}
@Override
public void tryPlaceBlock(int x, int y, boolean sound){
public boolean tryPlaceBlock(int x, int y, boolean sound){
if(player.recipe != null &&
validPlace(x, y, player.recipe.result) && cursorNear() &&
Vars.control.hasItems(player.recipe.requirements)){
@ -169,6 +169,8 @@ public class AndroidInput extends InputHandler{
if(!Vars.control.hasItems(player.recipe.requirements)){
Cursors.restoreCursor();
}
return true;
}
return false;
}
}

View File

@ -94,7 +94,7 @@ public class DesktopInput extends InputHandler{
Tile cursor = world.tile(tilex(), tiley());
if(Inputs.buttonUp(Buttons.LEFT) && cursor != null){
if(Inputs.buttonUp(Buttons.LEFT) && cursor != null && !ui.hasMouse()){
Tile linked = cursor.isLinked() ? cursor.getLinked() : cursor;
if(linked != null && linked.block() instanceof Configurable){
ui.showConfig(linked);

View File

@ -49,7 +49,7 @@ public abstract class InputHandler extends InputAdapter{
return Vector2.dst(player.x, player.y, getBlockX() * tilesize, getBlockY() * tilesize) <= placerange;
}
public void tryPlaceBlock(int x, int y, boolean sound){
public boolean tryPlaceBlock(int x, int y, boolean sound){
if(player.recipe != null &&
validPlace(x, y, player.recipe.result) && !ui.hasMouse() && cursorNear() &&
Vars.control.hasItems(player.recipe.requirements)){
@ -63,7 +63,9 @@ public abstract class InputHandler extends InputAdapter{
if(!Vars.control.hasItems(player.recipe.requirements)){
Cursors.restoreCursor();
}
return true;
}
return false;
}
public boolean tryDeleteBlock(int x, int y, boolean sound){

View File

@ -306,10 +306,12 @@ public enum PlaceMode{
boolean first = true;
for(int x = 0; x <= Math.abs(this.endx - this.tilex); x ++){
for(int y = 0; y <= Math.abs(this.endy - this.tiley); y ++){
control.getInput().tryPlaceBlock(
if(control.getInput().tryPlaceBlock(
tilex + x * Mathf.sign(endx - tilex),
tiley + y * Mathf.sign(endy - tiley), first);
first = false;
tiley + y * Mathf.sign(endy - tiley), first)){
first = false;
}
}
}
}

View File

@ -0,0 +1,70 @@
package io.anuke.mindustry.mapeditor;
import java.util.Stack;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.math.GridPoint2;
import com.badlogic.gdx.utils.IntSet;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.world.Block;
import io.anuke.mindustry.world.ColorMapper;
public enum EditorTool{
pencil{
public void touched(MapEditor editor, int x, int y){
editor.draw(x, y);
}
},
fill{
public void touched(MapEditor editor, int x, int y){
Pixmap pix = editor.pixmap();
int dest = pix.getPixel(x, y);
int width = pix.getWidth();
IntSet set = new IntSet();
Stack<GridPoint2> points = new Stack<GridPoint2>();
points.add(new GridPoint2(x, y));
while( !points.isEmpty()){
GridPoint2 pos = points.pop();
set.add(asInt(pos.x, pos.y, width));
int pcolor = pix.getPixel(pos.x, pos.y);
if(colorEquals(pcolor, dest)){
pix.drawPixel(pos.x, pos.y);
if(pos.x > 0 && !set.contains(asInt(pos.x - 1, pos.y, width))) points.add(new GridPoint2(pos).cpy().add( -1, 0));
if(pos.y > 0 && !set.contains(asInt(pos.x, pos.y - 1, width))) points.add(new GridPoint2(pos).cpy().add(0, -1));
if(pos.x < pix.getWidth() - 1 && !set.contains(asInt(pos.x + 1, pos.y, width))) points.add(new GridPoint2(pos).cpy().add(1, 0));
if(pos.y < pix.getHeight() - 1 && !set.contains(asInt(pos.x, pos.y + 1, width))) points.add(new GridPoint2(pos).cpy().add(0, 1));
}
}
editor.updateTexture();
}
int asInt(int x, int y, int width){
return x+y*width;
}
boolean colorEquals(int a, int b){
return a == b;
}
},
pick{
public void touched(MapEditor editor, int x, int y){
Block block = ColorMapper.get(editor.pixmap().getPixel(x, y)).dominant();
editor.setDrawBlock(block);
Vars.ui.getEditor().updateSelectedBlock();
}
},
zoom;
public void touched(MapEditor editor, int x, int y){
}
}

View File

@ -19,6 +19,11 @@ public class MapEditor{
private Pixmap[] brushPixmaps = new Pixmap[brushSizes.length];
private Map map;
private MapFilter filter = new MapFilter();
private Pixmap filterPixmap;
private Texture filterTexture;
private Pixmap pixmap;
private Texture texture;
private int brushSize = 1;
@ -31,6 +36,44 @@ public class MapEditor{
}
}
public void updateTexture(){
texture.draw(pixmap, 0, 0);
}
public MapFilter getFilter(){
return filter;
}
public void applyFilterPreview(){
if(filterPixmap != null && (filterPixmap.getWidth() != pixmap.getWidth()
|| filterPixmap.getHeight() != pixmap.getHeight())){
filterPixmap.dispose();
filterTexture.dispose();
filterPixmap = null;
filterTexture = null;
}
if(filterPixmap == null){
filterPixmap = Pixmaps.copy(pixmap);
filter.process(filterPixmap);
filterTexture = new Texture(filterPixmap);
}else{
filterPixmap.drawPixmap(pixmap, 0, 0);
filter.process(filterPixmap);
filterTexture.draw(filterPixmap, 0, 0);
}
}
public Texture getFilterTexture(){
return filterTexture;
}
public void applyFilter(){
filter.process(pixmap);
texture.draw(pixmap, 0, 0);
}
public void beginEdit(Map map){
this.map = map;
this.brushSize = 1;
@ -87,7 +130,7 @@ public class MapEditor{
y = 0;
}
pixmap.fillCircle(dx, dy, brushSize);
pixmap.fillCircle(dx, dy, brushSize-1);
Pixmap dst = brush(brushSize);
dst.drawPixmap(pixmap, x, y, dstWidth, dstHeight, 0, 0, dstWidth, dstHeight);
@ -109,6 +152,10 @@ public class MapEditor{
return texture;
}
public Pixmap pixmap(){
return pixmap;
}
public void resize(int mapSize){
Pixmap out = Pixmaps.resize(pixmap, mapSize, mapSize);
pixmap.dispose();

View File

@ -5,6 +5,7 @@ import io.anuke.mindustry.world.ColorMapper;
import io.anuke.mindustry.world.ColorMapper.BlockPair;
import io.anuke.mindustry.world.Map;
import io.anuke.mindustry.world.blocks.Blocks;
import io.anuke.ucore.core.Core;
import io.anuke.ucore.core.Draw;
import io.anuke.ucore.scene.builders.*;
import io.anuke.ucore.scene.ui.*;
@ -14,10 +15,13 @@ import io.anuke.ucore.scene.ui.layout.Unit;
public class MapEditorDialog extends Dialog{
private MapEditor editor;
private MapView view;
private MapGenerateDialog dialog;
private ButtonGroup<ImageButton> blockgroup;
public MapEditorDialog(MapEditor editor){
super("Map Editor", "dialog");
this.editor = editor;
dialog = new MapGenerateDialog(editor);
view = new MapView(editor);
setFillParent(true);
@ -30,9 +34,23 @@ public class MapEditorDialog extends Dialog{
shown(() -> {
editor.beginEdit(new Map());
Core.scene.setScrollFocus(view);
});
}
public void updateSelectedBlock(){
Block block = editor.getDrawBlock();
int i = 0;
for(BlockPair pair : ColorMapper.getPairs()){
if(pair.wall == block || (pair.wall == Blocks.air && pair.floor == block)){
blockgroup.getButtons().get(i).setChecked(true);
break;
}
i++;
}
}
public void build(){
new table(){{
@ -40,8 +58,15 @@ public class MapEditorDialog extends Dialog{
aleft();
new table(){{
defaults().growY().width(130f).units(Unit.dp).padBottom(-6);
new imagebutton("icon-terrain", isize, () -> {
dialog.show();
}).text("generate").units(Unit.dp);
row();
new imagebutton("icon-load", isize, () -> {
}).text("load map");
@ -73,7 +98,7 @@ public class MapEditorDialog extends Dialog{
row();
new imagebutton("icon-arrow-left", isize, () -> {
hide();
}).padBottom(0).text("back");
}}.left().growY().end();
@ -83,9 +108,24 @@ public class MapEditorDialog extends Dialog{
}}.grow().end();
new table(){{
new imagebutton("icon-terrain", isize, () -> {
Table tools = new Table("button");
tools.top();
tools.padTop(0).padBottom(6);
ButtonGroup<ImageButton> group = new ButtonGroup<>();
int i = 0;
for(EditorTool tool : EditorTool.values()){
ImageButton button = new ImageButton("icon-" + tool.name(), "toggle");
button.clicked(() -> view.setTool(tool));
button.resizeImage(Unit.dp.inPixels(16*2f));
group.add(button);
}).margin(12f).text("generate...").width(148f).units(Unit.dp);
tools.add(button).size(80f, 85f).padBottom(-6f).units(Unit.dp);
if(i++ % 2 == 1) tools.row();
}
add(tools).units(Unit.dp).width(160f).padBottom(-6);
row();
@ -116,6 +156,7 @@ public class MapEditorDialog extends Dialog{
pane.setFadeScrollBars(false);
pane.setOverscroll(true, false);
ButtonGroup<ImageButton> group = new ButtonGroup<>();
blockgroup = group;
int i = 0;

View File

@ -16,33 +16,37 @@ import io.anuke.ucore.noise.Simplex;
import io.anuke.ucore.util.Mathf;
public class MapFilter{
private ObjectMap<String, Boolean> prefs = new OrderedMap<String, Boolean>(){
{
put("replace", true);
put("terrain", false);
put("circle", false);
put("distort", false);
put("sand", false);
put("grass", false);
put("stone", false);
put("allgrass", false);
put("allsnow", false);
put("allsand", false);
put("lavarock", false);
put("water", false);
put("oil", false);
put("lavariver", false);
put("slavariver", false);
put("river", false);
put("iceriver", false);
put("oilriver", false);
}
};
private ObjectMap<String, GenPref> prefs = map(
pref("replace", "whether to replace blocks"),
pref("terrain", "generate new terrain"),
pref("circle", "generate terrain in a circle"),
pref("distort", "distort the map image"),
pref("sand", "add patches of sand"),
pref("grass", "add patches of grass"),
pref("stone", "add patches of stone"),
pref("blackstone", "add patches of black stone"),
pref("allgrass", "fill map with grass"),
pref("allsnow", "fill map with snow"),
pref("allsand", "fill map with sand"),
pref("water", "add lakes"),
pref("oil", "add oil lakes"),
pref("lavariver", "add lava rivers"),
pref("slavariver", "ad small lava rivers"),
pref("river", "add rivers"),
pref("iceriver", "add frozen rivers"),
pref("oilriver", "add oil rivers")
);
private Simplex sim = new Simplex();
private RidgedPerlin rid = new RidgedPerlin(1, 10, 20f);
private RidgedPerlin rid2 = new RidgedPerlin(1, 6, 1f);
private RidgedPerlin rid3 = new RidgedPerlin(1, 6, 1f);
public MapFilter(){
prefs.get("replace").enabled = true;
prefs.get("terrain").enabled = true;
}
public void randomize(){
sim.setSeed(Mathf.random(999999));
rid.setSeed(Mathf.random(999999));
@ -50,16 +54,16 @@ public class MapFilter{
rid3.setSeed(Mathf.random(999999));
}
public ObjectMap<String, Boolean> getPrefs(){
public ObjectMap<String, GenPref> getPrefs(){
return prefs;
}
public Pixmap process(Pixmap pixmap){
if(prefs.get("terrain")){
if(prefs.get("terrain").enabled){
for(int x = 0; x < pixmap.getWidth(); x++){
for(int y = 0; y < pixmap.getHeight(); y++){
float dist = Vector2.dst((float) x / pixmap.getWidth(), (float) y / pixmap.getHeight(), 0.5f, 0.5f) * 2f;
double noise = sim.octaveNoise2D(6, 0.6, 1 / 180.0, x, y + 9999) / (prefs.get("circle") ? 1.7 : 1f) + dist / 10f;
double noise = sim.octaveNoise2D(6, 0.6, 1 / 180.0, x, y + 9999) / (prefs.get("circle").enabled ? 1.7 : 1f) + dist / 10f;
if(dist > 0.8){
noise += 2 * (dist - 0.8);
@ -78,7 +82,7 @@ public class MapFilter{
for(int y = 0; y < pixmap.getHeight(); y++){
int dx = 0, dy = 0;
if(prefs.get("distort")){
if(prefs.get("distort").enabled){
double intensity = 12;
double scale = 80;
double octaves = 4;
@ -105,41 +109,41 @@ public class MapFilter{
double noil = sim.octaveNoise2D(1, 1.0, 1 / 150.0, x + 9999, y) + sim.octaveNoise2D(1, 1.0, 1 / 2.0, x, y) / 290.0;
if(!floor || prefs.get("replace")){
if(!floor || prefs.get("replace").enabled){
if(prefs.get("allgrass")){
if(prefs.get("allgrass").enabled){
block = floor ? Blocks.grass : Blocks.grassblock;
}else if(prefs.get("allsnow")){
}else if(prefs.get("allsnow").enabled){
block = floor ? Blocks.snow : Blocks.snowblock;
}else if(prefs.get("allsand")){
}else if(prefs.get("allsand").enabled){
block = floor ? Blocks.sand : Blocks.sandblock;
}else if(prefs.get("replace")){
}else if(prefs.get("replace").enabled){
block = floor ? Blocks.stone : Blocks.stoneblock;
}
if(noise > 0.7 && prefs.get("grass")){
if(noise > 0.7 && prefs.get("grass").enabled){
block = floor ? Blocks.grass : Blocks.grassblock;
}
if(noise > 0.7 && prefs.get("lavarock")){
if(noise > 0.7 && prefs.get("blackstone").enabled){
block = floor ? Blocks.blackstone : Blocks.blackstoneblock;
}
if(noise > 0.7 && prefs.get("sand")){
if(noise > 0.7 && prefs.get("sand").enabled){
block = floor ? Blocks.sand : Blocks.sandblock;
}
if(noise > 0.8 && prefs.get("stone")){
if(noise > 0.8 && prefs.get("stone").enabled){
block = floor ? Blocks.stone : Blocks.stoneblock;
}
}
if(floor){
if(nwater > 0.93 && prefs.get("water")){
if(nwater > 0.93 && prefs.get("water").enabled){
block = Blocks.water;
if(nwater > 0.943){
block = Blocks.deepwater;
}
}
if(noil > 0.95 && prefs.get("oil")){
if(noil > 0.95 && prefs.get("oil").enabled){
block = Blocks.dirt;
if(noil > 0.955){
block = Blocks.oil;
@ -147,7 +151,7 @@ public class MapFilter{
}
}
if(floor && prefs.get("lavariver")){
if(floor && prefs.get("lavariver").enabled){
double lava = rid.getValue(x, y, 1 / 100f);
double t = 0.6;
if(lava > t){
@ -157,7 +161,7 @@ public class MapFilter{
}
}
if(floor && prefs.get("slavariver")){
if(floor && prefs.get("slavariver").enabled){
double lava = rid.getValue(x, y, 1 / 40f);
double t = 0.7;
if(lava > t){
@ -167,7 +171,7 @@ public class MapFilter{
}
}
if(floor && prefs.get("oilriver")){
if(floor && prefs.get("oilriver").enabled){
double lava = rid3.getValue(x, y, 1 / 100f);
double t = 0.9;
if(lava > t){
@ -177,7 +181,7 @@ public class MapFilter{
}
}
if(floor && prefs.get("river")){
if(floor && prefs.get("river").enabled){
double riv = rid2.getValue(x, y, 1 / 140f);
double t = 0.4;
@ -190,7 +194,7 @@ public class MapFilter{
}
}
if(floor && prefs.get("iceriver")){
if(floor && prefs.get("iceriver").enabled){
double riv = rid2.getValue(x, y, 1 / 140f);
double t = 0.4;
@ -211,4 +215,29 @@ public class MapFilter{
return pixmap;
}
private static OrderedMap<String, GenPref> map(GenPref...objects){
OrderedMap<String, GenPref> prefs = new OrderedMap<>();
for(int i = 0; i < objects.length; i ++){
GenPref pref = (GenPref)objects[i];
prefs.put(pref.name, pref);
}
return prefs;
}
private GenPref pref(String name, String desc){
return new GenPref(name, desc);
}
class GenPref{
public final String name;
public final String description;
public boolean enabled;
GenPref(String name, String description){
this.name = name;
this.description = description;
}
}
}

View File

@ -1,5 +1,97 @@
package io.anuke.mindustry.mapeditor;
public class MapGenerateDialog{
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.utils.Align;
import com.badlogic.gdx.utils.Scaling;
import io.anuke.mindustry.mapeditor.MapFilter.GenPref;
import io.anuke.mindustry.ui.BorderImage;
import io.anuke.mindustry.ui.FloatingDialog;
import io.anuke.ucore.core.Timers;
import io.anuke.ucore.scene.style.TextureRegionDrawable;
import io.anuke.ucore.scene.ui.CheckBox;
import io.anuke.ucore.scene.ui.Image;
import io.anuke.ucore.scene.ui.ScrollPane;
import io.anuke.ucore.scene.ui.layout.Stack;
import io.anuke.ucore.scene.ui.layout.Table;
import io.anuke.ucore.scene.ui.layout.Unit;
public class MapGenerateDialog extends FloatingDialog{
private MapEditor editor;
private Image image;
private boolean loading;
public MapGenerateDialog(MapEditor editor) {
super("generate");
this.editor = editor;
Stack stack = new Stack();
stack.add(image = new BorderImage());
Image loadImage = new Image("icon-loading");
loadImage.setScaling(Scaling.none);
loadImage.setScale(3f);
loadImage.update(() -> loadImage.setOrigin(Align.center));
loadImage.setVisible(() -> loading);
Image next = new Image("white");
next.setScaling(Scaling.fit);
next.setColor(0, 0, 0, 0.6f);
next.setVisible(() -> loading);
stack.add(next);
stack.add(loadImage);
content().add(stack).grow();
image.setScaling(Scaling.fit);
Table preft = new Table();
preft.left();
preft.pad(Unit.dp.inPixels(4f)).padRight(Unit.dp.inPixels(25f));
for(GenPref pref : editor.getFilter().getPrefs().values()){
CheckBox box = new CheckBox(pref.name);
box.setChecked(pref.enabled);
box.changed(() -> pref.enabled = box.isChecked());
preft.add(box).pad(4f).units(Unit.dp).left();
preft.row();
}
ScrollPane pane = new ScrollPane(preft, "volume");
pane.setFadeScrollBars(false);
pane.setScrollingDisabled(true, false);
content().add(pane).fillY();
buttons().defaults().size(170f, 50f).units(Unit.dp).pad(4f);
buttons().addButton("Back", () -> hide());
buttons().addButton("Randomize", () ->{
editor.getFilter().randomize();
apply();
});
buttons().addButton("Update", () ->{
apply();
});
buttons().addButton("Apply", () ->{
editor.applyFilter();
hide();
});
shown(() ->{
loading = true;
Timers.run(30f, () -> {
editor.applyFilterPreview();
image.setDrawable(new TextureRegionDrawable(new TextureRegion(editor.getFilterTexture())));
loading = false;
});
});
}
private void apply(){
loading = true;
Timers.run(3f, ()->{
editor.applyFilterPreview();
loading = false;
});
}
}

View File

@ -1,21 +1,42 @@
package io.anuke.mindustry.mapeditor;
import com.badlogic.gdx.graphics.Colors;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.input.GestureDetector;
import com.badlogic.gdx.input.GestureDetector.GestureListener;
import com.badlogic.gdx.math.Bresenham2;
import com.badlogic.gdx.math.GridPoint2;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.scenes.scene2d.utils.ScissorStack;
import com.badlogic.gdx.utils.Array;
import io.anuke.mindustry.Vars;
import io.anuke.ucore.core.Core;
import io.anuke.ucore.core.Draw;
import io.anuke.ucore.core.Inputs;
import io.anuke.ucore.scene.Element;
import io.anuke.ucore.scene.event.InputEvent;
import io.anuke.ucore.scene.event.InputListener;
import io.anuke.ucore.scene.ui.layout.Unit;
import io.anuke.ucore.util.Mathf;
import io.anuke.ucore.util.Tmp;
public class MapView extends Element{
public class MapView extends Element implements GestureListener{
private MapEditor editor;
private EditorTool tool = EditorTool.pencil;
private Bresenham2 br = new Bresenham2();
private float offsetx, offsety;
private float zoom = 1f;
public void setTool(EditorTool tool){
this.tool = tool;
}
public MapView(MapEditor editor){
this.editor = editor;
Inputs.addProcessor(0, new GestureDetector(20, 0.5f, 2, 0.15f, this));
addListener(new InputListener(){
int lastx, lasty;
boolean drawing;
@ -25,7 +46,9 @@ public class MapView extends Element{
GridPoint2 p = project(x, y);
lastx = p.x;
lasty = p.y;
editor.draw(p.x, p.y);
tool.touched(editor, p.x, p.y);
drawing = true;
return true;
}
@ -38,29 +61,131 @@ public class MapView extends Element{
public void touchDragged (InputEvent event, float x, float y, int pointer) {
GridPoint2 p = project(x, y);
if(drawing){
if(drawing && tool == EditorTool.pencil){
Array<GridPoint2> points = br.line(lastx, lasty, p.x, p.y);
for(GridPoint2 point : points){
editor.draw(point.x, point.y);
}
}
drawing = true;
lastx = p.x;
lasty = p.y;
}
});
addListener(new InputListener(){
@Override
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
return tool == EditorTool.zoom;
}
@Override
public void touchDragged (InputEvent event, float x, float y, int pointer) {
//offsetx += Gdx.input.getDeltaX(pointer) / zoom;
//offsety -= Gdx.input.getDeltaY(pointer) / zoom;
}
});
}
@Override
public void act(float delta){
super.act(delta);
float size = Math.min(width, height);
offsetx = Mathf.clamp(offsetx, -size, size);
offsety = Mathf.clamp(offsety, -size, size);
if(tool != EditorTool.zoom) return;
zoom += Inputs.scroll()/10f * zoom;
clampZoom();
}
private void clampZoom(){
zoom = Mathf.clamp(zoom, 0.4f, 6f);
}
private GridPoint2 project(float x, float y){
float size = Math.min(width, height);
x = (x - getWidth()/2 + size/2) / size * editor.texture().getWidth();
y = (y - getHeight()/2 + size/2) / size * editor.texture().getHeight();
float size = Math.min(width, height)*zoom;
x = (x - getWidth()/2 + size/2 - offsetx*zoom) / size * editor.texture().getWidth();
y = (y - getHeight()/2 + size/2 - offsety*zoom) / size * editor.texture().getHeight();
return Tmp.g1.set((int)x, editor.texture().getHeight() - 1 - (int)y);
}
@Override
public void draw(Batch batch, float alpha){
float size = Math.min(width, height);
batch.draw(editor.texture(), x + width/2 - size/2, y + height/2 - size/2, size, size);
float sclsize = size * zoom;
float centerx = x + width/2 + offsetx * zoom;
float centery = y + height/2 + offsety * zoom;
batch.flush();
ScissorStack.pushScissors(Tmp.r1.set(x + width/2 - size/2, y + height/2 - size/2, size, size));
batch.draw(editor.texture(), centerx - sclsize/2, centery - sclsize/2, sclsize, sclsize);
batch.flush();
ScissorStack.popScissors();
Draw.color(Colors.get("accent"));
Draw.thick(Unit.dp.inPixels(3f));
Draw.linerect(x + width/2 - size/2, y + height/2 - size/2, size, size);
Draw.reset();
}
private boolean active(){
return Core.scene.getKeyboardFocus().isDescendantOf(Vars.ui.getEditor()) && Vars.ui.isEditing() && tool == EditorTool.zoom;
}
@Override
public boolean touchDown(float x, float y, int pointer, int button){
return false;
}
@Override
public boolean tap(float x, float y, int count, int button){
return false;
}
@Override
public boolean longPress(float x, float y){
return false;
}
@Override
public boolean fling(float velocityX, float velocityY, int button){
return false;
}
@Override
public boolean pan(float x, float y, float deltaX, float deltaY){
if(!active()) return false;
offsetx += deltaX / zoom;
offsety -= deltaY / zoom;
return false;
}
@Override
public boolean panStop(float x, float y, int pointer, int button){
return false;
}
@Override
public boolean zoom(float initialDistance, float distance){
if(!active()) return false;
float nzoom = distance - initialDistance;
zoom += nzoom / 2000f / Unit.dp.inPixels(1f) * zoom;
clampZoom();
return false;
}
@Override
public boolean pinch(Vector2 initialPointer1, Vector2 initialPointer2, Vector2 pointer1, Vector2 pointer2){
return false;
}
@Override
public void pinchStop(){
}
}

View File

@ -0,0 +1,24 @@
package io.anuke.mindustry.ui;
import com.badlogic.gdx.graphics.Colors;
import com.badlogic.gdx.graphics.g2d.Batch;
import io.anuke.ucore.core.Draw;
import io.anuke.ucore.scene.ui.Image;
import io.anuke.ucore.scene.ui.layout.Unit;
public class BorderImage extends Image{
@Override
public void draw(Batch batch, float alpha){
super.draw(batch, alpha);
float scaleX = getScaleX();
float scaleY = getScaleY();
Draw.color(Colors.get("accent"));
Draw.thick(Unit.dp.inPixels(3f));
Draw.linerect(x + imageX, y + imageY, imageWidth * scaleX, imageHeight * scaleY);
Draw.reset();
}
}

View File

@ -69,6 +69,10 @@ public class ColorMapper{
public static class BlockPair{
public final Block floor, wall;
public Block dominant(){
return wall == Blocks.air ? floor : wall;
}
private BlockPair(Block floor, Block wall){
this.floor = floor;
this.wall = wall;

View File

@ -55,7 +55,7 @@ public class ProductionBlocks{
requirements = new Item[]{Item.coal, Item.iron};
result = Item.steel;
description = "Converts coal + iron to steel.";
fullDescription = "The essential crafting block. When inputted 1x iron and 1x iron, outputs one steel.";
fullDescription = "The essential crafting block. When inputted 1x iron and 1x coal, outputs one steel.";
}
},

View File

@ -75,7 +75,7 @@ public class ShieldBlock extends PowerBlock{
}
bullet.remove();
Effects.effect(Fx.laserhit, bullet);
Effects.effect(bullet.damage > 5 ? Fx.shieldhit : Fx.laserhit, bullet);
Vars.renderer.addShieldHit(bullet.x, bullet.y);
entity.power -= bullet.getDamage() * powerPerDamage;

View File

@ -31,7 +31,6 @@ public class TunnelConveyor extends Block{
if(to == null || to.entity == null) return;
to.block().handleItem(item, to, tunnel);
});
}
@Override

View File

@ -1,18 +0,0 @@
package io.anuke.mindustry.desktop;
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3Application;
import com.badlogic.gdx.backends.lwjgl3.Lwjgl3ApplicationConfiguration;
import io.anuke.mindustry.editor.Editor;
public class EditorLauncher{
public static void main (String[] arg) {
Lwjgl3ApplicationConfiguration config = new Lwjgl3ApplicationConfiguration();
config.setTitle("Mindustry Editor");
config.setMaximized(true);
config.setWindowedMode(800, 600);
config.setWindowIcon("sprites/icon.png");
new Lwjgl3Application(new Editor(), config);
}
}