mirror of
https://github.com/Anuken/Mindustry.git
synced 2026-01-17 14:51:15 -08:00
Improved generation tool
This commit is contained in:
parent
97067a6ee2
commit
e7ffbd817c
13 changed files with 388 additions and 126 deletions
|
|
@ -212,6 +212,7 @@ editor.errorload = Error loading file:\n[accent]{0}
|
|||
editor.errorsave = Error saving file:\n[accent]{0}
|
||||
editor.errorname = Map has no name defined.
|
||||
editor.update = Update
|
||||
editor.randomize = Randomize
|
||||
editor.apply = Apply
|
||||
editor.generate = Generate
|
||||
editor.resize = Resize
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import io.anuke.arc.graphics.glutils.FrameBuffer;
|
|||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.math.geom.Rectangle;
|
||||
import io.anuke.arc.math.geom.Vector2;
|
||||
import io.anuke.arc.util.ScreenRecorder;
|
||||
import io.anuke.arc.util.Time;
|
||||
import io.anuke.arc.util.Tmp;
|
||||
import io.anuke.arc.util.pooling.Pools;
|
||||
|
|
@ -131,10 +130,6 @@ public class Renderer implements ApplicationListener{
|
|||
|
||||
draw();
|
||||
}
|
||||
|
||||
if(!ui.chatfrag.chatOpen()){
|
||||
ScreenRecorder.record(); //this only does something if CoreGifRecorder is on the class path, which it usually isn't
|
||||
}
|
||||
}
|
||||
|
||||
void updateShake(float scale){
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@ public class MapEditor{
|
|||
tiles = createTiles(map.width, map.height);
|
||||
tags.putAll(map.tags);
|
||||
MapIO.readTiles(map, tiles);
|
||||
checkTiles();
|
||||
checkLinkedTiles();
|
||||
renderer.resize(width(), height());
|
||||
loading = false;
|
||||
}
|
||||
|
|
@ -61,12 +61,12 @@ public class MapEditor{
|
|||
reset();
|
||||
|
||||
this.tiles = tiles;
|
||||
checkTiles();
|
||||
checkLinkedTiles();
|
||||
renderer.resize(width(), height());
|
||||
}
|
||||
|
||||
//adds missing blockparts
|
||||
void checkTiles(){
|
||||
public void checkLinkedTiles(){
|
||||
//clear block parts first
|
||||
for(int x = 0; x < width(); x ++){
|
||||
for(int y = 0; y < height(); y++){
|
||||
|
|
|
|||
|
|
@ -1,32 +1,49 @@
|
|||
package io.anuke.mindustry.editor;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.collection.Array;
|
||||
import io.anuke.arc.function.Supplier;
|
||||
import io.anuke.arc.graphics.Pixmap;
|
||||
import io.anuke.arc.graphics.Pixmap.Format;
|
||||
import io.anuke.arc.graphics.Texture;
|
||||
import io.anuke.arc.scene.Element;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.mindustry.editor.generation.FilterOption;
|
||||
import io.anuke.mindustry.editor.generation.GenerateFilter;
|
||||
import io.anuke.arc.util.Scaling;
|
||||
import io.anuke.arc.util.async.AsyncExecutor;
|
||||
import io.anuke.arc.util.async.AsyncResult;
|
||||
import io.anuke.mindustry.content.Blocks;
|
||||
import io.anuke.mindustry.editor.generation.*;
|
||||
import io.anuke.mindustry.editor.generation.GenerateFilter.GenerateInput;
|
||||
import io.anuke.mindustry.editor.generation.NoiseFilter;
|
||||
import io.anuke.mindustry.game.Team;
|
||||
import io.anuke.mindustry.graphics.Pal;
|
||||
import io.anuke.mindustry.io.MapIO;
|
||||
import io.anuke.mindustry.ui.BorderImage;
|
||||
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
||||
import io.anuke.mindustry.world.DummyTile;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.blocks.Floor;
|
||||
|
||||
import static io.anuke.mindustry.Vars.mobile;
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public class MapGenerateDialog extends FloatingDialog{
|
||||
private final MapEditor editor;
|
||||
private Pixmap pixmap;
|
||||
private Texture texture;
|
||||
private GenerateInput input = new GenerateInput();
|
||||
private Array<GenerateFilter> filters = new Array<>();
|
||||
private int scaling = mobile ? 3 : 1;
|
||||
private Supplier<GenerateFilter>[] filterTypes = new Supplier[]{NoiseFilter::new, ScatterFilter::new, TerrainFilter::new, DistortFilter::new, RiverNoiseFilter::new};
|
||||
private Table filterTable;
|
||||
|
||||
private AsyncExecutor executor = new AsyncExecutor(1);
|
||||
private AsyncResult<Void> result;
|
||||
private boolean generating;
|
||||
private DummyTile returnTile = new DummyTile();
|
||||
|
||||
private DummyTile[][] buffer1, buffer2;
|
||||
|
||||
public MapGenerateDialog(MapEditor editor){
|
||||
super("editor.generate");
|
||||
super("$editor.generate");
|
||||
this.editor = editor;
|
||||
|
||||
shown(this::setup);
|
||||
|
|
@ -35,9 +52,17 @@ public class MapGenerateDialog extends FloatingDialog{
|
|||
apply();
|
||||
hide();
|
||||
}).size(180f, 64f);
|
||||
buttons.addButton("$editor.randomize", () -> {
|
||||
for(GenerateFilter filter : filters){
|
||||
filter.randomize();
|
||||
}
|
||||
update();
|
||||
}).size(180f, 64f);
|
||||
}
|
||||
|
||||
void setup(){
|
||||
filters.clear();
|
||||
|
||||
if(pixmap != null){
|
||||
pixmap.dispose();
|
||||
texture.dispose();
|
||||
|
|
@ -45,123 +70,246 @@ public class MapGenerateDialog extends FloatingDialog{
|
|||
texture = null;
|
||||
}
|
||||
|
||||
pixmap = new Pixmap(editor.width(), editor.height(), Format.RGBA8888);
|
||||
pixmap = new Pixmap(editor.width() / scaling, editor.height() / scaling, Format.RGBA8888);
|
||||
texture = new Texture(pixmap);
|
||||
|
||||
cont.clear();
|
||||
cont.table("flat", t -> {
|
||||
t.margin(8f);
|
||||
t.add(new BorderImage(texture)).size(500f).padRight(6);
|
||||
t.add(new BorderImage(texture)).grow().padRight(6).top().get().setScaling(Scaling.fit);
|
||||
t.table(right -> {
|
||||
Table[] fs = {null};
|
||||
Runnable rebuild = () -> {
|
||||
Table p = fs[0];
|
||||
p.clearChildren();
|
||||
|
||||
for(GenerateFilter filter : filters){
|
||||
p.table("button", f -> {
|
||||
f.left();
|
||||
for(FilterOption option : filter.options){
|
||||
option.build(f);
|
||||
f.row();
|
||||
}
|
||||
for(Element e : f.getChildren()){
|
||||
e.changed(this::update);
|
||||
}
|
||||
}).pad(3).width(280f);
|
||||
p.row();
|
||||
}
|
||||
};
|
||||
|
||||
right.pane(p -> {
|
||||
p.top();
|
||||
fs[0] = p;
|
||||
}).fill().width(300f).growY().get().setScrollingDisabled(true, false);
|
||||
right.pane(p -> filterTable = p).grow().get().setScrollingDisabled(true, false);
|
||||
right.row();
|
||||
right.addButton("$add", () -> {
|
||||
filters.add(new NoiseFilter());
|
||||
rebuild.run();
|
||||
}).fillX().height(50f);
|
||||
right.addButton("$add", this::showAdd).fillX().height(50f);
|
||||
}).grow();
|
||||
|
||||
t.row();
|
||||
t.addButton("$editor.update", () -> {
|
||||
input.randomize();
|
||||
update();
|
||||
}).size(300f, 66f).colspan(2).pad(6);
|
||||
});
|
||||
}).grow();
|
||||
|
||||
update();
|
||||
|
||||
buffer1 = create();
|
||||
buffer2 = create();
|
||||
}
|
||||
|
||||
DummyTile[][] create(){
|
||||
DummyTile[][] out = new DummyTile[editor.width() / scaling][editor.height() / scaling];
|
||||
|
||||
for(int x = 0; x < out.length; x++){
|
||||
for(int y = 0; y < out[0].length; y++){
|
||||
out[x][y] = new DummyTile();
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
void rebuildFilters(){
|
||||
filterTable.clearChildren();
|
||||
filterTable.top();
|
||||
|
||||
for(GenerateFilter filter : filters){
|
||||
filterTable.table(t -> {
|
||||
t.add(filter.name()).padTop(5).color(Pal.accent).growX().left();
|
||||
|
||||
t.row();
|
||||
|
||||
t.table(b -> {
|
||||
b.left();
|
||||
b.defaults().size(50f);
|
||||
b.addImageButton("icon-refresh", 14*2, () -> {
|
||||
filter.randomize();
|
||||
update();
|
||||
});
|
||||
|
||||
b.addImageButton("icon-arrow-up", 10*2, () -> {
|
||||
int idx = filters.indexOf(filter);
|
||||
filters.swap(idx, Math.max(0, idx - 1));
|
||||
rebuildFilters();
|
||||
update();
|
||||
});
|
||||
b.addImageButton("icon-arrow-down", 10*2, () -> {
|
||||
int idx = filters.indexOf(filter);
|
||||
filters.swap(idx, Math.min(filters.size-1, idx + 1));
|
||||
rebuildFilters();
|
||||
update();
|
||||
});
|
||||
b.addImageButton("icon-trash", 14*2, () -> {
|
||||
filters.remove(filter);
|
||||
rebuildFilters();
|
||||
update();
|
||||
});
|
||||
}).growX();
|
||||
}).fillX();
|
||||
filterTable.row();
|
||||
filterTable.table("underline", f -> {
|
||||
f.left();
|
||||
for(FilterOption option : filter.options){
|
||||
option.changed = this::update;
|
||||
|
||||
f.table(t -> {
|
||||
t.left();
|
||||
option.build(t);
|
||||
}).growX().left();
|
||||
f.row();
|
||||
}
|
||||
}).pad(3).padTop(0).width(280f);
|
||||
filterTable.row();
|
||||
}
|
||||
}
|
||||
|
||||
void showAdd(){
|
||||
FloatingDialog selection = new FloatingDialog("");
|
||||
selection.setFillParent(false);
|
||||
selection.cont.defaults().size(210f, 60f);
|
||||
for(Supplier<GenerateFilter> gen : filterTypes){
|
||||
GenerateFilter filter = gen.get();
|
||||
selection.cont.addButton(filter.name(), () -> {
|
||||
filters.add(filter);
|
||||
rebuildFilters();
|
||||
update();
|
||||
selection.hide();
|
||||
});
|
||||
selection.cont.row();
|
||||
}
|
||||
|
||||
selection.addCloseButton();
|
||||
selection.show();
|
||||
}
|
||||
|
||||
DummyTile dset(Tile tile){
|
||||
returnTile.set(tile);
|
||||
return returnTile;
|
||||
}
|
||||
|
||||
void apply(){
|
||||
Tile[][] writeTiles = new Tile[editor.width()][editor.height()];
|
||||
if(result != null){
|
||||
result.get();
|
||||
}
|
||||
|
||||
//writeback buffer
|
||||
DummyTile[][] writeTiles = new DummyTile[editor.width()][editor.height()];
|
||||
|
||||
for(int x = 0; x < editor.width(); x++){
|
||||
for(int y = 0; y < editor.height(); y++){
|
||||
writeTiles[x][y] = new DummyTile(x, y);
|
||||
writeTiles[x][y] = new DummyTile();
|
||||
}
|
||||
}
|
||||
|
||||
for(GenerateFilter filter : filters){
|
||||
input.setFilter(filter, (x, y) -> dset(editor.tile(x, y)));
|
||||
//write to buffer
|
||||
for(int x = 0; x < editor.width(); x++){
|
||||
for(int y = 0; y < editor.height(); y++){
|
||||
Tile tile = editor.tile(x, y);
|
||||
Tile write = writeTiles[x][y];
|
||||
input.begin(editor, x, y, tile.floor(), tile.block(), tile.ore());
|
||||
filter.apply(input);
|
||||
write.setRotation(tile.getRotation());
|
||||
write.setOre(input.ore);
|
||||
write.setFloor((Floor)input.floor);
|
||||
write.setBlock(input.block);
|
||||
write.setTeam(tile.getTeam());
|
||||
writeTiles[x][y].set(input.floor, input.block, input.ore, tile.getTeam(), tile.getRotation());
|
||||
}
|
||||
}
|
||||
|
||||
editor.load(() -> {
|
||||
//read from buffer back into tiles
|
||||
for(int x = 0; x < editor.width(); x++){
|
||||
for(int y = 0; y < editor.height(); y++){
|
||||
Tile tile = editor.tile(x, y);
|
||||
Tile write = writeTiles[x][y];
|
||||
DummyTile write = writeTiles[x][y];
|
||||
|
||||
tile.setRotation(write.getRotation());
|
||||
tile.setOre(write.ore());
|
||||
tile.setFloor(write.floor());
|
||||
tile.setBlock(write.block());
|
||||
tile.setTeam(write.getTeam());
|
||||
tile.setRotation((byte)write.rotation);
|
||||
tile.setFloor((Floor)write.floor);
|
||||
tile.setBlock(write.block);
|
||||
tile.setTeam(write.team);
|
||||
tile.setOre(write.ore);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
//reset undo stack as generation... messes things up
|
||||
editor.load(editor::checkLinkedTiles);
|
||||
editor.renderer().updateAll();
|
||||
editor.clearOp();
|
||||
}
|
||||
|
||||
void update(){
|
||||
|
||||
boolean modified = false;
|
||||
for(GenerateFilter filter : filters){
|
||||
modified = true;
|
||||
for(int x = 0; x < editor.width(); x++){
|
||||
for(int y = 0; y < editor.height(); y++){
|
||||
Tile tile = editor.tile(x, y);
|
||||
input.begin(editor, x, y, tile.floor(), tile.block(), tile.ore());
|
||||
filter.apply(input);
|
||||
pixmap.drawPixel(x, pixmap.getHeight() - 1 - y, MapIO.colorFor(input.floor, input.block, input.ore, Team.none));
|
||||
}
|
||||
}
|
||||
if(generating){
|
||||
return;
|
||||
}
|
||||
|
||||
if(!modified){
|
||||
for(int x = 0; x < editor.width(); x++){
|
||||
for(int y = 0; y < editor.height(); y++){
|
||||
Tile tile = editor.tile(x, y);
|
||||
pixmap.drawPixel(x, pixmap.getHeight() - 1 - y, MapIO.colorFor(tile.floor(), tile.block(), tile.ore(), Team.none));
|
||||
Array<GenerateFilter> copy = new Array<>(filters);
|
||||
|
||||
result = executor.submit(() -> {
|
||||
generating = true;
|
||||
|
||||
if(!filters.isEmpty()){
|
||||
//write to buffer1 for reading
|
||||
for(int px = 0; px < pixmap.getWidth(); px++){
|
||||
for(int py = 0; py < pixmap.getHeight(); py++){
|
||||
buffer1[px][py].set(editor.tile(px * scaling, py * scaling));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(GenerateFilter filter : copy){
|
||||
input.setFilter(filter, (x, y) -> buffer1[x][y]);
|
||||
//read from buffer1 and write to buffer2
|
||||
for(int px = 0; px < pixmap.getWidth(); px++){
|
||||
for(int py = 0; py < pixmap.getHeight(); py++){
|
||||
int x = px*scaling, y = py*scaling;
|
||||
DummyTile tile = buffer1[px][py];
|
||||
input.begin(editor, x, y, tile.floor, tile.block, tile.ore);
|
||||
filter.apply(input);
|
||||
buffer2[px][py].set(input.floor, input.block, input.ore, tile.team, tile.rotation);
|
||||
}
|
||||
}
|
||||
for(int px = 0; px < pixmap.getWidth(); px++){
|
||||
for(int py = 0; py < pixmap.getHeight(); py++){
|
||||
buffer1[px][py].set(buffer2[px][py]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(int px = 0; px < pixmap.getWidth(); px++){
|
||||
for(int py = 0; py < pixmap.getHeight(); py++){
|
||||
int color;
|
||||
//get result from buffer1 if there's filters left, otherwise get from editor directly
|
||||
if(filters.isEmpty()){
|
||||
Tile tile = editor.tile(px * scaling, py * scaling);
|
||||
color = MapIO.colorFor(tile.floor(), tile.block(), tile.ore(), Team.none);
|
||||
}else{
|
||||
DummyTile tile = buffer1[px][py];
|
||||
color = MapIO.colorFor(tile.floor, tile.block, tile.ore, Team.none);
|
||||
}
|
||||
pixmap.drawPixel(px, pixmap.getHeight() - 1 - py, color);
|
||||
}
|
||||
}
|
||||
|
||||
Core.app.post(() -> {
|
||||
texture.draw(pixmap, 0, 0);
|
||||
generating = false;
|
||||
});
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
public static class DummyTile{
|
||||
public Block block = Blocks.air, ore = Blocks.air, floor = Blocks.air;
|
||||
public Team team = Team.none;
|
||||
public int rotation;
|
||||
|
||||
void set(Block floor, Block wall, Block ore, Team team, int rotation){
|
||||
this.floor = floor;
|
||||
this.block = wall;
|
||||
this.ore = ore;
|
||||
this.team = team;
|
||||
this.rotation = rotation;
|
||||
}
|
||||
|
||||
void set(DummyTile other){
|
||||
set(other.floor, other.block, other.ore, other.team, other.rotation);
|
||||
}
|
||||
|
||||
void set(Tile other){
|
||||
set(other.floor(), other.block(), other.ore(), other.getTeam(), other.getRotation());
|
||||
}
|
||||
|
||||
texture.draw(pixmap, 0, 0);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,24 +1,25 @@
|
|||
package io.anuke.mindustry.editor.generation;
|
||||
|
||||
import io.anuke.mindustry.editor.MapGenerateDialog.DummyTile;
|
||||
import io.anuke.mindustry.editor.generation.FilterOption.SliderOption;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.blocks.Floor;
|
||||
|
||||
public class DistortFilter extends GenerateFilter{
|
||||
float scl = 40, mag = 5;
|
||||
|
||||
{
|
||||
options(
|
||||
new SliderOption("scale", () -> scl, f -> scl = f, 1f, 1000f),
|
||||
new SliderOption("mag", () -> mag, f -> mag = f, 0.5f, 10f)
|
||||
new SliderOption("scale", () -> scl, f -> scl = f, 1f, 400f),
|
||||
new SliderOption("mag", () -> mag, f -> mag = f, 0.5f, 100f)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(){
|
||||
Tile tile = in.tile(in.x + noise(in.x, in.y, scl, mag)-mag/2f, in.y + noise(in.x, in.y+o, scl, mag)-mag/2f);
|
||||
DummyTile tile = in.tile(in.x + noise(in.x, in.y, scl, mag)-mag/2f, in.y + noise(in.x, in.y+o, scl, mag)-mag/2f);
|
||||
|
||||
in.floor = tile.floor();
|
||||
if(!tile.block().synthetic() && !in.block.synthetic()) in.block = tile.block();
|
||||
in.ore = tile.ore();
|
||||
in.floor = tile.floor;
|
||||
if(!tile.block.synthetic() && !in.block.synthetic()) in.block = tile.block;
|
||||
if(!((Floor)in.floor).isLiquid) in.ore = tile.ore;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package io.anuke.mindustry.editor.generation;
|
|||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.function.*;
|
||||
import io.anuke.arc.scene.style.TextureRegionDrawable;
|
||||
import io.anuke.arc.scene.ui.Slider;
|
||||
import io.anuke.arc.scene.ui.layout.Table;
|
||||
import io.anuke.mindustry.Vars;
|
||||
import io.anuke.mindustry.ui.dialogs.FloatingDialog;
|
||||
|
|
@ -16,6 +17,7 @@ public abstract class FilterOption{
|
|||
public static final Predicate<Block> wallsOnly = b -> (!b.synthetic() && !(b instanceof Floor)) && Core.atlas.isFound(b.icon(Icon.full));
|
||||
|
||||
public abstract void build(Table table);
|
||||
public Runnable changed = () -> {};
|
||||
|
||||
static class SliderOption extends FilterOption{
|
||||
final String name;
|
||||
|
|
@ -35,7 +37,9 @@ public abstract class FilterOption{
|
|||
public void build(Table table){
|
||||
table.add(name);
|
||||
table.row();
|
||||
table.addSlider(min, max, (max-min)/100f, setter).get().setValue(getter.get());
|
||||
Slider slider = table.addSlider(min, max, (max-min)/200f, setter).growX().get();
|
||||
slider.setValue(getter.get());
|
||||
slider.changed(changed);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -54,7 +58,6 @@ public abstract class FilterOption{
|
|||
|
||||
@Override
|
||||
public void build(Table table){
|
||||
table.add(name + ": ");
|
||||
table.addButton(b -> {
|
||||
b.addImage(supplier.get().icon(Icon.small)).update(i -> ((TextureRegionDrawable)i.getDrawable()).setRegion(supplier.get().icon(Icon.small))).size(8*3);
|
||||
}, () -> {
|
||||
|
|
@ -65,14 +68,17 @@ public abstract class FilterOption{
|
|||
if(!filter.test(block)) continue;
|
||||
|
||||
dialog.cont.addImage(block.icon(Icon.medium)).size(8*4).pad(3).get().clicked(() -> {
|
||||
consumer.accept(block);
|
||||
dialog.hide();
|
||||
consumer.accept(block);
|
||||
dialog.hide();
|
||||
changed.run();
|
||||
});
|
||||
if(++i % 10 == 0) dialog.cont.row();
|
||||
}
|
||||
|
||||
dialog.show();
|
||||
});
|
||||
}).pad(4).margin(12f);
|
||||
|
||||
table.add(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,18 @@
|
|||
package io.anuke.mindustry.editor.generation;
|
||||
|
||||
import io.anuke.arc.Core;
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.arc.util.Pack;
|
||||
import io.anuke.arc.util.noise.RidgedPerlin;
|
||||
import io.anuke.arc.util.noise.Simplex;
|
||||
import io.anuke.mindustry.editor.MapEditor;
|
||||
import io.anuke.mindustry.editor.MapGenerateDialog.DummyTile;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
import io.anuke.mindustry.world.Tile;
|
||||
import io.anuke.mindustry.world.blocks.Floor;
|
||||
|
||||
public abstract class GenerateFilter{
|
||||
protected float o = (float)(Math.random()*10000000.0);
|
||||
protected long seed;
|
||||
protected GenerateInput in;
|
||||
|
||||
public FilterOption[] options;
|
||||
|
|
@ -23,10 +27,26 @@ public abstract class GenerateFilter{
|
|||
return (float)in.noise.octaveNoise2D(octaves, persistence, 1f/scl, x + o, y + o)*mag;
|
||||
}
|
||||
|
||||
protected float rnoise(float x, float y, float scl, float mag){
|
||||
return in.pnoise.getValue((int)(x + o), (int)(y + o), 1f/scl)*mag;
|
||||
}
|
||||
|
||||
public void randomize(){
|
||||
seed = Mathf.random(99999999);
|
||||
}
|
||||
|
||||
protected float chance(){
|
||||
return Mathf.randomSeed(Pack.longInt(in.x, in.y + (int)o));
|
||||
}
|
||||
|
||||
public void options(FilterOption... options){
|
||||
this.options = options;
|
||||
}
|
||||
|
||||
public String name(){
|
||||
return Core.bundle.get("filter." + getClass().getSimpleName().toLowerCase().replace("filter", ""), getClass().getSimpleName().replace("Filter", ""));
|
||||
}
|
||||
|
||||
public final void apply(GenerateInput in){
|
||||
this.in = in;
|
||||
apply();
|
||||
|
|
@ -42,6 +62,8 @@ public abstract class GenerateFilter{
|
|||
public Block floor, block, ore;
|
||||
|
||||
Simplex noise = new Simplex();
|
||||
RidgedPerlin pnoise = new RidgedPerlin(0, 1);
|
||||
TileProvider buffer;
|
||||
|
||||
public void begin(MapEditor editor, int x, int y, Block floor, Block block, Block ore){
|
||||
this.editor = editor;
|
||||
|
|
@ -52,12 +74,18 @@ public abstract class GenerateFilter{
|
|||
this.y = y;
|
||||
}
|
||||
|
||||
public void randomize(){
|
||||
noise.setSeed(Mathf.random(99999999));
|
||||
public void setFilter(GenerateFilter filter, TileProvider buffer){
|
||||
this.buffer = buffer;
|
||||
noise.setSeed(filter.seed);
|
||||
pnoise.setSeed((int)(filter.seed + 1));
|
||||
}
|
||||
|
||||
Tile tile(double x, double y){
|
||||
return editor.tile((int)Mathf.clamp(x, 0, editor.width() - 1), (int)Mathf.clamp(y, 0, editor.height() - 1));
|
||||
DummyTile tile(float x, float y){
|
||||
return buffer.get(Mathf.clamp((int)x, 0, editor.width() - 1), Mathf.clamp((int)y, 0, editor.height() - 1));
|
||||
}
|
||||
|
||||
public interface TileProvider{
|
||||
DummyTile get(int x, int y);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,9 +14,9 @@ public class NoiseFilter extends GenerateFilter{
|
|||
|
||||
{
|
||||
options(
|
||||
new SliderOption("scale", () -> scl, f -> scl = f, 1f, 100f),
|
||||
new SliderOption("scale", () -> scl, f -> scl = f, 1f, 500f),
|
||||
new SliderOption("threshold", () -> threshold, f -> threshold = f, 0f, 1f),
|
||||
new SliderOption("octaves", () -> octaves, f -> octaves = f, 1f, 20f),
|
||||
new SliderOption("octaves", () -> octaves, f -> octaves = f, 1f, 10f),
|
||||
new SliderOption("falloff", () -> falloff, f -> falloff = f, 0f, 1f),
|
||||
new BlockOption("floor", () -> floor, b -> floor = b, floorsOnly),
|
||||
new BlockOption("wall", () -> block, b -> block = b, wallsOnly)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,36 @@
|
|||
package io.anuke.mindustry.editor.generation;
|
||||
|
||||
import io.anuke.mindustry.content.Blocks;
|
||||
import io.anuke.mindustry.editor.generation.FilterOption.BlockOption;
|
||||
import io.anuke.mindustry.editor.generation.FilterOption.SliderOption;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
|
||||
import static io.anuke.mindustry.editor.generation.FilterOption.floorsOnly;
|
||||
|
||||
public class RiverNoiseFilter extends GenerateFilter{
|
||||
float scl = 40, threshold = 0f, threshold2 = 0.1f;
|
||||
Block floor = Blocks.water, floor2 = Blocks.deepwater;
|
||||
|
||||
{
|
||||
options(
|
||||
new SliderOption("scale", () -> scl, f -> scl = f, 1f, 500f),
|
||||
new SliderOption("threshold", () -> threshold, f -> threshold = f, 0f, 1f),
|
||||
new SliderOption("threshold2", () -> threshold2, f -> threshold2 = f, 0f, 1f),
|
||||
new BlockOption("floor", () -> floor, b -> floor = b, floorsOnly),
|
||||
new BlockOption("floor2", () -> floor2, b -> floor2 = b, floorsOnly)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(){
|
||||
float noise = rnoise(in.x, in.y, scl, 1f);
|
||||
|
||||
if(noise >= threshold){
|
||||
in.floor = floor;
|
||||
|
||||
if(noise >= threshold2){
|
||||
in.floor = floor2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package io.anuke.mindustry.editor.generation;
|
||||
|
||||
import io.anuke.mindustry.content.Blocks;
|
||||
import io.anuke.mindustry.editor.generation.FilterOption.BlockOption;
|
||||
import io.anuke.mindustry.editor.generation.FilterOption.SliderOption;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
|
||||
import static io.anuke.mindustry.editor.generation.FilterOption.floorsOnly;
|
||||
import static io.anuke.mindustry.editor.generation.FilterOption.wallsOnly;
|
||||
|
||||
public class ScatterFilter extends GenerateFilter{
|
||||
float chance = 0.1f;
|
||||
Block floor = Blocks.ice, block = Blocks.icerocks;
|
||||
|
||||
{
|
||||
options(
|
||||
new SliderOption("chance", () -> chance, f -> chance = f, 0f, 1f),
|
||||
new BlockOption("floor", () -> floor, b -> floor = b, floorsOnly),
|
||||
new BlockOption("block", () -> block, b -> block = b, wallsOnly)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(){
|
||||
|
||||
if(in.srcfloor == floor && in.srcblock == Blocks.air && chance() <= chance){
|
||||
in.block = block;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package io.anuke.mindustry.editor.generation;
|
||||
|
||||
import io.anuke.arc.math.Mathf;
|
||||
import io.anuke.mindustry.content.Blocks;
|
||||
import io.anuke.mindustry.editor.generation.FilterOption.BlockOption;
|
||||
import io.anuke.mindustry.editor.generation.FilterOption.SliderOption;
|
||||
import io.anuke.mindustry.world.Block;
|
||||
|
||||
import static io.anuke.mindustry.editor.generation.FilterOption.floorsOnly;
|
||||
import static io.anuke.mindustry.editor.generation.FilterOption.wallsOnly;
|
||||
|
||||
public class TerrainFilter extends GenerateFilter{
|
||||
float scl = 40, threshold = 0.9f, octaves = 3f, falloff = 0.5f, circleScl = 2.1f;
|
||||
Block floor = Blocks.stone, block = Blocks.rocks;
|
||||
|
||||
{
|
||||
options(
|
||||
new SliderOption("scale", () -> scl, f -> scl = f, 1f, 500f),
|
||||
new SliderOption("threshold", () -> threshold, f -> threshold = f, 0f, 1f),
|
||||
new SliderOption("circle scale", () -> circleScl, f -> circleScl = f, 0f, 3f),
|
||||
new SliderOption("octaves", () -> octaves, f -> octaves = f, 1f, 10f),
|
||||
new SliderOption("falloff", () -> falloff, f -> falloff = f, 0f, 1f),
|
||||
new BlockOption("floor", () -> floor, b -> floor = b, floorsOnly),
|
||||
new BlockOption("wall", () -> block, b -> block = b, wallsOnly)
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void apply(){
|
||||
float noise = noise(in.x, in.y, scl, 1f, octaves, falloff) + Mathf.dst((float) in.x / in.editor.width(), (float) in.y / in.editor.height(), 0.5f, 0.5f) * circleScl;
|
||||
|
||||
in.floor = floor;
|
||||
in.ore = Blocks.air;
|
||||
|
||||
if(noise >= threshold){
|
||||
in.block = block;
|
||||
}else{
|
||||
in.block = Blocks.air;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
package io.anuke.mindustry.world;
|
||||
|
||||
import io.anuke.mindustry.game.Team;
|
||||
|
||||
public class DummyTile extends Tile{
|
||||
|
||||
public DummyTile(int x, int y){
|
||||
super(x, y);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Team getTeam(){
|
||||
return Team.all[getTeamID()];
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void changed(){
|
||||
//nothing matters
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void preChanged(){
|
||||
//it really doesn't
|
||||
}
|
||||
}
|
||||
|
|
@ -144,6 +144,7 @@ public class PowerGraph{
|
|||
|
||||
public void update(){
|
||||
if(Core.graphics.getFrameId() == lastFrameUpdated || (consumers.size == 0 && producers.size == 0 && batteries.size == 0)){
|
||||
powerBalance.addValue(0f);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue