From ccd25c7e76a4bc9dc997c024258273fc0184adda Mon Sep 17 00:00:00 2001 From: Anuken Date: Thu, 19 Apr 2018 21:57:55 -0400 Subject: [PATCH] Implemented basic minimap --- core/assets/version.properties | 2 +- core/src/io/anuke/mindustry/core/World.java | 14 +++ .../mindustry/entities/effect/Puddle.java | 25 +++-- .../io/anuke/mindustry/game/EventType.java | 62 +----------- core/src/io/anuke/mindustry/game/Team.java | 2 + .../mindustry/graphics/MinimapRenderer.java | 96 ++++++++++++++++++- .../mindustry/input/DefaultKeybinds.java | 1 + .../anuke/mindustry/input/DesktopInput.java | 2 + .../mindustry/ui/fragments/DebugFragment.java | 2 +- .../mindustry/ui/fragments/HudFragment.java | 35 +++++++ core/src/io/anuke/mindustry/world/Tile.java | 2 + 11 files changed, 172 insertions(+), 71 deletions(-) diff --git a/core/assets/version.properties b/core/assets/version.properties index 18f7b305c9..a3c832a2dd 100644 --- a/core/assets/version.properties +++ b/core/assets/version.properties @@ -1,5 +1,5 @@ #Autogenerated file. Do not modify. -#Thu Apr 19 19:06:19 EDT 2018 +#Thu Apr 19 21:55:56 EDT 2018 version=release androidBuildCode=1073 name=Mindustry diff --git a/core/src/io/anuke/mindustry/core/World.java b/core/src/io/anuke/mindustry/core/World.java index 54cb0c7f30..ddb52fadfa 100644 --- a/core/src/io/anuke/mindustry/core/World.java +++ b/core/src/io/anuke/mindustry/core/World.java @@ -6,12 +6,15 @@ import com.badlogic.gdx.math.MathUtils; import com.badlogic.gdx.utils.Array; import io.anuke.mindustry.ai.Pathfind; import io.anuke.mindustry.content.blocks.Blocks; +import io.anuke.mindustry.game.EventType.TileChangeEvent; +import io.anuke.mindustry.game.EventType.WorldLoadEvent; import io.anuke.mindustry.io.Map; import io.anuke.mindustry.io.MapIO; import io.anuke.mindustry.io.Maps; import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Tile; import io.anuke.mindustry.world.WorldGenerator; +import io.anuke.ucore.core.Events; import io.anuke.ucore.entities.Entities; import io.anuke.ucore.modules.Module; import io.anuke.ucore.util.Mathf; @@ -28,6 +31,7 @@ public class World extends Module{ private Maps maps = new Maps(); private Array tempTiles = new Array<>(); + private boolean generating; public World(){ maps.load(); @@ -157,6 +161,7 @@ public class World extends Module{ } public void loadMap(Map map, int seed){ + generating = true; this.currentMap = map; this.seed = seed; @@ -167,12 +172,21 @@ public class World extends Module{ Entities.resizeTree(0, 0, width * tilesize, height * tilesize); WorldGenerator.generate(tiles, MapIO.readTileData(map, true)); + generating = false; + + Events.fire(WorldLoadEvent.class); } public int getSeed(){ return seed; } + public void notifyChanged(Tile tile){ + if(!generating){ + Gdx.app.postRunnable(() -> Events.fire(TileChangeEvent.class, tile)); + } + } + public void removeBlock(Tile tile){ if(!tile.block().isMultiblock() && !tile.isLinked()){ tile.setBlock(Blocks.air); diff --git a/core/src/io/anuke/mindustry/entities/effect/Puddle.java b/core/src/io/anuke/mindustry/entities/effect/Puddle.java index 057b543f59..cc1315cad6 100644 --- a/core/src/io/anuke/mindustry/entities/effect/Puddle.java +++ b/core/src/io/anuke/mindustry/entities/effect/Puddle.java @@ -6,6 +6,7 @@ import com.badlogic.gdx.math.Rectangle; import com.badlogic.gdx.utils.IntMap; import com.badlogic.gdx.utils.Pool.Poolable; import com.badlogic.gdx.utils.Pools; +import io.anuke.mindustry.content.Liquids; import io.anuke.mindustry.content.blocks.Blocks; import io.anuke.mindustry.content.fx.BlockFx; import io.anuke.mindustry.content.fx.EnvironmentFx; @@ -60,8 +61,9 @@ public class Puddle extends Entity implements SerializableEntity, Poolable{ } private static void deposit(Tile tile, Tile source, Liquid liquid, float amount, int generation){ - if(tile.floor().liquid){ - reactPuddle(tile.floor().liquidDrop, liquid, amount, tile, tile.worldx(), tile.worldy()); + if(tile.floor().liquid && !canStayOn(liquid, tile.floor().liquidDrop)){ + reactPuddle(tile.floor().liquidDrop, liquid, amount, tile, + (tile.worldx() + source.worldx())/2f, (tile.worldy() + source.worldy())/2f); if(generation == 0 && Timers.get(tile, "ripple", 50)){ Effects.effect(BlockFx.ripple, tile.floor().liquidDrop.color, @@ -90,19 +92,26 @@ public class Puddle extends Entity implements SerializableEntity, Poolable{ } } - private static float reactPuddle(Liquid pliquid, Liquid liquid, float amount, Tile tile, float x, float y){ - if((pliquid.flammability > 0.3f && liquid.temperature > 0.7f) || - (liquid.flammability > 0.3f && pliquid.temperature > 0.7f)){ //flammable liquid + hot liquid + /**Returns whether the first liquid can 'stay' on the second one. + * Currently, the only place where this can happen is oil on water.*/ + private static boolean canStayOn(Liquid liquid, Liquid other){ + return liquid == Liquids.oil && other == Liquids.water; + } + + /**Reacts two liquids together at a location.*/ + private static float reactPuddle(Liquid dest, Liquid liquid, float amount, Tile tile, float x, float y){ + if((dest.flammability > 0.3f && liquid.temperature > 0.7f) || + (liquid.flammability > 0.3f && dest.temperature > 0.7f)){ //flammable liquid + hot liquid Fire.create(tile); if(Mathf.chance(0.006 * amount)){ - new Fireball(x, y, pliquid.flameColor, Mathf.random(360f)).add(); + new Fireball(x, y, dest.flameColor, Mathf.random(360f)).add(); } - }else if(pliquid.temperature > 0.7f && liquid.temperature < 0.55f){ //cold liquid poured onto hot puddle + }else if(dest.temperature > 0.7f && liquid.temperature < 0.55f){ //cold liquid poured onto hot puddle if(Mathf.chance(0.5f * amount)){ Effects.effect(EnvironmentFx.steam, x, y); } return - 0.1f * amount; - }else if(liquid.temperature > 0.7f && pliquid.temperature < 0.55f){ //hot liquid poured onto cold puddle + }else if(liquid.temperature > 0.7f && dest.temperature < 0.55f){ //hot liquid poured onto cold puddle if(Mathf.chance(0.8f * amount)){ Effects.effect(EnvironmentFx.steam, x, y); } diff --git a/core/src/io/anuke/mindustry/game/EventType.java b/core/src/io/anuke/mindustry/game/EventType.java index 7ae7b972d4..2459ec47bb 100644 --- a/core/src/io/anuke/mindustry/game/EventType.java +++ b/core/src/io/anuke/mindustry/game/EventType.java @@ -1,13 +1,7 @@ package io.anuke.mindustry.game; import io.anuke.mindustry.core.GameState.State; -import io.anuke.mindustry.entities.BulletType; -import io.anuke.mindustry.entities.TileEntity; -import io.anuke.mindustry.entities.units.BaseUnit; -import io.anuke.mindustry.resource.Weapon; -import io.anuke.mindustry.world.Block; import io.anuke.mindustry.world.Tile; -import io.anuke.ucore.entities.Entity; import io.anuke.ucore.function.Event; public class EventType { @@ -28,63 +22,15 @@ public class EventType { void handle(); } - public interface StateChangeEvent extends Event{ - void handle(State from, State to); - } - - public interface FriendlyFireChange extends Event{ - void handle(boolean on); - } - - public interface BulletEvent extends Event{ - void handle(BulletType type, Entity owner, float x, float y, float angle, short damage); - } - - public interface EnemyDeathEvent extends Event{ - void handle(BaseUnit enemy); - } - - public interface BlockDestroyEvent extends Event{ - void handle(TileEntity entity); - } - - public interface BlockDamageEvent extends Event{ - void handle(TileEntity entity); - } - - public interface PlayerDeathEvent extends Event{ + public interface WorldLoadEvent extends Event{ void handle(); } - public interface BlockConfigEvent extends Event{ - void handle(Tile tile, byte data); - } - - public interface BlockTapEvent extends Event{ + public interface TileChangeEvent extends Event{ void handle(Tile tile); } - public interface WeaponSwitchEvent extends Event{ - void handle(); - } - - public interface UpgradeEvent extends Event{ - void handle(Weapon weapon); - } - - public interface MessageSendEvent extends Event{ - void handle(String message); - } - - public interface ShootEvent extends Event{ - void handle(Weapon weapon, float x, float y, float angle); - } - - public interface PlaceEvent extends Event{ - void handle(int x, int y, Block block, int rotation); - } - - public interface BreakEvent extends Event{ - void handle(int x, int y); + public interface StateChangeEvent extends Event{ + void handle(State from, State to); } } diff --git a/core/src/io/anuke/mindustry/game/Team.java b/core/src/io/anuke/mindustry/game/Team.java index 1a4bad572a..08dcc2a6ec 100644 --- a/core/src/io/anuke/mindustry/game/Team.java +++ b/core/src/io/anuke/mindustry/game/Team.java @@ -9,8 +9,10 @@ public enum Team { green(Color.valueOf("1dc645")); public final Color color; + public final int intColor; Team(Color color){ this.color = color; + intColor = Color.rgba8888(color); } } diff --git a/core/src/io/anuke/mindustry/graphics/MinimapRenderer.java b/core/src/io/anuke/mindustry/graphics/MinimapRenderer.java index 01dd13a519..e2f4a1075c 100644 --- a/core/src/io/anuke/mindustry/graphics/MinimapRenderer.java +++ b/core/src/io/anuke/mindustry/graphics/MinimapRenderer.java @@ -1,29 +1,119 @@ package io.anuke.mindustry.graphics; import com.badlogic.gdx.graphics.Pixmap; +import com.badlogic.gdx.graphics.Pixmap.Format; import com.badlogic.gdx.graphics.Texture; +import com.badlogic.gdx.graphics.g2d.TextureRegion; +import com.badlogic.gdx.math.Rectangle; import com.sun.media.jfxmediaimpl.MediaDisposer.Disposable; +import io.anuke.mindustry.entities.Units; +import io.anuke.mindustry.game.EventType.TileChangeEvent; +import io.anuke.mindustry.game.EventType.WorldLoadEvent; +import io.anuke.mindustry.world.ColorMapper; import io.anuke.mindustry.world.Tile; +import io.anuke.ucore.core.Core; +import io.anuke.ucore.core.Events; +import io.anuke.ucore.graphics.Draw; +import io.anuke.ucore.graphics.Pixmaps; +import io.anuke.ucore.util.Mathf; + +import static io.anuke.mindustry.Vars.*; public class MinimapRenderer implements Disposable{ + private static final int baseSize = 16; private Pixmap pixmap; private Texture texture; + private TextureRegion region; + private Rectangle rect = new Rectangle(); + private int zoom = 4; + + public MinimapRenderer(){ + Events.on(WorldLoadEvent.class, () -> { + reset(); + updateAll(); + }); + + Events.on(TileChangeEvent.class, this::update); + } public Texture getTexture(){ return texture; } - public void reset(){ - + public void zoomBy(int amount){ + zoom += amount; + zoom = Mathf.clamp(zoom, 1, Math.min(world.width(), world.height())/baseSize/2); } - public void updated(Tile tile){ + public void reset(){ + if(pixmap != null){ + pixmap.dispose(); + texture.dispose(); + } + pixmap = new Pixmap(world.width(), world.height(), Format.RGBA8888); + texture = new Texture(pixmap); + region = new TextureRegion(texture); + } + public void drawEntities(float x, float y, float w, float h){ + int sz = baseSize * zoom; + float dx = (Core.camera.position.x / tilesize); + float dy = (Core.camera.position.y / tilesize); + dx = Mathf.clamp(dx, sz, world.width()-sz); + dy = Mathf.clamp(dy, sz, world.height()-sz); + + rect.set((dx - sz) * tilesize, (dy - sz) * tilesize, sz * 2 * tilesize, sz * 2 * tilesize); + Units.getNearby(rect, unit -> { + if(!rect.contains(unit.x, unit.y)) return; + + float rx = (unit.x - rect.x) / rect.width * w, ry = (unit.y - rect.y)/ rect.width * h; + Draw.color(unit.team.color); + Draw.rect("white", x + rx, y + ry, w/(sz*2), h/(sz*2)); + }); + Draw.color(); + } + + public TextureRegion getRegion() { + int sz = Mathf.clamp(baseSize * zoom, baseSize, Math.min(world.width(), world.height())); + float dx = (Core.camera.position.x / tilesize); + float dy = (Core.camera.position.y / tilesize); + dx = Mathf.clamp(dx, sz, world.width()-sz); + dy = Mathf.clamp(dy, sz, world.height()-sz); + float invTexWidth = 1f / texture.getWidth(); + float invTexHeight = 1f / texture.getHeight(); + float x = dx - sz, y = world.height()-dy - sz, width = sz*2, height = sz*2; + region.setRegion(x * invTexWidth, y * invTexHeight, (x + width) * invTexWidth, (y + height) * invTexHeight); + return region; + } + + public void updateAll(){ + for(int x = 0; x < world.width(); x ++){ + for(int y = 0; y < world.height(); y ++){ + pixmap.drawPixel(x, pixmap.getHeight() - 1 - y, colorFor(world.tile(x, y))); + } + } + texture.draw(pixmap, 0, 0); + } + + public void update(Tile tile){ + int color = colorFor(world.tile(tile.x, tile.y)); + pixmap.drawPixel(tile.x, pixmap.getHeight() - 1 - tile.y, color); + + texture.bind(); + Pixmaps.drawPixel(texture, tile.x, pixmap.getHeight() - 1 - tile.y, color); + } + + private int colorFor(Tile tile){ + int color = tile.breakable() ? tile.target().getTeam().intColor : ColorMapper.getColor(tile.block()); + if(color == 0) color = ColorMapper.getColor(tile.floor()); + return color; } @Override public void dispose() { pixmap.dispose(); texture.dispose(); + texture = null; + pixmap = null; } } diff --git a/core/src/io/anuke/mindustry/input/DefaultKeybinds.java b/core/src/io/anuke/mindustry/input/DefaultKeybinds.java index 4d5402a1ab..b9e89ffd95 100644 --- a/core/src/io/anuke/mindustry/input/DefaultKeybinds.java +++ b/core/src/io/anuke/mindustry/input/DefaultKeybinds.java @@ -18,6 +18,7 @@ public class DefaultKeybinds { "shoot", Input.MOUSE_LEFT, "zoom_hold", Input.CONTROL_LEFT, "zoom", new Axis(Input.SCROLL), + "zoom_minimap", new Axis(Input.MINUS, Input.PLUS), "menu", Gdx.app.getType() == ApplicationType.Android ? Input.BACK : Input.ESCAPE, "pause", Input.SPACE, "dash", Input.SHIFT_LEFT, diff --git a/core/src/io/anuke/mindustry/input/DesktopInput.java b/core/src/io/anuke/mindustry/input/DesktopInput.java index 43283759ec..9973d80f03 100644 --- a/core/src/io/anuke/mindustry/input/DesktopInput.java +++ b/core/src/io/anuke/mindustry/input/DesktopInput.java @@ -81,6 +81,8 @@ public class DesktopInput extends InputHandler{ zoomed = false; } + renderer.minimap().zoomBy(-(int)Inputs.getAxisTapped("zoom_minimap")); + if(!rotated) { rotation += Inputs.getAxis("rotate_alt"); rotated = true; diff --git a/core/src/io/anuke/mindustry/ui/fragments/DebugFragment.java b/core/src/io/anuke/mindustry/ui/fragments/DebugFragment.java index 1b55ce1e73..6426a3e4c6 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/DebugFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/DebugFragment.java @@ -44,7 +44,7 @@ public class DebugFragment implements Fragment { new table(){{ visible(() -> debug); - atop().aright(); + abottom().aleft(); new table("pane"){{ defaults().fillX(); diff --git a/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java b/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java index 004b34b3ae..9e8240ea1a 100644 --- a/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java +++ b/core/src/io/anuke/mindustry/ui/fragments/HudFragment.java @@ -2,16 +2,21 @@ package io.anuke.mindustry.ui.fragments; import com.badlogic.gdx.Gdx; import com.badlogic.gdx.graphics.Color; +import com.badlogic.gdx.graphics.g2d.Batch; +import com.badlogic.gdx.graphics.g2d.TextureRegion; import com.badlogic.gdx.math.Interpolation; import io.anuke.mindustry.core.GameState.State; import io.anuke.mindustry.net.Net; import io.anuke.ucore.core.Core; import io.anuke.ucore.core.Settings; +import io.anuke.ucore.graphics.Draw; import io.anuke.ucore.scene.actions.Actions; import io.anuke.ucore.scene.builders.imagebutton; import io.anuke.ucore.scene.builders.label; import io.anuke.ucore.scene.builders.table; import io.anuke.ucore.scene.event.Touchable; +import io.anuke.ucore.scene.style.TextureRegionDrawable; +import io.anuke.ucore.scene.ui.Image; import io.anuke.ucore.scene.ui.ImageButton; import io.anuke.ucore.scene.ui.Label; import io.anuke.ucore.scene.ui.layout.Table; @@ -131,6 +136,36 @@ public class HudFragment implements Fragment{ visible(() -> control.tutorial().active()); }}.end(); + new table(){{ + visible(() -> state.is(State.playing)); + atop(); + aright(); + + new table("button"){{ + margin(5); + marginBottom(10); + TextureRegionDrawable draw = new TextureRegionDrawable(new TextureRegion()); + Image image = new Image(){ + @Override + public void draw(Batch batch, float parentAlpha) { + super.draw(batch, parentAlpha); + if(renderer.minimap().getTexture() != null){ + renderer.minimap().drawEntities(x, y, width, height); + } + } + }; + image.setDrawable(draw); + image.update(() -> { + if (renderer.minimap().getTexture() == null) { + draw.getRegion().setRegion(Draw.region("white")); + } else { + draw.getRegion().setRegion(renderer.minimap().getRegion()); + } + }); + add(image).size(140f, 140f); + }}.end(); + }}.end(); + //paused table new table(){{ visible(() -> state.is(State.paused) && !Net.active()); diff --git a/core/src/io/anuke/mindustry/world/Tile.java b/core/src/io/anuke/mindustry/world/Tile.java index 54cac96093..eb1e25dfaf 100644 --- a/core/src/io/anuke/mindustry/world/Tile.java +++ b/core/src/io/anuke/mindustry/world/Tile.java @@ -325,6 +325,8 @@ public class Tile{ updateOcclusion(); } + + world.notifyChanged(this); } @Override