diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 371e18d9ec..d1b21c1851 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -413,6 +413,7 @@ setting.autotarget.name = Auto-Target setting.fpscap.name = Max FPS setting.fpscap.none = None setting.fpscap.text = {0} FPS +setting.swapdiagonal.name = Always Diagonal Placement setting.difficulty.training = training setting.difficulty.easy = easy setting.difficulty.normal = normal @@ -449,6 +450,7 @@ keybind.screenshot.name = Map Screenshot keybind.move_x.name = Move x keybind.move_y.name = Move y keybind.select.name = Select/Shoot +keybind.diagonal_placement.name = Diagonal Placement keybind.pick.name = Pick Block keybind.break_block.name = Break Block keybind.deselect.name = Deselect diff --git a/core/src/io/anuke/mindustry/entities/type/Player.java b/core/src/io/anuke/mindustry/entities/type/Player.java index 93aaa2588c..7598bfd03c 100644 --- a/core/src/io/anuke/mindustry/entities/type/Player.java +++ b/core/src/io/anuke/mindustry/entities/type/Player.java @@ -28,12 +28,12 @@ import io.anuke.mindustry.game.Team; import io.anuke.mindustry.gen.Call; import io.anuke.mindustry.graphics.Pal; import io.anuke.mindustry.input.Binding; +import io.anuke.mindustry.input.InputHandler.PlaceDraw; import io.anuke.mindustry.io.TypeIO; import io.anuke.mindustry.net.Net; import io.anuke.mindustry.net.NetConnection; import io.anuke.mindustry.type.*; import io.anuke.mindustry.world.Block; -import io.anuke.mindustry.world.Block.Icon; import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.blocks.Floor; @@ -411,6 +411,7 @@ public class Player extends Unit implements BuilderTrait, ShooterTrait{ /** Draw all current build requests. Does not draw the beam effect, only the positions. */ public void drawBuildRequests(){ + BuildRequest last = null; for(BuildRequest request : getPlaceQueue()){ if(getCurrentRequest() == request && request.progress > 0.001f) continue; @@ -433,20 +434,34 @@ public class Player extends Unit implements BuilderTrait, ShooterTrait{ request.y * tilesize + block.offset(), rad); }else{ Draw.color(); + PlaceDraw draw = PlaceDraw.instance; - TextureRegion region = request.block.icon(Icon.full); + draw.scalex = 1; + draw.scaley = 1; + draw.rotation = request.rotation; - Draw.rect(region, request.x * tilesize + request.block.offset(), request.y * tilesize + request.block.offset(), - region.getWidth() * 1f * Draw.scl, - region.getHeight() * 1f * Draw.scl, request.block.rotate ? request.rotation * 90 : 0); + if(last == null){ + request.block.getPlaceDraw(draw, request.rotation, request.x, request.y, request.rotation); + }else{ + request.block.getPlaceDraw(draw, request.rotation, last.x - request.x, last.y - request.y, last.rotation); + } + + TextureRegion region = draw.region; + + Draw.rect(region, + request.x * tilesize + request.block.offset(), request.y * tilesize + request.block.offset(), + region.getWidth() * 1f * Draw.scl * draw.scalex, + region.getHeight() * 1f * Draw.scl * draw.scaley, request.block.rotate ? draw.rotation * 90 : 0); Draw.color(Pal.accent); for(int i = 0; i < 4; i++){ Point2 p = Geometry.d8edge[i]; float offset = -Math.max(request.block.size-1, 0)/2f * tilesize; - Draw.rect("block-select", request.x * tilesize + request.block.offset() + offset * p.x, request.y * tilesize + request.block.offset() + offset * p.y, i * 90); + if(i % 2 == 0) Draw.rect("block-select", request.x * tilesize + request.block.offset() + offset * p.x, request.y * tilesize + request.block.offset() + offset * p.y, i * 90); } Draw.color(); + + last = request; } } diff --git a/core/src/io/anuke/mindustry/input/Binding.java b/core/src/io/anuke/mindustry/input/Binding.java index 5600c5f213..dc23e9f7dd 100644 --- a/core/src/io/anuke/mindustry/input/Binding.java +++ b/core/src/io/anuke/mindustry/input/Binding.java @@ -15,6 +15,7 @@ public enum Binding implements KeyBind{ deselect(KeyCode.MOUSE_RIGHT), break_block(KeyCode.MOUSE_RIGHT), rotate(new Axis(KeyCode.SCROLL)), + diagonal_placement(KeyCode.CONTROL_LEFT), pick(KeyCode.MOUSE_MIDDLE), dash(KeyCode.SHIFT_LEFT), gridMode(KeyCode.GRAVE), diff --git a/core/src/io/anuke/mindustry/input/DesktopInput.java b/core/src/io/anuke/mindustry/input/DesktopInput.java index 23db8ae4bd..eeda4020d1 100644 --- a/core/src/io/anuke/mindustry/input/DesktopInput.java +++ b/core/src/io/anuke/mindustry/input/DesktopInput.java @@ -3,15 +3,11 @@ package io.anuke.mindustry.input; import io.anuke.arc.Core; import io.anuke.arc.Graphics.Cursor; import io.anuke.arc.Graphics.Cursor.SystemCursor; -import io.anuke.arc.collection.Array; import io.anuke.arc.graphics.g2d.Draw; import io.anuke.arc.graphics.g2d.Lines; import io.anuke.arc.math.Mathf; import io.anuke.arc.math.geom.Geometry; import io.anuke.arc.math.geom.Point2; -import io.anuke.arc.util.Tmp; -import io.anuke.arc.util.pooling.Pool; -import io.anuke.arc.util.pooling.Pools; import io.anuke.mindustry.content.Blocks; import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.entities.type.Player; @@ -35,24 +31,19 @@ public class DesktopInput extends InputHandler{ private PlaceMode mode; /**Animation scale for line.*/ private float selectScale; - /**All requests for the line mode placing.*/ - private Array requests = new Array<>(); + + private int prevX, prevY, prevRotation; public DesktopInput(Player player){ super(player); } /**Draws a placement icon for a specific block.*/ - void drawPlace(int x, int y, Block block, int rotation, PlaceRequest prev){ + void drawPlace(int x, int y, Block block, int rotation, int prevX, int prevY, int prevRotation){ if(validPlace(x, y, block, rotation)){ - if(prev != null){ - block.getPlaceDraw(placeDraw, rotation, prev.x - x, prev.y - y, prev.rotation); - }else{ - block.getPlaceDraw(placeDraw, rotation, 0, 0, rotation); - } + block.getPlaceDraw(placeDraw, rotation, prevX, prevY, prevRotation); Draw.color(); - Draw.rect(placeDraw.region, x * tilesize + block.offset(), y * tilesize + block.offset(), placeDraw.region.getWidth() * selectScale * Draw.scl * placeDraw.scalex, placeDraw.region.getHeight() * selectScale * Draw.scl * placeDraw.scaley, @@ -62,14 +53,14 @@ public class DesktopInput extends InputHandler{ for(int i = 0; i < 4; i++){ Point2 p = Geometry.d8edge[i]; float offset = -Math.max(block.size-1, 0)/2f * tilesize; - Draw.rect("block-select", x * tilesize + block.offset() + offset * p.x, y * tilesize + block.offset() + offset * p.y, i * 90); + if(i % 2 == 0)Draw.rect("block-select", x * tilesize + block.offset() + offset * p.x, y * tilesize + block.offset() + offset * p.y, i * 90); } Draw.color(); }else{ Draw.color(Pal.removeBack); - Lines.square(x * tilesize + block.offset(), y * tilesize + block.offset() - 1, block.size * tilesize / 2f); + Lines.square(x * tilesize + block.offset(), y * tilesize + block.offset() - 1, block.size * tilesize / 2f - 1); Draw.color(Pal.remove); - Lines.square(x * tilesize + block.offset(), y * tilesize + block.offset(), block.size * tilesize / 2f); + Lines.square(x * tilesize + block.offset(), y * tilesize + block.offset(), block.size * tilesize / 2f - 1); } } @@ -86,30 +77,20 @@ public class DesktopInput extends InputHandler{ //draw selection(s) if(mode == placing && block != null){ - int i = 0; - PlaceRequest prev = null; - for(PlaceRequest request : requests){ - int x = request.x, y = request.y; + prevX = selectX; + prevY = selectY; + prevRotation = rotation; - if(++i >= requests.size && block.rotate){ - Draw.color(!validPlace(x, y, block, request.rotation) ? Pal.removeBack : Pal.accentBack); - Draw.rect(Core.atlas.find("place-arrow"), - x * tilesize + block.offset(), - y * tilesize + block.offset() - 1, - Core.atlas.find("place-arrow").getWidth() * Draw.scl, - Core.atlas.find("place-arrow").getHeight() * Draw.scl, request.rotation * 90 - 90); - - Draw.color(!validPlace(x, y, block, request.rotation) ? Pal.remove : Pal.accent); - Draw.rect(Core.atlas.find("place-arrow"), - x * tilesize + block.offset(), - y * tilesize + block.offset(), - Core.atlas.find("place-arrow").getWidth() * Draw.scl, - Core.atlas.find("place-arrow").getHeight() * Draw.scl, request.rotation * 90 - 90); + iterateLine(selectX, selectY, cursorX, cursorY, l -> { + if(l.last && block.rotate){ + drawArrow(block, l.x, l.y, l.rotation); } + drawPlace(l.x, l.y, block, l.rotation, prevX - l.x, prevY - l.y, prevRotation); - drawPlace(request.x, request.y, block, request.rotation, prev); - prev = request; - } + prevX = l.x; + prevY = l.y; + prevRotation = l.rotation; + }); }else if(mode == breaking){ NormalizeDrawResult result = PlaceUtils.normalizeDrawArea(Blocks.air, selectX, selectY, cursorX, cursorY, false, maxLength, 1f); @@ -134,21 +115,9 @@ public class DesktopInput extends InputHandler{ Lines.rect(result.x, result.y, result.x2 - result.x, result.y2 - result.y); }else if(isPlacing()){ if(block.rotate){ - Draw.color(!validPlace(cursorX, cursorY, block, rotation) ? Pal.removeBack : Pal.accentBack); - Draw.rect(Core.atlas.find("place-arrow"), - cursorX * tilesize + block.offset(), - cursorY * tilesize + block.offset() - 1, - Core.atlas.find("place-arrow").getWidth() * Draw.scl, - Core.atlas.find("place-arrow").getHeight() * Draw.scl, rotation * 90 - 90); - - Draw.color(!validPlace(cursorX, cursorY, block, rotation) ? Pal.remove : Pal.accent); - Draw.rect(Core.atlas.find("place-arrow"), - cursorX * tilesize + block.offset(), - cursorY * tilesize + block.offset(), - Core.atlas.find("place-arrow").getWidth() * Draw.scl, - Core.atlas.find("place-arrow").getHeight() * Draw.scl, rotation * 90 - 90); + drawArrow(block, cursorX, cursorY, rotation); } - drawPlace(cursorX, cursorY, block, rotation, null); + drawPlace(cursorX, cursorY, block, rotation, cursorX, cursorY, rotation); block.drawPlace(cursorX, cursorY, rotation, validPlace(cursorX, cursorY, block, rotation)); } @@ -184,7 +153,6 @@ public class DesktopInput extends InputHandler{ //deselect if not placing if(!isPlacing() && mode == placing){ mode = none; - requests.clear(); } if(player.isShooting && !canShoot()){ @@ -241,7 +209,6 @@ public class DesktopInput extends InputHandler{ selectX = cursorX; selectY = cursorY; mode = placing; - requests.add(new PlaceRequest(selectX, selectY, rotation)); }else if(selected != null){ //only begin shooting if there's no cursor event if (!tileTapped(selected) && !tryTapPlayer(Core.input.mouseWorld().x, Core.input.mouseWorld().y) && player.getPlaceQueue().size == 0 && !droppingItem && @@ -266,50 +233,13 @@ public class DesktopInput extends InputHandler{ selectY = tileY(Core.input.mouseY()); } - if(isPlacing() && mode == placing){ - if((cursorX != selectX || cursorY != selectY)){ - points.clear(); - outPoints.clear(); - Pool pool = Pools.get(Point2.class, Point2::new); - Array out = bres.line(selectX, selectY, cursorX, cursorY, pool, outPoints); - - for(int i = 0; i < out.size; i++){ - points.add(out.get(i)); - - if(i != out.size - 1){ - Point2 curr = out.get(i); - Point2 next = out.get(i + 1); - //diagonal - if(next.x != curr.x && next.y != curr.y){ - points.add(new Point2(next.x, curr.y)); - } - } - } - - for(Point2 point : points){ - if(checkUnused(point.x, point.y)){ - addRequest(point); - selectX = point.x; - selectY = point.y; - } - - } - - pool.freeAll(outPoints); - } - } - if(Core.input.keyRelease(Binding.break_block) || Core.input.keyRelease(Binding.select)){ if(mode == placing && block != null){ //touch up while placing, place everything in selection - int rot = rotation; - - for(PlaceRequest req : requests){ - rotation = req.rotation; - tryPlaceBlock(req.x, req.y); - } - - rotation = rot; + iterateLine(selectX, selectY, cursorX, cursorY, l -> { + rotation = l.rotation; + tryPlaceBlock(l.x, l.y); + }); }else if(mode == breaking){ //touch up while breaking, break everything in selection NormalizeResult result = PlaceUtils.normalizeArea(selectX, selectY, cursorX, cursorY, rotation, false, maxLength); for(int x = 0; x <= Math.abs(result.x2 - result.x); x++){ @@ -326,44 +256,8 @@ public class DesktopInput extends InputHandler{ tryDropItems(selected.target(), Core.input.mouseWorld().x, Core.input.mouseWorld().y); } - requests.clear(); mode = none; } - - } - - boolean checkUnused(int x, int y){ - Tmp.r2.setSize(block.size * tilesize); - Tmp.r2.setCenter(x * tilesize + block.offset(), y * tilesize + block.offset()); - - for(PlaceRequest req : requests){ - Tmp.r1.setSize(block.size * tilesize); - Tmp.r1.setCenter(req.x*tilesize + block.offset(), req.y*tilesize + block.offset()); - - if(Tmp.r2.overlaps(Tmp.r1)){ - return false; - } - } - return true; - } - - void addRequest(Point2 point){ - if(!checkUnused(point.x, point.y)) return; - - PlaceRequest last = requests.peek(); - - if(last.x == point.x && last.y == point.y){ - return; - } - - int rel = Tile.relativeTo(last.x, last.y, point.x, point.y); - - if(rel != -1){ - last.rotation = rel; - rotation = rel; - } - - requests.add(new PlaceRequest(point.x, point.y, rotation)); } @Override @@ -388,15 +282,4 @@ public class DesktopInput extends InputHandler{ droppingItem = false; } } - - private class PlaceRequest{ - int x, y, rotation; - - public PlaceRequest(int x, int y, int rotation){ - this.x = x; - this.y = y; - this.rotation = rotation; - } - } - } diff --git a/core/src/io/anuke/mindustry/input/InputHandler.java b/core/src/io/anuke/mindustry/input/InputHandler.java index 2851b2d819..f9e0432e48 100644 --- a/core/src/io/anuke/mindustry/input/InputHandler.java +++ b/core/src/io/anuke/mindustry/input/InputHandler.java @@ -4,12 +4,13 @@ import io.anuke.annotations.Annotations.Loc; import io.anuke.annotations.Annotations.Remote; import io.anuke.arc.Core; import io.anuke.arc.collection.Array; +import io.anuke.arc.function.Consumer; import io.anuke.arc.graphics.Color; +import io.anuke.arc.graphics.g2d.Draw; import io.anuke.arc.graphics.g2d.TextureRegion; import io.anuke.arc.input.InputProcessor; import io.anuke.arc.math.Angles; import io.anuke.arc.math.Mathf; -import io.anuke.arc.math.geom.Bresenham2; import io.anuke.arc.math.geom.Point2; import io.anuke.arc.math.geom.Vector2; import io.anuke.arc.scene.ui.layout.Table; @@ -21,6 +22,7 @@ import io.anuke.mindustry.entities.effect.ItemTransfer; import io.anuke.mindustry.entities.traits.BuilderTrait.BuildRequest; import io.anuke.mindustry.entities.type.Player; import io.anuke.mindustry.gen.Call; +import io.anuke.mindustry.graphics.Pal; import io.anuke.mindustry.net.Net; import io.anuke.mindustry.net.ValidateException; import io.anuke.mindustry.type.Item; @@ -48,10 +50,8 @@ public abstract class InputHandler implements InputProcessor{ public int rotation; public boolean droppingItem; - protected Bresenham2 bres = new Bresenham2(); - protected Array points = new Array<>(); - protected Array outPoints = new Array<>(); protected PlaceDraw placeDraw = new PlaceDraw(); + private PlaceLine line = new PlaceLine(); public InputHandler(Player player){ this.player = player; @@ -346,8 +346,58 @@ public abstract class InputHandler implements InputProcessor{ player.addBuildRequest(new BuildRequest(tile.x, tile.y)); } - public class PlaceDraw{ + void drawArrow(Block block, int x, int y, int rotation){ + Draw.color(!validPlace(x, y, block, rotation) ? Pal.removeBack : Pal.accentBack); + Draw.rect(Core.atlas.find("place-arrow"), + x * tilesize + block.offset(), + y * tilesize + block.offset() - 1, + Core.atlas.find("place-arrow").getWidth() * Draw.scl, + Core.atlas.find("place-arrow").getHeight() * Draw.scl, rotation * 90 - 90); + + Draw.color(!validPlace(x, y, block, rotation) ? Pal.remove : Pal.accent); + Draw.rect(Core.atlas.find("place-arrow"), + x * tilesize + block.offset(), + y * tilesize + block.offset(), + Core.atlas.find("place-arrow").getWidth() * Draw.scl, + Core.atlas.find("place-arrow").getHeight() * Draw.scl, rotation * 90 - 90); + } + + void iterateLine(int startX, int startY, int endX, int endY, Consumer cons){ + Array points; + boolean diagonal = Core.input.keyDown(Binding.diagonal_placement); + if(Core.settings.getBool("swapdiagonal")){ + diagonal = !diagonal; + } + + if(diagonal){ + points = PlaceUtils.normalizeDiagonal(startX, startY, endX, endY); + }else{ + points = PlaceUtils.normalizeLine(startX, startY, endX, endY); + } + + float angle = Angles.angle(startX, startY, endX, endY); + int baseRotation = (startX == endX && startY == endY) ? rotation : ((int)((angle + 45) / 90f)) % 4; + + for(int i = 0; i < points.size; i++){ + Point2 point = points.get(i); + Point2 next = i == points.size - 1 ? null : points.get(i + 1); + line.x = point.x; + line.y = point.y; + line.rotation = next != null ? Tile.relativeTo(point.x, point.y, next.x, next.y) : baseRotation; + line.last = next == null; + cons.accept(line); + } + } + + public static class PlaceDraw{ public int rotation, scalex, scaley; public TextureRegion region; + + public static final PlaceDraw instance = new PlaceDraw(); + } + + class PlaceLine{ + public int x, y, rotation; + public boolean last; } } diff --git a/core/src/io/anuke/mindustry/input/MobileInput.java b/core/src/io/anuke/mindustry/input/MobileInput.java index d3679a4fb0..a2b1d076ef 100644 --- a/core/src/io/anuke/mindustry/input/MobileInput.java +++ b/core/src/io/anuke/mindustry/input/MobileInput.java @@ -20,8 +20,6 @@ import io.anuke.arc.scene.ui.layout.Table; import io.anuke.arc.util.Align; import io.anuke.arc.util.Time; import io.anuke.arc.util.Tmp; -import io.anuke.arc.util.pooling.Pool; -import io.anuke.arc.util.pooling.Pools; import io.anuke.mindustry.content.Blocks; import io.anuke.mindustry.content.Fx; import io.anuke.mindustry.core.GameState.State; @@ -80,6 +78,8 @@ public class MobileInput extends InputHandler implements GestureListener{ /** Last placed request. Used for drawing block overlay. */ private PlaceRequest lastPlaced; + private int prevX, prevY, prevRotation; + public MobileInput(Player player){ super(player); Core.input.addProcessor(new GestureDetector(20, 0.5f, 0.4f, 0.15f, this)); @@ -169,6 +169,25 @@ public class MobileInput extends InputHandler implements GestureListener{ removals.add(request); } + void showGuide(String type){ + if(!guides.contains(type) && !Core.settings.getBool(type, false)){ + FloatingDialog dialog = new FloatingDialog("$" + type + ".title"); + dialog.addCloseButton(); + dialog.cont.left(); + dialog.cont.add("$" + type).growX().wrap(); + dialog.cont.row(); + dialog.cont.addCheck("$showagain", false, checked -> { + Core.settings.put(type, checked); + Core.settings.save(); + }).growX().left().get().left(); + dialog.show(); + guides.add(type); + } + } + + //endregion + //region UI and drawing + void drawRequest(PlaceRequest request, PlaceRequest prev){ Tile tile = request.tile(); @@ -196,7 +215,7 @@ public class MobileInput extends InputHandler implements GestureListener{ Point2 p = Geometry.d8edge[i]; float poffset = -Math.max(request.block.size-1, 0)/2f * tilesize; TextureRegion find = Core.atlas.find("block-select"); - Draw.rect("block-select", request.tile().x * tilesize + request.block.offset() + poffset * p.x, request.tile().y * tilesize + request.block.offset() + poffset * p.y, + if(i%2 == 0) Draw.rect("block-select", request.tile().x * tilesize + request.block.offset() + poffset * p.x, request.tile().y * tilesize + request.block.offset() + poffset * p.y, find.getWidth() * Draw.scl * request.scale, find.getHeight() * Draw.scl * request.scale, i * 90); } Draw.color(); @@ -211,43 +230,32 @@ public class MobileInput extends InputHandler implements GestureListener{ } } - void showGuide(String type){ - if(!guides.contains(type) && !Core.settings.getBool(type, false)){ - FloatingDialog dialog = new FloatingDialog("$" + type + ".title"); - dialog.addCloseButton(); - dialog.cont.left(); - dialog.cont.add("$" + type).growX().wrap(); - dialog.cont.row(); - dialog.cont.addCheck("$showagain", false, checked -> { - Core.settings.put(type, checked); - Core.settings.save(); - }).growX().left().get().left(); - dialog.show(); - guides.add(type); + /**Draws a placement icon for a specific block.*/ + void drawPlace(int x, int y, Block block, int rotation, int prevX, int prevY, int prevRotation){ + if(validPlace(x, y, block, rotation)){ + block.getPlaceDraw(placeDraw, rotation, prevX, prevY, prevRotation); + + Draw.color(); + Draw.rect(placeDraw.region, x * tilesize + block.offset(), y * tilesize + block.offset(), + placeDraw.region.getWidth() * Draw.scl * placeDraw.scalex, + placeDraw.region.getHeight() * Draw.scl * placeDraw.scaley, + block.rotate ? placeDraw.rotation * 90 : 0); + + Draw.color(Pal.accent); + for(int i = 0; i < 4; i++){ + Point2 p = Geometry.d8edge[i]; + float offset = -Math.max(block.size-1, 0)/2f * tilesize; + if(i % 2 == 0)Draw.rect("block-select", x * tilesize + block.offset() + offset * p.x, y * tilesize + block.offset() + offset * p.y, i * 90); + } + Draw.color(); + }else{ + Draw.color(Pal.removeBack); + Lines.square(x * tilesize + block.offset(), y * tilesize + block.offset() - 1, block.size * tilesize / 2f - 1); + Draw.color(Pal.remove); + Lines.square(x * tilesize + block.offset(), y * tilesize + block.offset(), block.size * tilesize / 2f - 1); } } - void drawPlaceArrow(Block block, int x, int y, int rotation){ - if(!block.rotate) return; - Draw.color(!validPlace(x, y, block, rotation) ? Pal.removeBack : Pal.accentBack); - Draw.rect(Core.atlas.find("place-arrow"), - x * tilesize + block.offset(), - y * tilesize + block.offset() - 1, - Core.atlas.find("place-arrow").getWidth() * Draw.scl, - Core.atlas.find("place-arrow").getHeight() * Draw.scl, rotation * 90 - 90); - - Draw.color(!validPlace(x, y, block, rotation) ? Pal.remove : Pal.accent); - Draw.rect(Core.atlas.find("place-arrow"), - x * tilesize + block.offset(), - y * tilesize + block.offset(), - Core.atlas.find("place-arrow").getWidth() * Draw.scl, - Core.atlas.find("place-arrow").getHeight() * Draw.scl, rotation * 90 - 90); - } - - //endregion - - //region UI and drawing - @Override public void buildUI(Table table){ table.addImage("blank").color(Pal.accent).height(3f).colspan(4).growX(); @@ -346,7 +354,7 @@ public class MobileInput extends InputHandler implements GestureListener{ if(!request.remove && request == lastPlaced && request.block != null){ Draw.mixcol(); - drawPlaceArrow(request.block, tile.x, tile.y, request.rotation); + drawArrow(request.block, tile.x, tile.y, request.rotation); } Draw.mixcol(Tmp.c1, 1f); @@ -369,8 +377,24 @@ public class MobileInput extends InputHandler implements GestureListener{ int tileX = tileX(Core.input.mouseX()); int tileY = tileY(Core.input.mouseY()); - //draw placing - if(mode == breaking){ + if(mode == placing && block != null){ + //draw placing + + prevX = lineStartX; + prevY = lineStartY; + prevRotation = rotation; + + iterateLine(lineStartX, lineStartY, tileX, tileY, l -> { + if(l.last && block.rotate){ + drawArrow(block, l.x, l.y, l.rotation); + } + drawPlace(l.x, l.y, block, l.rotation, prevX - l.x, prevY - l.y, prevRotation); + + prevX = l.x; + prevY = l.y; + prevRotation = l.rotation; + }); + }else if(mode == breaking){ //draw breaking NormalizeDrawResult result = PlaceUtils.normalizeDrawArea(Blocks.air, lineStartX, lineStartY, tileX, tileY, false, maxLength, 1f); NormalizeResult dresult = PlaceUtils.normalizeArea(lineStartX, lineStartY, tileX, tileY, rotation, false, maxLength); @@ -455,7 +479,13 @@ public class MobileInput extends InputHandler implements GestureListener{ int tileX = tileX(screenX); int tileY = tileY(screenY); - if(mode == breaking){ + if(mode == placing && isPlacing()){ + iterateLine(lineStartX, lineStartY, tileX, tileY, l -> { + PlaceRequest request = new PlaceRequest(l.x, l.y, block, l.rotation); + request.scale = 1f; + selection.add(request); + }); + }else if(mode == breaking){ //normalize area NormalizeResult result = PlaceUtils.normalizeArea(lineStartX, lineStartY, tileX, tileY, rotation, false, maxLength); @@ -511,7 +541,6 @@ public class MobileInput extends InputHandler implements GestureListener{ Effects.effect(Fx.tapBlock, cursor.worldx(), cursor.worldy(), 1f); }else if(block != null){ Effects.effect(Fx.tapBlock, cursor.worldx() + block.offset(), cursor.worldy() + block.offset(), block.size); - selection.add(new PlaceRequest(cursor.x, cursor.y, block, rotation)); } return false; @@ -619,45 +648,6 @@ public class MobileInput extends InputHandler implements GestureListener{ Core.camera.position.x += vector.x; Core.camera.position.y += vector.y; } - - Tile selected = tileAt(Core.input.mouseX(), Core.input.mouseY()); - - if(mode == placing && block != null && selected != null){ - int cursorX = tileX(Core.input.mouseX()); - int cursorY = tileY(Core.input.mouseY()); - - if((cursorX != lineStartX || cursorY != lineStartY)){ - points.clear(); - outPoints.clear(); - Pool pool = Pools.get(Point2.class, Point2::new); - Array out = bres.line(lineStartX, lineStartY, cursorX, cursorY, pool, outPoints); - - for(int i = 0; i < out.size; i++){ - points.add(out.get(i)); - - if(i != out.size - 1){ - Point2 curr = out.get(i); - Point2 next = out.get(i + 1); - //diagonal - if(next.x != curr.x && next.y != curr.y){ - points.add(new Point2(next.x, curr.y)); - } - } - } - - for(Point2 point : points){ - if(!checkOverlapPlacement(point.x, point.y, block)){ - addRequest(point); - lineStartX = point.x; - lineStartY = point.y; - } - - } - - pool.freeAll(outPoints); - - } - } }else{ lineScale = 0f; } @@ -673,23 +663,6 @@ public class MobileInput extends InputHandler implements GestureListener{ } } - void addRequest(Point2 point){ - PlaceRequest last = selection.peek(); - - if(last.x == point.x && last.y == point.y){ - return; - } - - int rel = Tile.relativeTo(last.x, last.y, point.x, point.y); - - if(rel != -1){ - last.rotation = rel; - rotation = rel; - } - - selection.add(new PlaceRequest(point.x, point.y, block, rotation)); - } - @Override public boolean pan(float x, float y, float deltaX, float deltaY){ if(Core.scene.hasDialog()) return false; diff --git a/core/src/io/anuke/mindustry/input/PlaceUtils.java b/core/src/io/anuke/mindustry/input/PlaceUtils.java index c2e3370eed..1a36c24608 100644 --- a/core/src/io/anuke/mindustry/input/PlaceUtils.java +++ b/core/src/io/anuke/mindustry/input/PlaceUtils.java @@ -1,13 +1,44 @@ package io.anuke.mindustry.input; -import io.anuke.mindustry.world.Block; +import io.anuke.arc.collection.Array; import io.anuke.arc.math.Mathf; +import io.anuke.arc.math.geom.Bresenham2; +import io.anuke.arc.math.geom.Point2; +import io.anuke.arc.util.pooling.Pools; +import io.anuke.mindustry.world.Block; import static io.anuke.mindustry.Vars.tilesize; public class PlaceUtils{ private static final NormalizeResult result = new NormalizeResult(); private static final NormalizeDrawResult drawResult = new NormalizeDrawResult(); + private static Bresenham2 bres = new Bresenham2(); + private static Array points = new Array<>(); + + /**Normalize a diagonal line into points. */ + public static Array normalizeDiagonal(int startX, int startY, int endX, int endY){ + Pools.freeAll(points); + points.clear(); + return bres.lineNoDiagonal(startX, startY, endX, endY, Pools.get(Point2.class, Point2::new), points); + } + + /**Normalize two points into one straight line, no diagonals.*/ + public static Array normalizeLine(int startX, int startY, int endX, int endY){ + Pools.freeAll(points); + points.clear(); + if(Math.abs(startX - endX) > Math.abs(startY - endY)){ + //go width + for(int i = 0; i <= Math.abs(startX - endX); i++){ + points.add(Pools.obtain(Point2.class, Point2::new).set(startX + i*Mathf.sign(endX - startX), startY)); + } + }else{ + //go height + for(int i = 0; i <= Math.abs(startY - endY); i++){ + points.add(Pools.obtain(Point2.class, Point2::new).set(startX, startY + i*Mathf.sign(endY - startY))); + } + } + return points; + } /** * Normalizes a placement area and returns the result, ready to be used for drawing a rectangle. diff --git a/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java index 60e0ad707e..fa55b6534d 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java @@ -124,6 +124,7 @@ public class SettingsMenuDialog extends SettingsDialog{ game.screenshakePref(); game.checkPref("effects", true); + game.checkPref("swapdiagonal", false); if(mobile){ game.checkPref("autotarget", true); } diff --git a/core/src/io/anuke/mindustry/world/Tile.java b/core/src/io/anuke/mindustry/world/Tile.java index e1481dcfab..6bd1f201a3 100644 --- a/core/src/io/anuke/mindustry/world/Tile.java +++ b/core/src/io/anuke/mindustry/world/Tile.java @@ -103,6 +103,14 @@ public class Tile implements Position, TargetTrait{ return -1; } + public static byte absoluteRelativeTo(int x, int y, int cx, int cy){ + if(x == cx && y <= cy - 1) return 1; + if(x == cx && y >= cy + 1) return 3; + if(x <= cx - 1 && y == cy) return 0; + if(x >= cx + 1 && y == cy) return 2; + return -1; + } + @SuppressWarnings("unchecked") public T entity(){ return (T) entity;