Add line tool and undo tools

This commit is contained in:
Anuken 2017-12-21 13:40:57 -05:00
parent 443b4436ce
commit 295ddc42aa
22 changed files with 476 additions and 268 deletions

File diff suppressed because it is too large Load diff

Binary file not shown.

Before

Width:  |  Height:  |  Size: 80 KiB

After

Width:  |  Height:  |  Size: 82 KiB

Before After
Before After

View file

@ -35,8 +35,6 @@ import io.anuke.ucore.modules.Module;
import io.anuke.ucore.util.Mathf;
public class Control extends Module{
int targetscale = baseCameraScale;
Tutorial tutorial = new Tutorial();
boolean hiscore = false;
@ -48,7 +46,7 @@ public class Control extends Module{
public final EntityGroup<Bullet> bulletGroup = Entities.addGroup(Bullet.class);
public final EntityGroup<Shield> shieldGroup = Entities.addGroup(Shield.class);
Array<EnemySpawn> spawns = new Array<>();
Array<EnemySpawn> spawns;
int wave = 1;
int lastUpdated = -1;
float wavetime;
@ -429,7 +427,7 @@ public class Control extends Module{
Entities.initPhysics();
Entities.setCollider(tilesize, (x, y)-> world.solid(x, y));
Entities.setCollider(tilesize, (x, y) -> world.solid(x, y));
}
@Override
@ -451,13 +449,6 @@ public class Control extends Module{
wavetime = 0f;
}
if(Inputs.keyUp(Keys.C)){
//crash cause:
//map is null.
//core is null.
//tiles are null.
}
if(Inputs.keyUp(Keys.U)){
Vars.showUI = !Vars.showUI;
}

View file

@ -397,7 +397,7 @@ public class Renderer extends RendererModule{
drawHealth(entity);
}
if(!Vars.android && Vars.showPlayer)
if(!Vars.android && Vars.showPlayer && !player.isDead())
drawHealth(player);
}
}

View file

