From 6a12effd6a196ab691e3850bd633d70427de3b89 Mon Sep 17 00:00:00 2001 From: Anuken Date: Fri, 18 Oct 2019 14:38:43 -0400 Subject: [PATCH] Schematic flipping + rotation --- core/src/io/anuke/mindustry/Vars.java | 2 + .../entities/traits/BuilderTrait.java | 6 +- .../io/anuke/mindustry/game/Schematics.java | 23 ++---- .../anuke/mindustry/input/DesktopInput.java | 30 ++++--- .../anuke/mindustry/input/InputHandler.java | 82 ++++++++++++++++--- .../io/anuke/mindustry/input/MobileInput.java | 2 +- .../io/anuke/mindustry/input/PlaceUtils.java | 18 ++-- 7 files changed, 114 insertions(+), 49 deletions(-) diff --git a/core/src/io/anuke/mindustry/Vars.java b/core/src/io/anuke/mindustry/Vars.java index 77475bb2c7..34b91182cd 100644 --- a/core/src/io/anuke/mindustry/Vars.java +++ b/core/src/io/anuke/mindustry/Vars.java @@ -33,6 +33,8 @@ public class Vars implements Loadable{ public static boolean loadLocales = true; /** Maximum number of broken blocks. TODO implement or remove.*/ public static final int maxBrokenBlocks = 256; + /** Maximum schematic size.*/ + public static final int maxSchematicSize = 32; /** IO buffer size. */ public static final int bufferSize = 8192; /** global charset, since Android doesn't support the Charsets class */ diff --git a/core/src/io/anuke/mindustry/entities/traits/BuilderTrait.java b/core/src/io/anuke/mindustry/entities/traits/BuilderTrait.java index f8547cb800..482bfb653f 100644 --- a/core/src/io/anuke/mindustry/entities/traits/BuilderTrait.java +++ b/core/src/io/anuke/mindustry/entities/traits/BuilderTrait.java @@ -278,7 +278,7 @@ public interface BuilderTrait extends Entity, TeamTrait{ /** Config int. Not used unless hasConfig is true.*/ public int config; /** Original position, only used in schematics.*/ - public int originalX, originalY; + public int originalX, originalY, originalWidth, originalHeight; /** Last progress.*/ public float progress; @@ -327,9 +327,11 @@ public interface BuilderTrait extends Entity, TeamTrait{ return copy; } - public BuildRequest original(int x, int y){ + public BuildRequest original(int x, int y, int originalWidth, int originalHeight){ originalX = x; originalY = y; + this.originalWidth = originalWidth; + this.originalHeight = originalHeight; return this; } diff --git a/core/src/io/anuke/mindustry/game/Schematics.java b/core/src/io/anuke/mindustry/game/Schematics.java index c0942eb1f7..65bb11022f 100644 --- a/core/src/io/anuke/mindustry/game/Schematics.java +++ b/core/src/io/anuke/mindustry/game/Schematics.java @@ -15,6 +15,8 @@ import io.anuke.mindustry.content.*; import io.anuke.mindustry.entities.traits.BuilderTrait.*; import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.game.Schematic.*; +import io.anuke.mindustry.input.*; +import io.anuke.mindustry.input.PlaceUtils.*; import io.anuke.mindustry.type.*; import io.anuke.mindustry.world.*; @@ -29,7 +31,6 @@ public class Schematics implements Loadable{ private static final byte version = 0; private static final int padding = 2; - private static final int maxSize = 64; private OptimizedByteArrayOutputStream out = new OptimizedByteArrayOutputStream(1024); private Array all = new Array<>(); @@ -63,7 +64,7 @@ public class Schematics implements Loadable{ } Core.app.post(() -> { - shadowBuffer = new FrameBuffer(maxSize + padding, maxSize + padding); + shadowBuffer = new FrameBuffer(maxSchematicSize + padding, maxSchematicSize + padding); }); } @@ -145,7 +146,7 @@ public class Schematics implements Loadable{ /** Creates an array of build requests from a schematic's data, centered on the provided x+y coordinates. */ public Array toRequests(Schematic schem, int x, int y){ - return schem.tiles.map(t -> new BuildRequest(t.x + x - schem.width/2, t.y + y - schem.height/2, t.rotation, t.block).original(t.x, t.y).configure(t.config)); + return schem.tiles.map(t -> new BuildRequest(t.x + x - schem.width/2, t.y + y - schem.height/2, t.rotation, t.block).original(t.x, t.y, schem.width, schem.height).configure(t.config)); } /** Adds a schematic to the list, also copying it into the files.*/ @@ -160,17 +161,11 @@ public class Schematics implements Loadable{ /** Creates a schematic from a world selection. */ public Schematic create(int x, int y, int x2, int y2){ - if(x > x2){ - int temp = x; - x = x2; - x2 = temp; - } - - if(y > y2){ - int temp = y; - y = y2; - y2 = temp; - } + NormalizeResult result = PlaceUtils.normalizeArea(x, y, x2, y2, 0, false, maxSchematicSize); + x = result.x; + y = result.y; + x2 = result.x2; + y2 = result.y2; Array tiles = new Array<>(); diff --git a/core/src/io/anuke/mindustry/input/DesktopInput.java b/core/src/io/anuke/mindustry/input/DesktopInput.java index 21694b8be8..f9135f8475 100644 --- a/core/src/io/anuke/mindustry/input/DesktopInput.java +++ b/core/src/io/anuke/mindustry/input/DesktopInput.java @@ -10,6 +10,7 @@ import io.anuke.arc.scene.*; import io.anuke.arc.scene.event.*; import io.anuke.arc.scene.ui.*; import io.anuke.arc.util.ArcAnnotate.*; +import io.anuke.mindustry.*; import io.anuke.mindustry.core.GameState.*; import io.anuke.mindustry.entities.traits.BuilderTrait.*; import io.anuke.mindustry.game.EventType.*; @@ -91,7 +92,7 @@ public class DesktopInput extends InputHandler{ drawRequest(lineRequests.get(i)); } }else if(mode == breaking){ - drawSelection(selectX, selectY, cursorX, cursorY); + drawBreakSelection(selectX, selectY, cursorX, cursorY); }else if(isPlacing()){ if(block.rotate){ drawArrow(block, cursorX, cursorY, rotation); @@ -126,10 +127,7 @@ public class DesktopInput extends InputHandler{ } if(Core.input.keyDown(Binding.schematic)){ - Lines.stroke(2f); - - Draw.color(Pal.accent); - Lines.rect(schemX * tilesize, schemY * tilesize, (cursorX - schemX) * tilesize, (cursorY - schemY) * tilesize); + drawSelection(schemX, schemY, cursorX, cursorY, Vars.maxSchematicSize); } Draw.reset(); @@ -156,7 +154,7 @@ public class DesktopInput extends InputHandler{ if(state.is(State.menu) || Core.scene.hasDialog()) return; //zoom things - if(Math.abs(Core.input.axisTap(Binding.zoom)) > 0 && (Core.input.keyDown(Binding.zoom_hold))){ + if(Math.abs(Core.input.axisTap(Binding.zoom)) > 0 && Core.input.keyDown(Binding.zoom_hold)){ renderer.scaleCamera(Core.input.axisTap(Binding.zoom)); } @@ -193,10 +191,12 @@ public class DesktopInput extends InputHandler{ sreq.rotation = Mathf.mod(sreq.rotation + (int)Core.input.axisTap(Binding.rotate), 4); } - if(Math.abs((int)Core.input.axisTap(Binding.rotate)) > 0 && isPlacing() && mode == placing){ - updateLine(selectX, selectY); - }else if(Math.abs((int)Core.input.axisTap(Binding.rotate)) > 0 && !selectRequests.isEmpty()){ - rotateRequests(selectRequests, (int)Core.input.axisTap(Binding.rotate)); + if(!Core.input.keyDown(Binding.zoom_hold) && Math.abs((int)Core.input.axisTap(Binding.rotate)) > 0){ + if(isPlacing() && mode == placing){ + updateLine(selectX, selectY); + }else if(!selectRequests.isEmpty()){ + rotateRequests(selectRequests, (int)Core.input.axisTap(Binding.rotate)); + } } Tile cursor = tileAt(Core.input.mouseX(), Core.input.mouseY()); @@ -288,6 +288,16 @@ public class DesktopInput extends InputHandler{ } } + if(!selectRequests.isEmpty()){ + if(Core.input.keyTap(Binding.schematic_flip_x)){ + flipRequests(selectRequests, true); + } + + if(Core.input.keyTap(Binding.schematic_flip_y)){ + flipRequests(selectRequests, false); + } + } + //TODO remove if(Core.input.keyTap(KeyCode.V)){ ui.schematics.show(); diff --git a/core/src/io/anuke/mindustry/input/InputHandler.java b/core/src/io/anuke/mindustry/input/InputHandler.java index 14572f2f25..94e06a9328 100644 --- a/core/src/io/anuke/mindustry/input/InputHandler.java +++ b/core/src/io/anuke/mindustry/input/InputHandler.java @@ -227,11 +227,25 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } public void rotateRequests(Array requests, int direction){ - int ox = tileX(getMouseX()), oy = tileY(getMouseY()); + int ox = rawTileX(), oy = rawTileY(); requests.each(req -> { - //req.x -= ox; - //req.y -= oy; + //rotate config position + if(req.block.posConfig){ + int cx = Pos.x(req.config) - req.originalX, cy = Pos.y(req.config) - req.originalY; + int lx = cx; + + if(direction >= 0){ + cx = -cy; + cy = lx; + }else{ + cx = cy; + cy = -lx; + } + req.config = Pos.get(cx + req.originalX, cy + req.originalY); + } + + //rotate actual request, centered on its multiblock position float wx = (req.x - ox) * tilesize + req.block.offset(), wy = (req.y - oy) * tilesize + req.block.offset(); float x = wx; if(direction >= 0){ @@ -243,7 +257,38 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } req.x = world.toTile(wx - req.block.offset()) + ox; req.y = world.toTile(wy - req.block.offset()) + oy; - req.rotation += direction; + req.rotation = Mathf.mod(req.rotation + direction, 4); + }); + } + + public void flipRequests(Array requests, boolean x){ + int origin = x ? rawTileX() : rawTileY(); + + requests.each(req -> { + int value = -((x ? req.x : req.y) - origin) + origin; + + if(x){ + req.x = value; + }else{ + req.y = value; + } + + if(req.block.posConfig){ + int corigin = x ? req.originalWidth/2 : req.originalHeight/2; + int nvalue = -((x ? Pos.x(req.config) : Pos.y(req.config)) - corigin) + corigin; + if(x){ + req.originalX = -(req.originalX - corigin) + corigin; + req.config = Pos.get(nvalue, Pos.y(req.config)); + }else{ + req.originalY = -(req.originalY - corigin) + corigin; + req.config = Pos.get(Pos.x(req.config), nvalue); + } + } + + //flip rotation + if(x == (req.rotation % 2 == 0)){ + req.rotation = Mathf.mod(req.rotation + 2, 4); + } }); } @@ -287,7 +332,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ return null; } - protected void drawSelection(int x1, int y1, int x2, int y2){ + protected void drawBreakSelection(int x1, int y1, int x2, int y2){ NormalizeDrawResult result = PlaceUtils.normalizeDrawArea(Blocks.air, x1, y1, x2, y2, false, maxLength, 1f); NormalizeResult dresult = PlaceUtils.normalizeArea(x1, y1, x2, y2, rotation, false, maxLength); @@ -335,6 +380,17 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ Lines.rect(result.x, result.y, result.x2 - result.x, result.y2 - result.y); } + protected void drawSelection(int x1, int y1, int x2, int y2, int maxLength){ + NormalizeDrawResult result = PlaceUtils.normalizeDrawArea(Blocks.air, x1, y1, x2, y2, false, maxLength, 1f); + + Lines.stroke(2f); + + Draw.color(Pal.accentBack); + Lines.rect(result.x, result.y - 1, result.x2 - result.x, result.y2 - result.y); + Draw.color(Pal.accent); + Lines.rect(result.x, result.y, result.x2 - result.x, result.y2 - result.y); + } + protected void flushSelectRequests(Array requests){ for(BuildRequest req : requests){ if(req.block != null && validPlace(req.x, req.y, req.block, req.rotation)){ @@ -480,14 +536,6 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } } - /* - //clear when the player taps on something else - if(!consumed && !mobile && player.isBuilding() && block == null){ - //player.clearBuilding(); - block = null; - return true; - }*/ - if(!showedInventory){ frag.inv.hide(); } @@ -531,6 +579,14 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ return world.tile(tileX(x), tileY(y)); } + int rawTileX(){ + return world.toTile(Core.input.mouseWorld().x); + } + + int rawTileY(){ + return world.toTile(Core.input.mouseWorld().y); + } + int tileX(float cursorX){ Vector2 vec = Core.input.mouseWorld(cursorX, 0); if(selectedBlock()){ diff --git a/core/src/io/anuke/mindustry/input/MobileInput.java b/core/src/io/anuke/mindustry/input/MobileInput.java index 02787ed86a..440fd95eef 100644 --- a/core/src/io/anuke/mindustry/input/MobileInput.java +++ b/core/src/io/anuke/mindustry/input/MobileInput.java @@ -302,7 +302,7 @@ public class MobileInput extends InputHandler implements GestureListener{ drawRequest(lineRequests.get(i)); } }else if(mode == breaking){ - drawSelection(lineStartX, lineStartY, tileX, tileY); + drawBreakSelection(lineStartX, lineStartY, tileX, tileY); } } diff --git a/core/src/io/anuke/mindustry/input/PlaceUtils.java b/core/src/io/anuke/mindustry/input/PlaceUtils.java index 52e06e518b..79a358e286 100644 --- a/core/src/io/anuke/mindustry/input/PlaceUtils.java +++ b/core/src/io/anuke/mindustry/input/PlaceUtils.java @@ -95,14 +95,14 @@ public class PlaceUtils{ }else{ endx = tilex; } + } - if(Math.abs(endx - tilex) > maxLength){ - endx = Mathf.sign(endx - tilex) * maxLength + tilex; - } + if(Math.abs(endx - tilex) > maxLength){ + endx = Mathf.sign(endx - tilex) * maxLength + tilex; + } - if(Math.abs(endy - tiley) > maxLength){ - endy = Mathf.sign(endy - tiley) * maxLength + tiley; - } + if(Math.abs(endy - tiley) > maxLength){ + endy = Mathf.sign(endy - tiley) * maxLength + tiley; } int dx = endx - tilex, dy = endy - tiley; @@ -141,12 +141,12 @@ public class PlaceUtils{ return result; } - static class NormalizeDrawResult{ + public static class NormalizeDrawResult{ float x, y, x2, y2; } - static class NormalizeResult{ - int x, y, x2, y2, rotation; + public static class NormalizeResult{ + public int x, y, x2, y2, rotation; boolean isX(){ return Math.abs(x2 - x) > Math.abs(y2 - y);