From 9aec61020dfb08857ceeea71eb458473bda95833 Mon Sep 17 00:00:00 2001 From: Anuken Date: Mon, 7 Oct 2019 19:51:52 -0400 Subject: [PATCH] More usability improvements --- .../anuke/mindustry/entities/type/Player.java | 3 +- .../mindustry/graphics/OverlayRenderer.java | 2 +- .../anuke/mindustry/input/DesktopInput.java | 51 +++++++++++++++++++ .../anuke/mindustry/input/InputHandler.java | 44 +++++++++++++++- .../io/anuke/mindustry/input/MobileInput.java | 1 - 5 files changed, 97 insertions(+), 4 deletions(-) diff --git a/core/src/io/anuke/mindustry/entities/type/Player.java b/core/src/io/anuke/mindustry/entities/type/Player.java index ad6c6a173f..eeb59f2dd0 100644 --- a/core/src/io/anuke/mindustry/entities/type/Player.java +++ b/core/src/io/anuke/mindustry/entities/type/Player.java @@ -436,7 +436,8 @@ public class Player extends Unit implements BuilderMinerTrait, ShooterTrait{ if(request.breaking){ control.input.drawBreaking(request); }else{ - request.block.drawRequest(request, control.input.allRequests(), true); + request.block.drawRequest(request, control.input.allRequests(), + Build.validPlace(getTeam(), request.x, request.y, request.block, request.rotation)); } } diff --git a/core/src/io/anuke/mindustry/graphics/OverlayRenderer.java b/core/src/io/anuke/mindustry/graphics/OverlayRenderer.java index 4b94cc091f..3c91d89a58 100644 --- a/core/src/io/anuke/mindustry/graphics/OverlayRenderer.java +++ b/core/src/io/anuke/mindustry/graphics/OverlayRenderer.java @@ -25,7 +25,7 @@ public class OverlayRenderer{ public void drawBottom(){ InputHandler input = control.input; - if(!input.isDrawing() || player.isDead()) return; + if(player.isDead()) return; input.drawBottom(); } diff --git a/core/src/io/anuke/mindustry/input/DesktopInput.java b/core/src/io/anuke/mindustry/input/DesktopInput.java index 4dfd2b6d01..8657175cf1 100644 --- a/core/src/io/anuke/mindustry/input/DesktopInput.java +++ b/core/src/io/anuke/mindustry/input/DesktopInput.java @@ -7,10 +7,12 @@ import io.anuke.arc.graphics.g2d.*; import io.anuke.arc.math.*; import io.anuke.arc.scene.*; import io.anuke.arc.scene.ui.*; +import io.anuke.arc.util.ArcAnnotate.*; import io.anuke.mindustry.core.GameState.*; import io.anuke.mindustry.entities.traits.BuilderTrait.*; import io.anuke.mindustry.game.EventType.*; import io.anuke.mindustry.gen.*; +import io.anuke.mindustry.graphics.*; import io.anuke.mindustry.ui.*; import io.anuke.mindustry.world.*; @@ -29,6 +31,8 @@ public class DesktopInput extends InputHandler{ private PlaceMode mode; /** Animation scale for line. */ private float selectScale; + /** Selected build request for movement. */ + private @Nullable BuildRequest sreq; @Override public boolean isDrawing(){ @@ -69,6 +73,24 @@ public class DesktopInput extends InputHandler{ block.drawPlace(cursorX, cursorY, rotation, validPlace(cursorX, cursorY, block, rotation)); } + if(mode == none && !isPlacing()){ + BuildRequest req = getRequest(cursorX, cursorY); + if(req != null){ + drawSelected(req.x, req.y, req.breaking ? req.tile().block() : req.block, Pal.accent); + } + } + + if(sreq != null){ + boolean valid = validPlace(sreq.x, sreq.y, sreq.block, sreq.rotation, sreq); + if(sreq.block.rotate){ + drawArrow(sreq.block, sreq.x, sreq.y, sreq.rotation, valid); + } + + sreq.block.drawRequest(sreq, allRequests(), valid); + + drawSelected(sreq.x, sreq.y, sreq.block, getRequest(sreq.x, sreq.y, sreq.block.size, sreq) != null ? Pal.remove : Pal.accent); + } + Draw.reset(); } @@ -121,6 +143,11 @@ public class DesktopInput extends InputHandler{ } rotation = Mathf.mod(rotation + (int)Core.input.axisTap(Binding.rotate), 4); + + if(sreq != null){ + 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); } @@ -140,6 +167,10 @@ public class DesktopInput extends InputHandler{ cursorType = ui.drillCursor; } + if(getRequest(cursor.x, cursor.y) != null && mode == none){ + cursorType = SystemCursor.hand; + } + if(canTapPlayer(Core.input.mouseWorld().x, Core.input.mouseWorld().y)){ cursorType = ui.unloadCursor; } @@ -169,6 +200,14 @@ public class DesktopInput extends InputHandler{ player.clearBuilding(); } + if(sreq != null){ + float offset = ((sreq.block.size + 2) % 2) * tilesize / 2f; + float x = Core.input.mouseWorld().x + offset; + float y = Core.input.mouseWorld().y + offset; + sreq.x = (int)(x / tilesize); + sreq.y = (int)(y / tilesize); + } + if(block == null || mode != placing){ lineRequests.clear(); } @@ -180,6 +219,8 @@ public class DesktopInput extends InputHandler{ } if(Core.input.keyTap(Binding.select) && !Core.scene.hasMouse()){ + BuildRequest req = getRequest(cursorX, cursorY); + if(isPlacing()){ selectX = cursorX; selectY = cursorY; @@ -187,6 +228,8 @@ public class DesktopInput extends InputHandler{ lastLineY = cursorY; mode = placing; updateLine(selectX, selectY); + }else if(req != null && !req.breaking && mode == none){ + sreq = req; }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.buildQueue().size == 0 && !droppingItem && @@ -229,6 +272,13 @@ public class DesktopInput extends InputHandler{ tryDropItems(selected.link(), Core.input.mouseWorld().x, Core.input.mouseWorld().y); } + if(sreq != null){ + if(getRequest(sreq.x, sreq.y, sreq.block.size, sreq) != null){ + player.buildQueue().removeValue(sreq, true); + } + sreq = null; + } + mode = none; } } @@ -254,6 +304,7 @@ public class DesktopInput extends InputHandler{ droppingItem = false; mode = none; block = null; + sreq = null; } } } diff --git a/core/src/io/anuke/mindustry/input/InputHandler.java b/core/src/io/anuke/mindustry/input/InputHandler.java index 9ba51b1572..c2ef91d2cd 100644 --- a/core/src/io/anuke/mindustry/input/InputHandler.java +++ b/core/src/io/anuke/mindustry/input/InputHandler.java @@ -39,6 +39,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ /** Maximum line length. */ final static int maxLength = 100; final static Vector2 stackTrns = new Vector2(); + final static Rectangle r1 = new Rectangle(), r2 = new Rectangle(); /** Distance on the back from where items originate. */ final static float backTrns = 3f; @@ -52,6 +53,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ protected GestureDetector detector; protected PlaceLine line = new PlaceLine(); + protected BuildRequest resultreq; protected BuildRequest brequest = new BuildRequest(); protected Array lineRequests = new Array<>(); protected Array selectRequests = new Array<>(); @@ -194,7 +196,7 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ } public void drawSelected(int x, int y, Block block, Color color){ - Draw.color(Pal.remove); + Draw.color(color); for(int i = 0; i < 4; i++){ Point2 p = Geometry.d8edge[i]; float offset = -Math.max(block.size - 1, 0) / 2f * tilesize; @@ -221,6 +223,46 @@ public abstract class InputHandler implements InputProcessor, GestureListener{ drawSelected(x, y, block, Pal.remove); } + /** Returns the selection request that overlaps this position, or null. */ + protected BuildRequest getRequest(int x, int y){ + return getRequest(x, y, 1, null); + } + + /** Returns the selection request that overlaps this position, or null. */ + protected BuildRequest getRequest(int x, int y, int size, BuildRequest skip){ + float offset = ((size + 1) % 2) * tilesize / 2f; + r2.setSize(tilesize * size); + r2.setCenter(x * tilesize + offset, y * tilesize + offset); + resultreq = null; + + Predicate test = req -> { + if(req == skip) return false; + Tile other = req.tile(); + + if(other == null) return false; + + if(!req.breaking){ + r1.setSize(req.block.size * tilesize); + r1.setCenter(other.worldx() + req.block.offset(), other.worldy() + req.block.offset()); + }else{ + r1.setSize(other.block().size * tilesize); + r1.setCenter(other.worldx() + other.block().offset(), other.worldy() + other.block().offset()); + } + + return r2.overlaps(r1); + }; + + for(BuildRequest req : player.buildQueue()){ + if(test.test(req)) return req; + } + + for(BuildRequest req : selectRequests){ + if(test.test(req)) return req; + } + + return null; + } + protected void drawSelection(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); diff --git a/core/src/io/anuke/mindustry/input/MobileInput.java b/core/src/io/anuke/mindustry/input/MobileInput.java index d98d901e1d..9efd453a0b 100644 --- a/core/src/io/anuke/mindustry/input/MobileInput.java +++ b/core/src/io/anuke/mindustry/input/MobileInput.java @@ -29,7 +29,6 @@ import static io.anuke.mindustry.input.PlaceMode.*; public class MobileInput extends InputHandler implements GestureListener{ /** Maximum speed the player can pan. */ private static final float maxPanSpeed = 1.3f; - private static Rectangle r1 = new Rectangle(), r2 = new Rectangle(); /** Distance to edge of screen to start panning. */ private final float edgePan = Scl.scl(60f);