@ -253,7 +253,7 @@ public class World extends Module{
TileEntity e = other.entity;
if(damaged && ((TileEntity) e).health >= ((TileEntity) e).tile.block().health)
if(damaged && e.health >= e.tile.block().health)
continue;
float ndst = Vector2.dst(x, y, e.x, e.y);
@ -276,11 +276,9 @@ public class World extends Module{
* Input is in block coordinates, not world coordinates.
* @return null if no collisions found, block position otherwise.
*/
public GridPoint2 raycast(int x0f, int y0f, int x1f, int y1f){
int x0 = (int)x0f;
int y0 = (int)y0f;
int x1 = (int)x1f;
int y1 = (int)y1f;
public GridPoint2 raycast(int x0f, int y0f, int x1, int y1){
int x0 = x0f;
int y0 = y0f;
int dx = Math.abs(x1 - x0);
int dy = Math.abs(y1 - y0);

View file

@ -10,6 +10,8 @@ import io.anuke.mindustry.input.PlaceMode;
import io.anuke.mindustry.resource.Mech;
import io.anuke.mindustry.resource.Recipe;
import io.anuke.mindustry.resource.Weapon;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.Blocks;
import io.anuke.ucore.core.*;
import io.anuke.ucore.entities.DestructibleEntity;
import io.anuke.ucore.util.Angles;
@ -74,6 +76,11 @@ public class Player extends DestructibleEntity{
if(health < maxhealth && Timers.get(this, "regen", 50))
health ++;
Tile tile = world.tileWorld(x, y);
if(tile != null && tile.floor().liquid && tile.block() == Blocks.air){
damage(health+1); //drown
}
vector.set(0, 0);

View file

@ -54,18 +54,20 @@ public class TileEntity extends Entity{
}
public void onDeath(){
dead = true;
if(tile.block() == ProductionBlocks.core){
Vars.control.coreDestroyed();
}
Block block = tile.block();
block.onDestroyed(tile);
Vars.world.removeBlock(tile);
remove();
if(!dead) {
dead = true;
Block block = tile.block();
block.onDestroyed(tile);
Vars.world.removeBlock(tile);
remove();
}
}
public void collision(Bullet other){

View file

@ -9,11 +9,14 @@ import io.anuke.mindustry.entities.*;
import io.anuke.mindustry.graphics.Fx;
import io.anuke.mindustry.graphics.Shaders;
import io.anuke.mindustry.world.Tile;
import io.anuke.mindustry.world.blocks.Blocks;
import io.anuke.ucore.UCore;
import io.anuke.ucore.core.*;
import io.anuke.ucore.entities.*;
import io.anuke.ucore.util.*;
import static io.anuke.mindustry.Vars.world;
public class Enemy extends DestructibleEntity{
public final static Color[] tierColors = { Color.valueOf("ffe451"), Color.valueOf("f48e20"), Color.valueOf("ff6757"), Color.valueOf("ff2d86") };
public final static int maxtier = 4;
@ -211,6 +214,11 @@ public class Enemy extends DestructibleEntity{
}else{
idletime = 0;
}
Tile tile = world.tileWorld(x, y);
if(tile != null && tile.floor().liquid && tile.block() == Blocks.air){
damage(health+1); //drown
}
if(Float.isNaN(angle)){
angle = 0;

View file

@ -1,14 +1,40 @@
package io.anuke.mindustry.mapeditor;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.utils.Disposable;
import io.anuke.ucore.graphics.Pixmaps;
public class DrawOperation implements Disposable{
Pixmap from, to, pixmap;
public abstract class DrawOperation{
protected Pixmap pixmap;
public DrawOperation(Pixmap pixmap){
this.pixmap = pixmap;
}
public abstract void undo();
public abstract void redo();
public void add(Pixmap from, Pixmap to) {
this.from = from;
this.to = to;
}
public void undo() {
pixmap.drawPixmap(from, 0, 0);
}
public void redo() {
pixmap.drawPixmap(to, 0, 0);
}
@Override
public void dispose() {
if(!Pixmaps.isDisposed(from))
from.dispose();
if(!Pixmaps.isDisposed(to))
to.dispose();
}
public void disposeFrom(){
from.dispose();
}
}

View file

@ -12,6 +12,15 @@ import io.anuke.mindustry.world.ColorMapper;
import io.anuke.mindustry.world.ColorMapper.BlockPair;
public enum EditorTool{
pick{
public void touched(MapEditor editor, int x, int y){
BlockPair pair = ColorMapper.get(editor.pixmap().getPixel(x, y));
if(pair == null) return;
Block block = pair.dominant();
editor.setDrawBlock(block);
Vars.ui.getEditorDialog().updateSelectedBlock();
}
},
pencil{
{
edit = true;
@ -21,6 +30,12 @@ public enum EditorTool{
editor.draw(x, y);
}
},
line{
{
}
},
fill{
{
edit = true;
@ -64,15 +79,6 @@ public enum EditorTool{
return a == b;
}
},
pick{
public void touched(MapEditor editor, int x, int y){
BlockPair pair = ColorMapper.get(editor.pixmap().getPixel(x, y));
if(pair == null) return;
Block block = pair.dominant();
editor.setDrawBlock(block);
Vars.ui.getEditorDialog().updateSelectedBlock();
}
},
zoom;
boolean edit;

View file

@ -61,6 +61,7 @@ public class MapEditor{
if(filterPixmap == null){
filterPixmap = Pixmaps.copy(pixmap);
filter.process(filterPixmap);
filterTexture = new Texture(filterPixmap);
}else{
@ -109,7 +110,11 @@ public class MapEditor{
public void setBrushSize(int size){
this.brushSize = size;
}
public int getBrushSize() {
return brushSize;
}
public void draw(int dx, int dy){
if(dx < 0 || dy < 0 || dx >= pixmap.getWidth() || dy >= pixmap.getHeight()){
return;

View file

@ -4,6 +4,7 @@ import java.util.Arrays;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.files.FileHandle;
import com.badlogic.gdx.graphics.Color;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.Texture;
@ -226,19 +227,33 @@ public class MapEditorDialog extends Dialog{
tools.padTop(0).padBottom(6);
ButtonGroup<ImageButton> group = new ButtonGroup<>();
int i = 0;
int i = 1;
tools.defaults().size(53f, 58f).padBottom(-6);
ImageButton undo = tools.addIButton("icon-undo", 16*2f, () -> view.undo()).get();
ImageButton redo = tools.addIButton("icon-redo", 16*2f, () -> view.redo()).get();
ImageButton grid = tools.addIButton("toggle", "icon-grid", 16*2f, () -> view.setGrid(!view.isGrid())).get();
undo.setDisabled(() -> !view.getStack().canUndo());
redo.setDisabled(() -> !view.getStack().canRedo());
undo.update(() -> undo.getImage().setColor(undo.isDisabled() ? Color.GRAY : Color.WHITE));
redo.update(() -> redo.getImage().setColor(redo.isDisabled() ? Color.GRAY : Color.WHITE));
for(EditorTool tool : EditorTool.values()){
ImageButton button = new ImageButton("icon-" + tool.name(), "toggle");
button.clicked(() -> view.setTool(tool));
button.resizeImage(16*2f);
group.add(button);
if (tool == EditorTool.pencil)
button.setChecked(true);
tools.add(button).size(80f, 85f).padBottom(-6f);
if(i++ % 2 == 1) tools.row();
tools.add(button).padBottom(-6f);
if(i++ % 4 == 1) tools.row();
}
add(tools).width(160f).padBottom(-6);
add(tools).width(53*4).padBottom(-6);
row();
@ -330,12 +345,10 @@ public class MapEditorDialog extends Dialog{
}
}
content.padLeft(-5f);
group.getButtons().get(2).setChecked(true);
Table extra = new Table("button");
extra.labelWrap(() -> editor.getDrawBlock().name).width(120f).center();
extra.labelWrap(() -> editor.getDrawBlock().name).width(180f).center();
table.add(extra).growX();
table.row();
table.add(pane).growY().fillX();

View file

@ -45,6 +45,7 @@ public class MapFilter{
public MapFilter(){
prefs.get("replace").enabled = true;
prefs.get("terrain").enabled = true;
randomize();
}
public void randomize(){

View file

@ -1,5 +1,6 @@
package io.anuke.mindustry.mapeditor;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import com.badlogic.gdx.utils.Align;
import com.badlogic.gdx.utils.Scaling;
@ -9,6 +10,7 @@ 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.graphics.Pixmaps;
import io.anuke.ucore.scene.style.TextureRegionDrawable;
import io.anuke.ucore.scene.ui.CheckBox;
import io.anuke.ucore.scene.ui.Image;
@ -72,10 +74,11 @@ public class MapGenerateDialog extends FloatingDialog{
Vars.ui.showLoading();
Timers.run(3f, () ->{
Pixmap copy = Pixmaps.copy(editor.pixmap());
editor.applyFilter();
Vars.ui.getEditorDialog().getView().push(copy, Pixmaps.copy(editor.pixmap()));
Vars.ui.hideLoading();
Vars.ui.getEditorDialog().resetSaved();
Vars.ui.getEditorDialog().getView().clearStack();
hide();
});
});

View file

@ -1,6 +1,8 @@
package io.anuke.mindustry.mapeditor;
import com.badlogic.gdx.Input;
import com.badlogic.gdx.graphics.Colors;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.input.GestureDetector;
import com.badlogic.gdx.input.GestureDetector.GestureListener;
@ -11,7 +13,11 @@ import com.badlogic.gdx.scenes.scene2d.utils.ScissorStack;
import com.badlogic.gdx.utils.Array;
import io.anuke.mindustry.Vars;
import io.anuke.mindustry.ui.GridImage;
import io.anuke.mindustry.world.ColorMapper;
import io.anuke.ucore.UCore;
import io.anuke.ucore.core.*;
import io.anuke.ucore.graphics.Pixmaps;
import io.anuke.ucore.scene.Element;
import io.anuke.ucore.scene.event.InputEvent;
import io.anuke.ucore.scene.event.InputListener;
@ -24,17 +30,60 @@ public class MapView extends Element implements GestureListener{
private MapEditor editor;
private EditorTool tool = EditorTool.pencil;
private OperationStack stack = new OperationStack();
private PixelOperation op;
private DrawOperation op;
private Pixmap current;
private Bresenham2 br = new Bresenham2();
private boolean updated = false;
private float offsetx, offsety;
private float zoom = 1f;
private boolean grid = false;
private GridImage image = new GridImage(0, 0);
private boolean drawing;
private int lastx, lasty;
private int startx, starty;
public void setTool(EditorTool tool){
this.tool = tool;
}
public void clearStack(){
stack.clear();
current = null;
}
public OperationStack getStack() {
return stack;
}
public void setGrid(boolean grid) {
this.grid = grid;
}
public boolean isGrid() {
return grid;
}
public void push(Pixmap previous, Pixmap add){
DrawOperation op = new DrawOperation(editor.pixmap());
op.add(previous, add);
stack.add(op);
this.current = add;
}
public void undo(){
if(stack.canUndo()){
stack.undo();
editor.updateTexture();
}
}
public void redo(){
if(stack.canRedo()){
stack.redo();
editor.updateTexture();
}
}
public MapView(MapEditor editor){
@ -44,24 +93,31 @@ public class MapView extends Element implements GestureListener{
setTouchable(Touchable.enabled);
addListener(new InputListener(){
int lastx, lasty;
boolean drawing;
@Override
public boolean touchDown (InputEvent event, float x, float y, int pointer, int button) {
if(pointer != 0){
return false;
}
if(current == null){
current = Pixmaps.copy(editor.pixmap());
}
updated = false;
GridPoint2 p = project(x, y);
lastx = p.x;
lasty = p.y;
startx = p.x;
starty = p.y;
tool.touched(editor, p.x, p.y);
if(tool.edit){
updated = true;
Vars.ui.getEditorDialog().resetSaved();
}
op = new PixelOperation(editor.pixmap());
op = new DrawOperation(editor.pixmap());
drawing = true;
return true;
@ -70,8 +126,25 @@ public class MapView extends Element implements GestureListener{
@Override
public void touchUp (InputEvent event, float x, float y, int pointer, int button) {
drawing = false;
stack.add(op);
op = null;
GridPoint2 p = project(x, y);
if(tool == EditorTool.line){
Vars.ui.getEditorDialog().resetSaved();
Array<GridPoint2> points = br.line(startx, starty, p.x, p.y);
for(GridPoint2 point : points){
editor.draw(point.x, point.y);
}
updated = true;
}
if(updated){
Pixmap next = Pixmaps.copy(editor.pixmap());
op.add(current, next);
current = next;
stack.add(op);
op = null;
}
}
@Override
@ -84,6 +157,7 @@ public class MapView extends Element implements GestureListener{
for(GridPoint2 point : points){
editor.draw(point.x, point.y);
}
updated = true;
}
lastx = p.x;
lasty = p.y;
@ -118,7 +192,18 @@ public class MapView extends Element implements GestureListener{
y = (y - getHeight()/2 + sclheight/2 - offsety*zoom) / sclheight * editor.texture().getHeight();
return Tmp.g1.set((int)x, editor.texture().getHeight() - 1 - (int)y);
}
private Vector2 unproject(int x, int y){
float ratio = 1f / ((float)editor.pixmap().getWidth() / editor.pixmap().getHeight());
float size = Math.min(width, height);
float sclwidth = size * zoom;
float sclheight = size * zoom * ratio;
float px = ((float)x / editor.texture().getWidth()) * sclwidth + offsetx*zoom - sclwidth/2 + getWidth()/2;
float py = (float)((float)(editor.texture().getHeight() - 1 - y) / editor.texture().getHeight()) * sclheight
+ offsety*zoom - sclheight/2 + getHeight()/2;
return Tmp.v1.set(px, py);
}
@Override
public void draw(Batch batch, float alpha){
float ratio = 1f / ((float)editor.pixmap().getWidth() / editor.pixmap().getHeight());
@ -127,17 +212,38 @@ public class MapView extends Element implements GestureListener{
float sclheight = size * zoom * ratio;
float centerx = x + width/2 + offsetx * zoom;
float centery = y + height/2 + offsety * zoom;
image.setImageSize(editor.pixmap().getWidth(), editor.pixmap().getHeight());
batch.flush();
boolean pop = ScissorStack.pushScissors(Tmp.r1.set(x + width/2 - size/2, y + height/2 - size/2, size, size));
batch.draw(editor.texture(), centerx - sclwidth/2, centery - sclheight/2, sclwidth, sclheight);
if(grid){
image.setBounds(centerx - sclwidth/2, centery - sclheight/2, sclwidth, sclheight);
image.draw(batch, alpha);
}
if(tool == EditorTool.line && drawing){
Vector2 v1 = unproject(startx, starty).add(x, y);
float sx = v1.x, sy = v1.y;
Vector2 v2 = unproject(lastx, lasty).add(x, y);
Draw.color(Tmp.c1.set(ColorMapper.getColor(editor.getDrawBlock())));
Draw.thick(Unit.dp.scl(3f * zoom));
Draw.line(sx, sy, v2.x, v2.y);
Draw.polygon(40, sx, sy, editor.getBrushSize() * zoom * 3);
Draw.polygon(40, v2.x, v2.y, editor.getBrushSize() * zoom * 3);
}
batch.flush();
if(pop) ScissorStack.popScissors();
Draw.color(Colors.get("accent"));
Draw.thick(3f);
Draw.thick(Unit.dp.scl(3f));
Draw.linerect(x + width/2 - size/2, y + height/2 - size/2, size, size);
Draw.reset();
}

View file

@ -1,8 +1,12 @@
package io.anuke.mindustry.mapeditor;
import com.badlogic.gdx.graphics.Pixmap;
import com.badlogic.gdx.utils.Array;
import io.anuke.ucore.core.Draw;
import io.anuke.ucore.graphics.Pixmaps;
public class OperationStack{
private final static int maxSize = 10;
private Array<DrawOperation> stack = new Array<>();
private int index = 0;
@ -11,6 +15,9 @@ public class OperationStack{
}
public void clear(){
for(DrawOperation op : stack){
op.dispose();
}
stack.clear();
index = 0;
}
@ -19,6 +26,11 @@ public class OperationStack{
stack.truncate(stack.size + index);
index = 0;
stack.add(action);
if(stack.size > maxSize){
stack.get(0).disposeFrom();
stack.removeIndex(0);
}
}
public boolean canUndo(){
@ -43,8 +55,4 @@ public class OperationStack{
stack.get(stack.size - 1 + index).redo();
}
public void dispose(){
//TODO
}
}

View file

@ -1,24 +0,0 @@
package io.anuke.mindustry.mapeditor;
import com.badlogic.gdx.graphics.Pixmap;
public class PixelOperation extends DrawOperation {
public PixelOperation(Pixmap pixmap){
super(pixmap);
}
public void add() {
}
@Override
public void undo() {
}
@Override
public void redo() {
}
}

View file

@ -0,0 +1,37 @@
package io.anuke.mindustry.ui;
import com.badlogic.gdx.graphics.g2d.Batch;
import com.badlogic.gdx.graphics.g2d.TextureRegion;
import io.anuke.ucore.core.Draw;
import io.anuke.ucore.scene.Element;
public class GridImage extends Element{
private int imageWidth, imageHeight;
public GridImage(int w, int h){
this.imageWidth = w;
this.imageHeight = h;
}
public void draw(Batch batch, float alpha){
TextureRegion blank = Draw.region("white");
float xspace = (getWidth() / imageWidth);
float yspace = (getHeight() / imageHeight);
float s = 1f;
for(int x = 0; x <= imageWidth; x ++){
batch.draw(blank, (int)(getX() + xspace * x - s), getY() - s, 2, getHeight()+ (x == imageWidth ? 1: 0));
}
for(int y = 0; y <= imageHeight; y ++){
batch.draw(blank, getX() - s, (int)(getY() + y * yspace - s), getWidth(), 2);
}
}
public void setImageSize(int w, int h){
this.imageWidth = w;
this.imageHeight = h;
}
}

View file

@ -39,12 +39,14 @@ public class Block{
public boolean destructible;
/**whether this is solid*/
public boolean solid;
/**whethe this block CAN be solid.*/
/**whether this block CAN be solid.*/
public boolean solidifes;
/**whether this is rotateable*/
public boolean rotate;
/**whether you can break this with rightblick*/
/**whether you can break this with rightclick*/
public boolean breakable;
/**whether this block can be drowned in*/
public boolean liquid;
/**time it takes to break*/
public float breaktime = 18;
/**tile entity health*/

View file

@ -159,7 +159,7 @@ public class Tile{
public boolean solid(){
Block block = block();
Block floor = floor();
return block.solid || (floor.solid && block == Blocks.air) || block.isSolidFor(this);
return block.solid || (floor.solid && (block == Blocks.air || block.solidifes)) || block.isSolidFor(this);
}
public boolean breakable(){

View file

@ -28,12 +28,14 @@ public class Blocks{
variants = 0;
solid = true;
liquidDrop = Liquid.water;
liquid = true;
}},
water = new Floor("water"){{
variants = 0;
solid = true;
liquidDrop = Liquid.water;
liquid = true;
}},
lava = new Floor("lava"){
@ -41,6 +43,7 @@ public class Blocks{
variants = 0;
solid = true;
liquidDrop = Liquid.lava;
liquid = true;
}
@Override
@ -60,6 +63,7 @@ public class Blocks{
variants = 0;
solid = true;
liquidDrop = Liquid.oil;
liquid = true;
}
@Override

View file

@ -31,6 +31,7 @@ public class Door extends Wall implements Configurable{
public Door(String name) {
super(name);
solid = false;
solidifes = true;
}
@Override