diff --git a/TODO.md b/TODO.md index 3309621ac9..ac5c9879c2 100644 --- a/TODO.md +++ b/TODO.md @@ -3,8 +3,8 @@ _Keep in mind that this is just a basic outline of planned features, and will be ### 3.0 Release - New tutorial with the power blocks - New SFX for specific blocks, especially turrets -- Block drawing layers. Refactor/remove `Block#drawOver()`, add `Layer` enum. Should fix 'glitchy' lasers and conveyor clipping -- Balance nuclear reactor, improve effectiveness as they are currently underpowered +- [DONE] Block drawing layers. Refactor/remove `Block#drawOver()`, add `Layer` enum. Should fix 'glitchy' lasers and conveyor clipping +- [DONE] Balance nuclear reactor, improve effectiveness as they are currently underpowered - Make generation frame independent - Investigate issue #5 (enemies stuck in blocks) - Faster mech movement, possibly with a "boost" key @@ -52,4 +52,7 @@ _Keep in mind that this is just a basic outline of planned features, and will be - Optimize generator laser distribution, especially finding targets - Optimize UI - Check memory usage and GC, profile +- Optimize health bars and enemies in general +- Make drawing of enemies more efficient (don't call `flush()`?) +- Look into `NodeRecord` storage for pathfinder, since it's taking 2MB+ of memory! diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index 2fa7952442..a64b7a7557 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -1,8 +1,8 @@ + android:versionCode="22" + android:versionName="3.06b" > diff --git a/build.gradle b/build.gradle index 1450c5c2fe..61901cb5b0 100644 --- a/build.gradle +++ b/build.gradle @@ -79,7 +79,7 @@ project(":core") { apply plugin: "java" dependencies { - compile 'com.github.Anuken:ucore:191a0bc25a' + compile 'com.github.Anuken:ucore:6238d06' compile "com.badlogicgames.gdx:gdx:$gdxVersion" compile "com.badlogicgames.gdx:gdx-ai:1.8.1" } diff --git a/core/assets-raw/sprites/enemyarrow.png b/core/assets-raw/sprites/enemyarrow.png index e2e0989c73..04e4f069be 100644 Binary files a/core/assets-raw/sprites/enemyarrow.png and b/core/assets-raw/sprites/enemyarrow.png differ diff --git a/core/assets/sprites/sprites.png b/core/assets/sprites/sprites.png index 67a390a345..1f20badea7 100644 Binary files a/core/assets/sprites/sprites.png and b/core/assets/sprites/sprites.png differ diff --git a/core/src/io/anuke/mindustry/Vars.java b/core/src/io/anuke/mindustry/Vars.java index 22267e5889..ec2f87178c 100644 --- a/core/src/io/anuke/mindustry/Vars.java +++ b/core/src/io/anuke/mindustry/Vars.java @@ -27,7 +27,7 @@ public class Vars{ //how far away from spawn points the player can't place blocks public static final float enemyspawnspace = 65; //scale of the font - public static final float fontscale = Unit.dp.inPixels(1f)/2f; + public static float fontscale = Unit.dp.inPixels(1f)/2f; //camera zoom displayed on startup public static final int baseCameraScale = Math.round(Unit.dp.inPixels(4)); //how much the zoom changes every zoom button press diff --git a/core/src/io/anuke/mindustry/core/Control.java b/core/src/io/anuke/mindustry/core/Control.java index 899890991b..0660e32610 100644 --- a/core/src/io/anuke/mindustry/core/Control.java +++ b/core/src/io/anuke/mindustry/core/Control.java @@ -199,9 +199,7 @@ public class Control extends Module{ play(); }); - Timers.run(18, ()->{ - ui.hideLoading(); - }); + Timers.run(18, ()-> ui.hideLoading()); } public GameMode getMode(){ @@ -306,9 +304,7 @@ public class Control extends Module{ } Effects.effect(Fx.coreexplosion, core.worldx(), core.worldy()); - Timers.run(60, ()->{ - ui.showRestart(); - }); + Timers.run(60, ()-> ui.showRestart()); } float waveSpacing(){ diff --git a/core/src/io/anuke/mindustry/core/Renderer.java b/core/src/io/anuke/mindustry/core/Renderer.java index d6c1b4cc95..d508abdf0e 100644 --- a/core/src/io/anuke/mindustry/core/Renderer.java +++ b/core/src/io/anuke/mindustry/core/Renderer.java @@ -32,19 +32,22 @@ import io.anuke.ucore.entities.DestructibleEntity; import io.anuke.ucore.entities.EffectEntity; import io.anuke.ucore.entities.Entities; import io.anuke.ucore.graphics.CacheBatch; +import io.anuke.ucore.graphics.Surface; import io.anuke.ucore.modules.RendererModule; import io.anuke.ucore.scene.ui.layout.Unit; import io.anuke.ucore.scene.utils.Cursors; import io.anuke.ucore.util.*; public class Renderer extends RendererModule{ - String[] surfaces = { "shadow", "shield", "pixel", "indicators" }; - int targetscale = baseCameraScale; - int chunksize = 32; - int[][][] cache; - FloatArray shieldHits = new FloatArray(); - float shieldHitDuration = 18f; - CacheBatch cbatch; + private final static int chunksize = 32; + private final static float shieldHitDuration = 18f; + + public Surface shadowSurface, shieldSurface, indicatorSurface; + + private int targetscale = baseCameraScale; + private int[][][] cache; + private FloatArray shieldHits = new FloatArray(); + private CacheBatch cbatch; public Renderer() { Core.cameraScale = baseCameraScale; @@ -63,9 +66,12 @@ public class Renderer extends RendererModule{ @Override public void init(){ pixelate = Settings.getBool("pixelate"); - for(String surface : surfaces){ - Graphics.addSurface(surface, Settings.getBool("pixelate") ? Core.cameraScale : 1); - } + int scale = Settings.getBool("pixelate") ? Core.cameraScale : 1; + + shadowSurface = Graphics.createSurface(scale); + shieldSurface = Graphics.createSurface(scale); + indicatorSurface = Graphics.createSurface(scale); + pixelSurface = Graphics.createSurface(scale); } public void setPixelate(boolean pixelate){ @@ -81,9 +87,7 @@ public class Renderer extends RendererModule{ if(Mathf.in(camera.zoom, targetzoom, 0.005f)){ camera.zoom = 1f; - Core.cameraScale = targetscale; - camera.viewportWidth = Gdx.graphics.getWidth() / Core.cameraScale; - camera.viewportHeight = Gdx.graphics.getHeight() / Core.cameraScale; + Graphics.setCameraScale(targetscale); AndroidInput.mousex = Gdx.graphics.getWidth() / 2; AndroidInput.mousey = Gdx.graphics.getHeight() / 2; @@ -158,12 +162,15 @@ public class Renderer extends RendererModule{ @Override public void draw(){ - Graphics.surface("shield"); + //clera shield surface + Graphics.surface(shieldSurface); Graphics.surface(); + + boolean optimize = false; Profiler.begin("blockDraw"); drawFloor(); - drawBlocks(false); + drawBlocks(false, optimize); Profiler.end("blockDraw"); Profiler.begin("entityDraw"); @@ -177,11 +184,11 @@ public class Renderer extends RendererModule{ Profiler.end("entityDraw"); - drawBlocks(true); + if(!optimize) drawBlocks(true, false); drawShield(); - renderPixelOverlay(); + drawOverlay(); if(Settings.getBool("indicators")){ drawEnemyMarkers(); @@ -198,7 +205,7 @@ public class Renderer extends RendererModule{ } void drawEnemyMarkers(){ - Graphics.surface("indicators"); + Graphics.surface(indicatorSurface); Draw.color(Color.RED); //Draw.alpha(0.6f); for(Enemy enemy : control.enemyGroup.all()){ @@ -232,7 +239,7 @@ public class Renderer extends RendererModule{ } } - Texture texture = Graphics.getSurface("shield").texture(); + Texture texture = shieldSurface.texture(); Shaders.shield.color.set(Color.SKY); Tmp.tr2.setRegion(texture); @@ -273,8 +280,8 @@ public class Renderer extends RendererModule{ Graphics.end(); - int crangex = (int) (camera.viewportWidth / (chunksize * tilesize)) + 1; - int crangey = (int) (camera.viewportHeight / (chunksize * tilesize)) + 1; + int crangex = Math.round(camera.viewportWidth * camera.zoom / (chunksize * tilesize)); + int crangey = Math.round(camera.viewportHeight * camera.zoom / (chunksize * tilesize)); drawCache(0, crangex, crangey); @@ -303,12 +310,12 @@ public class Renderer extends RendererModule{ } } - void drawBlocks(boolean top){ + void drawBlocks(boolean top, boolean optimize){ int crangex = (int) (camera.viewportWidth / (chunksize * tilesize)) + 1; int crangey = (int) (camera.viewportHeight / (chunksize * tilesize)) + 1; - int rangex = (int) (camera.viewportWidth * camera.zoom / tilesize / 2) + 2; - int rangey = (int) (camera.viewportHeight * camera.zoom / tilesize / 2) + 2; + int rangex = (int) (camera.viewportWidth * camera.zoom / tilesize / 2)+2; + int rangey = (int) (camera.viewportHeight * camera.zoom / tilesize / 2)+2; boolean noshadows = Settings.getBool("noshadows"); @@ -318,8 +325,8 @@ public class Renderer extends RendererModule{ Layer[] layers = Layer.values(); - int start = top ? 4 : (noshadows ? 1 : 0); - int end = top ? 4 + layers.length-1 : 4; + int start = optimize ? (noshadows ? 1 : 0) : (top ? 4 : (noshadows ? 1 : 0)); + int end = optimize ? 4 : (top ? 4 + layers.length-1 : 4); //0 = shadows //1 = cache blocks @@ -327,13 +334,13 @@ public class Renderer extends RendererModule{ //3+ = layers for(int l = start; l < end; l++){ if(l == 0){ - Graphics.surface("shadow"); + Graphics.surface(shadowSurface); } Layer layer = l >= 3 ? layers[l - 3] : null; - boolean expand = l >= 2; - int expandr = (expand ? 4 : 0); + boolean expand = layer == Layer.power; + int expandr = (expand ? 3 : 0); if(l == 1){ Graphics.end(); @@ -353,15 +360,18 @@ public class Renderer extends RendererModule{ tile.block().drawShadow(tile); } }else if(!(tile.block() instanceof StaticBlock) && - !expanded || tile.block().expanded){ + (!expanded || tile.block().expanded)){ if(l == 2){ tile.block().draw(tile); - }else{ + }else if(!optimize){ if(tile.block().layer == layer) tile.block().drawLayer(tile); if(tile.block().layer2 == layer) tile.block().drawLayer2(tile); + }else if(l == 3){ + tile.block().drawLayer(tile); + tile.block().drawLayer2(tile); } } } @@ -437,7 +447,7 @@ public class Renderer extends RendererModule{ Draw.reset(); } - void renderPixelOverlay(){ + void drawOverlay(){ //draw tutorial placement point if(Vars.control.tutorial.showBlock()){ @@ -571,7 +581,8 @@ public class Renderer extends RendererModule{ void drawHealth(float x, float y, float health, float maxhealth){ drawBar(Color.RED, x, y, health / maxhealth); } - + + //TODO optimize! public void drawBar(Color color, float x, float y, float fraction){ float len = 3; @@ -595,9 +606,10 @@ public class Renderer extends RendererModule{ public void setCameraScale(int amount){ targetscale = amount; clampScale(); + //scale up all surfaces in preparation for the zoom if(Settings.getBool("pixelate")){ - for(String surface : surfaces){ - Graphics.getSurface(surface).setScale(targetscale); + for(Surface surface : Graphics.getSurfaces()){ + surface.setScale(targetscale); } } } diff --git a/core/src/io/anuke/mindustry/core/UI.java b/core/src/io/anuke/mindustry/core/UI.java index dfdaabbd33..feb8f1ad39 100644 --- a/core/src/io/anuke/mindustry/core/UI.java +++ b/core/src/io/anuke/mindustry/core/UI.java @@ -175,6 +175,17 @@ public class UI extends SceneModule{ prefs.screenshakePref(); prefs.volumePrefs(); + //this is incredinbly buggy + /* + prefs.sliderPref("sscale", "UI Scale", 100, 25, 200, i ->{ + + Unit.dp.multiplier = i / 100f; + fontscale = Unit.dp.inPixels(1f)/2f; + skin.font().getData().setScale(fontscale); + invalidateAll(); + + return i + "%"; + });*/ prefs.checkPref("fps", "Show FPS", false); prefs.checkPref("noshadows", "Disable shadows", false); @@ -184,12 +195,12 @@ public class UI extends SceneModule{ prefs.checkPref("drawblocks", "Draw Blocks", true); prefs.checkPref("pixelate", "Pixelate Screen", true, b->{ if(b){ - Graphics.getSurface("pixel").setScale(Core.cameraScale); - Graphics.getSurface("shadow").setScale(Core.cameraScale); - Graphics.getSurface("shield").setScale(Core.cameraScale); + Vars.renderer.pixelSurface.setScale(Core.cameraScale); + Vars.renderer.shadowSurface.setScale(Core.cameraScale); + Vars.renderer.shieldSurface.setScale(Core.cameraScale); }else{ - Graphics.getSurface("shadow").setScale(1); - Graphics.getSurface("shield").setScale(1); + Vars.renderer.shadowSurface.setScale(1); + Vars.renderer.shieldSurface.setScale(1); } renderer.setPixelate(b); }); @@ -280,6 +291,15 @@ public class UI extends SceneModule{ build.end(); } + void invalidateAll(){ + for(Element e : scene.getElements()){ + if(e instanceof Table){ + ((Table)e).invalidateHierarchy(); + } + + } + } + public void updateWeapons(){ ((WeaponFragment)weaponfrag).updateWeapons(); } diff --git a/core/src/io/anuke/mindustry/entities/effect/Shield.java b/core/src/io/anuke/mindustry/entities/effect/Shield.java index ea4c28b0a1..2f4d6c03b3 100644 --- a/core/src/io/anuke/mindustry/entities/effect/Shield.java +++ b/core/src/io/anuke/mindustry/entities/effect/Shield.java @@ -76,7 +76,7 @@ public class Shield extends Entity{ float rad = drawRadius(); - Graphics.surface("shield", false); + Graphics.surface(Vars.renderer.shieldSurface, false); Draw.color(Color.ROYAL); Draw.thick(2f); Draw.rect("circle2", x, y, rad, rad); diff --git a/core/src/io/anuke/mindustry/entities/enemies/Enemy.java b/core/src/io/anuke/mindustry/entities/enemies/Enemy.java index 42778cd0a5..4252601223 100644 --- a/core/src/io/anuke/mindustry/entities/enemies/Enemy.java +++ b/core/src/io/anuke/mindustry/entities/enemies/Enemy.java @@ -65,11 +65,10 @@ public class Enemy extends DestructibleEntity{ Tile core = Vars.control.getCore(); boolean nearCore = distanceTo(core.worldx(), core.worldy()) <= range - 18f && stopNearCore; - Vector2 vec; - + if(nearCore){ - vec = Tmp.v2.setZero(); + vec = Tmp.v1.setZero(); if(targetCore) target = core.entity; }else{ vec = Vars.world.pathfinder().find(this); @@ -84,9 +83,8 @@ public class Enemy extends DestructibleEntity{ Entities.getNearby(Vars.control.enemyGroup, x, y, range, other -> { Enemy enemy = (Enemy)other; + if(other == this) return; float dst = other.distanceTo(this); - if(other == this) - return; if(dst < shiftRange){ float scl = Mathf.clamp(1.4f - dst / shiftRange) * enemy.mass * 1f/mass; diff --git a/core/src/io/anuke/mindustry/entities/enemies/HealerEnemy.java b/core/src/io/anuke/mindustry/entities/enemies/HealerEnemy.java index 6659bff146..210a32ea53 100644 --- a/core/src/io/anuke/mindustry/entities/enemies/HealerEnemy.java +++ b/core/src/io/anuke/mindustry/entities/enemies/HealerEnemy.java @@ -3,11 +3,11 @@ package io.anuke.mindustry.entities.enemies; import com.badlogic.gdx.math.MathUtils; import io.anuke.mindustry.Vars; +import io.anuke.mindustry.entities.Bullet; import io.anuke.mindustry.entities.BulletType; +import io.anuke.mindustry.entities.effect.Fx; import io.anuke.mindustry.entities.effect.Shaders; -import io.anuke.ucore.core.Draw; -import io.anuke.ucore.core.Graphics; -import io.anuke.ucore.core.Timers; +import io.anuke.ucore.core.*; import io.anuke.ucore.entities.Entities; import io.anuke.ucore.graphics.Hue; import io.anuke.ucore.util.Angles; @@ -19,19 +19,30 @@ public class HealerEnemy extends Enemy{ speed = 0.25f; reload = 10; maxhealth = 200; - range = 90f; bullet = BulletType.shot; - range = 30f; + range = 40f; alwaysRotate = false; targetCore = false; + stopNearCore = true; mass = 1.1f; heal(); } + @Override + void move(){ + super.move(); + + if(idletime > 60f*3){ //explode after 3 seconds of stillness + explode(); + Effects.effect(Fx.shellexplosion, this); + Effects.effect(Fx.shellsmoke, this); + } + } + @Override void updateTargeting(boolean nearCore){ - if(Timers.get(this, "target", 15)){ + if(timer.get(timerTarget, 15)){ target = Entities.getClosest(Vars.control.enemyGroup, x, y, range, e -> e instanceof Enemy && e != this && ((Enemy)e).healthfrac() < 1f); } @@ -47,6 +58,7 @@ public class HealerEnemy extends Enemy{ if(enemy.health < enemy.maxhealth && Timers.get(this, "heal", reload)){ enemy.health ++; + idletime = 0; } } @@ -68,5 +80,11 @@ public class HealerEnemy extends Enemy{ } Graphics.shader(Shaders.outline); } + + void explode(){ + Bullet b = new Bullet(BulletType.blast, this, x, y, 0).add(); + b.damage = BulletType.blast.damage + (tier-1) * 40; + damage(999); + } } diff --git a/core/src/io/anuke/mindustry/input/AndroidInput.java b/core/src/io/anuke/mindustry/input/AndroidInput.java index 0bca99eca2..4185afc536 100644 --- a/core/src/io/anuke/mindustry/input/AndroidInput.java +++ b/core/src/io/anuke/mindustry/input/AndroidInput.java @@ -85,7 +85,7 @@ public class AndroidInput extends InputAdapter{ int tilex = Mathf.scl2(vec.x, tilesize); int tiley = Mathf.scl2(vec.y, tilesize); - if(player.recipe != null && Vars.world.validPlace(tilex, tiley, player.recipe.result)){ + if(player.recipe != null && Vars.control.hasItems(player.recipe.requirements) && Vars.world.validPlace(tilex, tiley, player.recipe.result)){ Vars.world.placeBlock(tilex, tiley, player.recipe.result, player.rotation); @@ -98,10 +98,7 @@ public class AndroidInput extends InputAdapter{ public static void doInput(){ if(Gdx.input.isTouched(0) && Mathf.near2d(lmousex, lmousey, Gdx.input.getX(0), Gdx.input.getY(0), Unit.dp.inPixels(50)) - && !ui.hasMouse() /* - * && (player.recipe == null || mode == - * PlaceMode.touch) - */){ + && !ui.hasMouse()){ warmup += Timers.delta(); float lx = mousex, ly = mousey; diff --git a/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java b/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java index 297c0dbb69..f6b8ef2750 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java @@ -215,6 +215,7 @@ public class HudFragment implements Fragment{ for(int i = 0; i < control.getItems().length; i ++){ int amount = control.getItems()[i]; + if(amount == 0) continue; String formatted = Mindustry.formatter.format(amount); if(amount > 99999999){ formatted = "inf"; diff --git a/core/src/io/anuke/mindustry/ui/fragments/WeaponFragment.java b/core/src/io/anuke/mindustry/ui/fragments/WeaponFragment.java index 788b94ff94..cf8f881991 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/WeaponFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/WeaponFragment.java @@ -18,7 +18,7 @@ public class WeaponFragment implements Fragment{ public void build(){ weapontable = Core.scene.table(); weapontable.bottom().left(); - weapontable.setVisible(()->!GameState.is(State.menu)); + weapontable.setVisible(()-> !GameState.is(State.menu)); if(android){ weapontable.remove(); diff --git a/core/src/io/anuke/mindustry/world/blocks/ProductionBlocks.java b/core/src/io/anuke/mindustry/world/blocks/ProductionBlocks.java index d81e92fdfd..178498945d 100644 --- a/core/src/io/anuke/mindustry/world/blocks/ProductionBlocks.java +++ b/core/src/io/anuke/mindustry/world/blocks/ProductionBlocks.java @@ -257,7 +257,7 @@ public class ProductionBlocks{ formalName = "RTG generator"; generateItem = Item.uranium; powerCapacity = 40f; - powerOutput = 0.055f; + powerOutput = 0.05f; itemDuration = 250f; description = "Generates power from uranium."; fullDescription = "Generates small amounts of power from the radioactive decay of uranium. Outputs power as lasers to its 4 sides."; diff --git a/core/src/io/anuke/mindustry/world/blocks/types/defense/ShieldedWallBlock.java b/core/src/io/anuke/mindustry/world/blocks/types/defense/ShieldedWallBlock.java index 811cfb75be..034f2aaa84 100644 --- a/core/src/io/anuke/mindustry/world/blocks/types/defense/ShieldedWallBlock.java +++ b/core/src/io/anuke/mindustry/world/blocks/types/defense/ShieldedWallBlock.java @@ -48,7 +48,7 @@ public class ShieldedWallBlock extends PowerBlock{ ShieldedWallEntity entity = tile.entity(); if(entity.power > powerToDamage){ - Graphics.surface("shield", false); + Graphics.surface(Vars.renderer.shieldSurface, false); Draw.color(Color.ROYAL); Draw.rect("blank", tile.worldx(), tile.worldy(), Vars.tilesize, Vars.tilesize); Graphics.surface(); diff --git a/core/src/io/anuke/mindustry/world/blocks/types/production/NuclearReactor.java b/core/src/io/anuke/mindustry/world/blocks/types/production/NuclearReactor.java index b2cfdf32ec..486767ca85 100644 --- a/core/src/io/anuke/mindustry/world/blocks/types/production/NuclearReactor.java +++ b/core/src/io/anuke/mindustry/world/blocks/types/production/NuclearReactor.java @@ -26,7 +26,7 @@ public class NuclearReactor extends LiquidItemPowerGenerator{ protected Color coolColor = new Color(1, 1, 1, 0f); protected Color hotColor = Color.valueOf("ff9575a3"); protected int fuelUseTime = 120; //time to consume 1 fuel - protected float powerMultiplier = 0.08f; //power per frame, depends on full capacity + protected float powerMultiplier = 0.2f; //power per frame, depends on full capacity protected float heating = 0.007f; //heating per frame protected float coolantPower = 0.007f; //how much heat decreases per coolant unit protected float smokeThreshold = 0.3f; //threshold at which block starts smoking