diff --git a/core/assets/bundles/bundle.properties b/core/assets/bundles/bundle.properties index 63a3e099d4..2709ee58da 100644 --- a/core/assets/bundles/bundle.properties +++ b/core/assets/bundles/bundle.properties @@ -270,6 +270,7 @@ setting.multithread.name=Multithreading setting.fps.name=Show FPS setting.vsync.name=VSync setting.lasers.name=Show Power Lasers +setting.previewopacity.name=Placing Preview Opacity setting.healthbars.name=Show Entity Health bars setting.pixelate.name=Pixelate Screen setting.musicvol.name=Music Volume diff --git a/core/src/io/anuke/mindustry/graphics/BlockRenderer.java b/core/src/io/anuke/mindustry/graphics/BlockRenderer.java index e53ffacd1b..967449dfff 100644 --- a/core/src/io/anuke/mindustry/graphics/BlockRenderer.java +++ b/core/src/io/anuke/mindustry/graphics/BlockRenderer.java @@ -12,13 +12,14 @@ import io.anuke.mindustry.world.Layer; import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.blocks.Blocks; import io.anuke.mindustry.world.blocks.types.StaticBlock; +import io.anuke.mindustry.world.blocks.types.defense.Turret; import io.anuke.ucore.core.Core; import io.anuke.ucore.core.Graphics; +import io.anuke.ucore.core.Settings; import io.anuke.ucore.graphics.CacheBatch; import io.anuke.ucore.graphics.Draw; import io.anuke.ucore.graphics.Lines; import io.anuke.ucore.util.Mathf; - import java.util.Arrays; import static io.anuke.mindustry.Vars.*; @@ -27,6 +28,8 @@ import static io.anuke.ucore.core.Core.camera; public class BlockRenderer{ private final static int chunksize = 32; private final static int initialRequests = 32*32; + private static float storeX = 0; + private static float storeY = 0; private int[][][] cache; private CacheBatch cbatch; @@ -49,7 +52,7 @@ public class BlockRenderer{ public int compareTo(BlockRequest other){ return layer.compareTo(other.layer); } - + @Override public String toString(){ return tile.block().name + ":" + layer.toString(); @@ -65,11 +68,11 @@ public class BlockRenderer{ int rangex = (int) (camera.viewportWidth * camera.zoom / tilesize / 2)+2; int rangey = (int) (camera.viewportHeight * camera.zoom / tilesize / 2)+2; - + int expandr = 3; Graphics.surface(renderer.shadowSurface); - + for(int x = -rangex - expandr; x <= rangex + expandr; x++){ for(int y = -rangey - expandr; y <= rangey + expandr; y++){ int worldx = Mathf.scl(camera.position.x, tilesize) + x; @@ -89,16 +92,16 @@ public class BlockRenderer{ if(block == Blocks.air){ if(!state.is(State.paused)) tile.floor().update(tile); }else{ - + if(!expanded){ addRequest(tile, Layer.block); } - + if(block.expanded || !expanded){ if(block.layer != null && block.isLayer(tile)){ addRequest(tile, block.layer); } - + if(block.layer2 != null && block.isLayer2(tile)){ addRequest(tile, block.layer2); } @@ -120,7 +123,7 @@ public class BlockRenderer{ Arrays.sort(requests.items, 0, requestidx); iterateidx = 0; } - + public int getRequests(){ return requestidx; } @@ -129,14 +132,14 @@ public class BlockRenderer{ Layer stopAt = top ? Layer.laser : Layer.overlay; for(; iterateidx < requestidx; iterateidx ++){ - + if(iterateidx < requests.size - 1 && requests.get(iterateidx).layer.ordinal() > stopAt.ordinal()){ break; } BlockRequest req = requests.get(iterateidx); Block block = req.tile.block(); - + if(req.layer == Layer.block){ block.draw(req.tile); }else if(req.layer == block.layer){ @@ -162,11 +165,11 @@ public class BlockRenderer{ public void drawFloor(){ int chunksx = world.width() / chunksize, chunksy = world.height() / chunksize; - + //render the entire map if(cache == null || cache.length != chunksx || cache[0].length != chunksy){ cache = new int[chunksx][chunksy][2]; - + for(int x = 0; x < chunksx; x++){ for(int y = 0; y < chunksy; y++){ cacheChunk(x, y, true); @@ -174,24 +177,24 @@ public class BlockRenderer{ } } } - + OrthographicCamera camera = Core.camera; - + if(Graphics.drawing()) Graphics.end(); - + int crangex = (int)(camera.viewportWidth * camera.zoom / (chunksize * tilesize))+1; int crangey = (int)(camera.viewportHeight * camera.zoom / (chunksize * tilesize))+1; - + drawCache(0, crangex, crangey); - + Graphics.begin(); - + Draw.reset(); if(showPaths && debug){ drawPaths(); } - + if(debug && debugChunks){ Draw.color(Color.YELLOW); Lines.stroke(1f); @@ -199,7 +202,7 @@ public class BlockRenderer{ for(int y = -crangey; y <= crangey; y++){ int worldx = Mathf.scl(camera.position.x, chunksize * tilesize) + x; int worldy = Mathf.scl(camera.position.y, chunksize * tilesize) + y; - + if(!Mathf.inBounds(worldx, worldy, cache)) continue; Lines.rect(worldx * chunksize * tilesize, worldy * chunksize * tilesize, chunksize * tilesize, chunksize * tilesize); @@ -215,7 +218,7 @@ public class BlockRenderer{ if(point.pathTiles != null){ for(int i = 1; i < point.pathTiles.length; i ++){ Lines.line(point.pathTiles[i-1].worldx(), point.pathTiles[i-1].worldy(), - point.pathTiles[i].worldx(), point.pathTiles[i].worldy()); + point.pathTiles[i].worldx(), point.pathTiles[i].worldy()); Lines.circle(point.pathTiles[i-1].worldx(), point.pathTiles[i-1].worldy(), 6f); } } @@ -223,35 +226,35 @@ public class BlockRenderer{ Draw.reset(); } - + void drawCache(int layer, int crangex, int crangey){ Gdx.gl.glEnable(GL20.GL_BLEND); - + cbatch.setProjectionMatrix(Core.camera.combined); cbatch.beginDraw(); for(int x = -crangex; x <= crangex; x++){ for(int y = -crangey; y <= crangey; y++){ int worldx = Mathf.scl(camera.position.x, chunksize * tilesize) + x; int worldy = Mathf.scl(camera.position.y, chunksize * tilesize) + y; - + if(!Mathf.inBounds(worldx, worldy, cache)) continue; - + cbatch.drawCache(cache[worldx][worldy][layer]); } } - + cbatch.endDraw(); } - + void cacheChunk(int cx, int cy, boolean floor){ if(cbatch == null){ createBatch(); } - + cbatch.begin(); Graphics.useBatch(cbatch); - + for(int tilex = cx * chunksize; tilex < (cx + 1) * chunksize; tilex++){ for(int tiley = cy * chunksize; tiley < (cy + 1) * chunksize; tiley++){ Tile tile = world.tile(tilex, tiley); @@ -269,15 +272,60 @@ public class BlockRenderer{ cbatch.end(); cache[cx][cy][floor ? 0 : 1] = cbatch.getLastCache(); } - + public void clearTiles(){ cache = null; createBatch(); } - + private void createBatch(){ if(cbatch != null) cbatch.dispose(); cbatch = new CacheBatch(world.width() * world.height() * 4); } -} + + public void drawPreview(Block block, float drawx, float drawy, float rotation, float opacity) { + Draw.alpha(opacity); + Draw.rect(block.name(), drawx, drawy, rotation); + } + + public void handlePreview(Block block, float rotation, float drawx, float drawy, int tilex, int tiley) { + + if(control.input().recipe != null && state.inventory.hasItems(control.input().recipe.requirements) + && control.input().validPlace(tilex, tiley, block) && (android || control.input().cursorNear())) { + + if(block.isMultiblock()) { + float halfBlockWidth = (block.width * tilesize) / 2; + float halfBlockHeight = (block.height * tilesize) / 2; + if((storeX == 0 && storeY == 0)) { + storeX = drawx; + storeY = drawy; + } + if((storeX == drawx - halfBlockWidth || storeX == drawx + halfBlockWidth || storeY == drawy - halfBlockHeight || storeY == drawy + halfBlockHeight) && + ((tiley - control.input().getBlockY()) % block.height != 0 || (tilex - control.input().getBlockX()) % block.width != 0)) { + return; + } + else { + storeX = drawx; + storeY = drawy; + } + } + + float opacity = (float) Settings.getInt("previewopacity") / 100f; + Draw.color(Color.WHITE); + Draw.alpha(opacity); + + if(block instanceof Turret) { + if (block.isMultiblock()) { + Draw.rect("block-" + block.width + "x" + block.height, drawx, drawy); + } else { + Draw.rect("block", drawx, drawy); + } + } + + drawPreview(block, drawx, drawy, rotation, opacity); + + Draw.reset(); + } + } +} \ No newline at end of file diff --git a/core/src/io/anuke/mindustry/input/PlaceMode.java b/core/src/io/anuke/mindustry/input/PlaceMode.java index 0ac5439057..6bfbf4e57d 100644 --- a/core/src/io/anuke/mindustry/input/PlaceMode.java +++ b/core/src/io/anuke/mindustry/input/PlaceMode.java @@ -29,20 +29,22 @@ public enum PlaceMode{ float y = tiley * tilesize; boolean valid = control.input().validPlace(tilex, tiley, control.input().recipe.result) && (android || control.input().cursorNear()); - + Vector2 offset = control.input().recipe.result.getPlaceOffset(); - + float si = MathUtils.sin(Timers.time() / 6f) + 1.5f; - + + renderer.getBlocks().handlePreview(control.input().recipe.result, control.input().recipe.result.rotate ? control.input().rotation * 90 : 0f, x + offset.x, y + offset.y, tilex, tiley); + Draw.color(valid ? Colors.get("place") : Colors.get("placeInvalid")); Lines.stroke(2f); Lines.crect(x + offset.x, y + offset.y, tilesize * control.input().recipe.result.width + si, - tilesize * control.input().recipe.result.height + si); - + tilesize * control.input().recipe.result.height + si); + control.input().recipe.result.drawPlace(tilex, tiley, control.input().rotation, valid); - Lines.stroke(2f); - + if(control.input().recipe.result.rotate){ + Draw.color(Colors.get("placeRotate")); tr.trns(control.input().rotation * 90, 7, 0); Lines.line(x, y, x + tr.x, y + tr.y); @@ -126,9 +128,9 @@ public enum PlaceMode{ process(tilex, tiley, endx, endy); - tilex = this.tilex; tiley = this.tiley; + tilex = this.tilex; tiley = this.tiley; endx = this.endx; endy = this.endy; - float x = this.tilex * t, y = this.tiley * t, + float x = this.tilex * t, y = this.tiley * t, x2 = this.endx * t, y2 = this.endy * t; if(x2 >= x){ @@ -150,7 +152,7 @@ public enum PlaceMode{ tile = tile.getLinked(); if(tile != null && control.input().validBreak(tile.x, tile.y)){ Lines.crect(tile.drawx(), tile.drawy(), - tile.block().width * t, tile.block().height * t); + tile.block().width * t, tile.block().height * t); } } } @@ -165,9 +167,9 @@ public enum PlaceMode{ public void released(int tilex, int tiley, int endx, int endy){ process(tilex, tiley, endx, endy); - tilex = this.tilex; tiley = this.tiley; + tilex = this.tilex; tiley = this.tiley; endx = this.endx; endy = this.endy; - + if(android){ ToolFragment t = ui.toolfrag; if(!t.confirming || t.px != tilex || t.py != tiley || t.px2 != endx || t.py2 != endy) { @@ -244,9 +246,9 @@ public enum PlaceMode{ process(tilex, tiley, endx, endy); int tx = tilex, ty = tiley, ex = endx, ey = endy; - tilex = this.tilex; tiley = this.tiley; + tilex = this.tilex; tiley = this.tiley; endx = this.endx; endy = this.endy; - float x = this.tilex * t, y = this.tiley * t, + float x = this.tilex * t, y = this.tiley * t, x2 = this.endx * t, y2 = this.endy * t; if(x2 >= x){ @@ -272,17 +274,19 @@ public enum PlaceMode{ Lines.rect(x, y, x2 - x, y2 - y); Draw.alpha(0.3f); Draw.crect("blank", x, y, x2 - x, y2 - y); - - Draw.color(Colors.get("placeInvalid")); int amount = 1; for(int cx = 0; cx <= Math.abs(endx - tilex); cx ++){ for(int cy = 0; cy <= Math.abs(endy - tiley); cy ++){ - int px = tx + cx * Mathf.sign(ex - tx), - py = ty + cy * Mathf.sign(ey - ty); + int px = tx + cx * Mathf.sign(ex - tx), + py = ty + cy * Mathf.sign(ey - ty); + + renderer.getBlocks().handlePreview(control.input().recipe.result, control.input().recipe.result.rotate ? rotation * 90 : 0f, px * t + offset.x, py * t + offset.y, px, py); if(!control.input().validPlace(px, py, control.input().recipe.result) - || !state.inventory.hasItems(control.input().recipe.requirements, amount)){ + || !state.inventory.hasItems(control.input().recipe.requirements, amount)){ + Lines.stroke(2f); + Draw.color(Colors.get("placeInvalid")); Lines.crect(px * t + offset.x, py * t + offset.y, t*block.width, t*block.height); } amount ++; @@ -291,6 +295,7 @@ public enum PlaceMode{ if(control.input().recipe.result.rotate){ float cx = tx * t, cy = ty * t; + Lines.stroke(2f); Draw.color(Colors.get("placeRotate")); tr.trns(rotation * 90, 7, 0); Lines.line(cx, cy, cx + tr.x, cy + tr.y); @@ -308,7 +313,7 @@ public enum PlaceMode{ for(int x = 0; x <= Math.abs(this.endx - this.tilex); x ++){ for(int y = 0; y <= Math.abs(this.endy - this.tiley); y ++){ if(control.input().tryPlaceBlock( - tilex + x * Mathf.sign(endx - tilex), + tilex + x * Mathf.sign(endx - tilex), tiley + y * Mathf.sign(endy - tiley), first)){ first = false; } @@ -340,7 +345,7 @@ public enum PlaceMode{ rotation = 1; else if(endy < tiley) rotation = 3; - else + else rotation = control.input().rotation; if(endx < tilex){ @@ -367,23 +372,23 @@ public enum PlaceMode{ public boolean showCancel; public boolean delete = false; public boolean both = false; - + private static final Translator tr = new Translator(); public void draw(int tilex, int tiley, int endx, int endy){ - + } public void released(int tilex, int tiley, int endx, int endy){ - + } public void tapped(int x, int y){ - + } - + @Override public String toString(){ return Bundles.get("placemode."+name().toLowerCase()+".name"); } -} +} \ No newline at end of file diff --git a/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java b/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java index 6d2e79c610..895122b158 100644 --- a/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java +++ b/core/src/io/anuke/mindustry/ui/dialogs/SettingsMenuDialog.java @@ -139,6 +139,7 @@ public class SettingsMenuDialog extends SettingsDialog{ graphics.checkPref("fps", false); graphics.checkPref("lasers", true); + graphics.sliderPref("previewopacity", 50, 0, 100, i -> i + "%"); graphics.checkPref("indicators", true); graphics.checkPref("healthbars", true); graphics.checkPref("pixelate", true, b -> {