From 99b01f3a3c0a10f1e3bbd7d4538e73a5570aa7b8 Mon Sep 17 00:00:00 2001 From: Anuken Date: Sat, 19 Feb 2022 20:34:55 -0500 Subject: [PATCH] Fog building hiding --- .../mindustry/entities/comp/BuildingComp.java | 19 +++++++++ core/src/mindustry/game/FogControl.java | 3 +- core/src/mindustry/game/Rules.java | 4 ++ .../src/mindustry/graphics/BlockRenderer.java | 41 +++++++++++++++++-- core/src/mindustry/graphics/EnvRenderers.java | 3 +- core/src/mindustry/graphics/FogRenderer.java | 14 +++---- .../mindustry/graphics/MinimapRenderer.java | 5 ++- core/src/mindustry/type/UnitType.java | 2 +- core/src/mindustry/world/Block.java | 3 ++ .../world/blocks/defense/BaseShield.java | 7 ++++ .../world/blocks/defense/ForceProjector.java | 6 +++ 11 files changed, 90 insertions(+), 17 deletions(-) diff --git a/core/src/mindustry/entities/comp/BuildingComp.java b/core/src/mindustry/entities/comp/BuildingComp.java index aa8246242a..acf0cb00f3 100644 --- a/core/src/mindustry/entities/comp/BuildingComp.java +++ b/core/src/mindustry/entities/comp/BuildingComp.java @@ -70,6 +70,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, transient float enabledControlTime; transient String lastAccessed; transient boolean wasDamaged; //used only by the indexer + transient boolean wasVisible; //used only by the block renderer when fog is on transient float visualLiquid; @Nullable PowerModule power; @@ -1775,6 +1776,24 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, } } + @Replace + @Override + public boolean inFogTo(Team viewer){ + if(team == viewer || !state.rules.fog) return false; + + int size = block.size, of = block.sizeOffset, tx = tile.x, ty = tile.y; + + for(int x = 0; x < size; x++){ + for(int y = 0; y < size; y++){ + if(fogControl.isVisibleTile(viewer, tx + x + of, ty + y + of)){ + return false; + } + } + } + + return true; + } + @Override public void remove(){ if(sound != null){ diff --git a/core/src/mindustry/game/FogControl.java b/core/src/mindustry/game/FogControl.java index 597cb83715..b595a1a909 100644 --- a/core/src/mindustry/game/FogControl.java +++ b/core/src/mindustry/game/FogControl.java @@ -320,7 +320,8 @@ public class FogControl implements CustomChunk{ data.write.clear(); } - circle(data.write, x, y, rad); + //radius is always +1 to keep up with visuals + circle(data.write, x, y, rad + 1); } } dynamicEvents.clear(); diff --git a/core/src/mindustry/game/Rules.java b/core/src/mindustry/game/Rules.java index d0a3ccc095..2e94170f65 100644 --- a/core/src/mindustry/game/Rules.java +++ b/core/src/mindustry/game/Rules.java @@ -115,6 +115,10 @@ public class Rules{ public ObjectSet hiddenBuildItems = new ObjectSet<>(); /** HIGHLY UNSTABLE/EXPERIMENTAL. DO NOT USE THIS. */ public boolean fog = false; + /** Color for static, undiscovered fog of war areas. */ + public Color staticColor = new Color(0f, 0f, 0f, 1f); + /** Color for discovered but un-monitored fog of war areas. */ + public Color dynamicColor = new Color(0f, 0f, 0f, 0.5f); /** Whether ambient lighting is enabled. */ public boolean lighting = false; /** Whether enemy lighting is visible. diff --git a/core/src/mindustry/graphics/BlockRenderer.java b/core/src/mindustry/graphics/BlockRenderer.java index 78417abadf..2ba35fd37d 100644 --- a/core/src/mindustry/graphics/BlockRenderer.java +++ b/core/src/mindustry/graphics/BlockRenderer.java @@ -9,8 +9,10 @@ import arc.math.*; import arc.math.geom.*; import arc.struct.*; import arc.util.*; +import mindustry.*; import mindustry.content.*; import mindustry.game.EventType.*; +import mindustry.game.*; import mindustry.game.Teams.*; import mindustry.gen.*; import mindustry.world.*; @@ -81,7 +83,11 @@ public class BlockRenderer{ updateFloors.add(new UpdateRenderState(tile, tile.floor())); } - if(tile.block().hasShadow){ + if(tile.build != null && (tile.team() == player.team() || !state.rules.fog)){ + tile.build.wasVisible = true; + } + + if(tile.block().hasShadow && (tile.build == null || tile.build.wasVisible)){ Fill.rect(tile.x + 0.5f, tile.y + 0.5f, 1, 1); } } @@ -99,7 +105,14 @@ public class BlockRenderer{ }); Events.on(TileChangeEvent.class, event -> { - shadowEvents.add(event.tile); + boolean visible = event.tile.build == null || event.tile.build.inFogTo(Vars.player.team()); + if(event.tile.build != null){ + event.tile.build.wasVisible = visible; + } + + if(visible){ + shadowEvents.add(event.tile); + } int avgx = (int)(camera.position.x / tilesize); int avgy = (int)(camera.position.y / tilesize); @@ -265,7 +278,7 @@ public class BlockRenderer{ for(Tile tile : shadowEvents){ //draw white/shadow color depending on blend - Draw.color(!tile.block().hasShadow ? Color.white : blendShadowColor); + Draw.color((!tile.block().hasShadow || (state.rules.fog && tile.build != null && !tile.build.wasVisible)) ? Color.white : blendShadowColor); Fill.rect(tile.x + 0.5f, tile.y + 0.5f, 1, 1); } @@ -371,6 +384,7 @@ public class BlockRenderer{ } public void drawBlocks(){ + Team pteam = player.team(); drawDestroyed(); @@ -382,7 +396,9 @@ public class BlockRenderer{ Draw.z(Layer.block); - if(block != Blocks.air){ + boolean visible = (build == null || !build.inFogTo(pteam)/* || build.wasVisible*/); + + if(block != Blocks.air && visible){ block.drawBase(tile); Draw.reset(); Draw.z(Layer.block); @@ -394,6 +410,8 @@ public class BlockRenderer{ } if(build != null){ + if(!build.wasVisible) updateShadow(build); + build.wasVisible = true; if(build.damaged()){ Draw.z(Layer.blockCracks); @@ -411,6 +429,11 @@ public class BlockRenderer{ } } Draw.reset(); + }else if(!visible){ + //TODO here is the question: should buildings you lost sight of remain rendered? if so, how should this information be stored? + //comment lines below for buggy persistence + if(build.wasVisible) updateShadow(build); + build.wasVisible = false; } } @@ -443,6 +466,16 @@ public class BlockRenderer{ } } + void updateShadow(Building build){ + int size = build.block.size, of = build.block.sizeOffset, tx = build.tile.x, ty = build.tile.y; + + for(int x = 0; x < size; x++){ + for(int y = 0; y < size; y++){ + shadowEvents.add(world.tile(x + tx + of, y + ty + of)); + } + } + } + static class BlockQuadtree extends QuadTree{ public BlockQuadtree(Rect bounds){ diff --git a/core/src/mindustry/graphics/EnvRenderers.java b/core/src/mindustry/graphics/EnvRenderers.java index 5d261f7a10..cce4d3908e 100644 --- a/core/src/mindustry/graphics/EnvRenderers.java +++ b/core/src/mindustry/graphics/EnvRenderers.java @@ -97,7 +97,8 @@ public class EnvRenderers{ tex.setWrap(TextureWrap.repeat); } - Draw.z(Layer.weather - 1); + //TODO layer looks better? should not be conditional + Draw.z(state.rules.fog ? Layer.fogOfWar + 1 : Layer.weather - 1); Weather.drawNoiseLayers(tex, Color.scarlet, 1000f, 0.23f, 0.4f, 1f, 1f, 0f, 4, -1.3f, 0.7f, 0.8f, 0.9f); Draw.reset(); diff --git a/core/src/mindustry/graphics/FogRenderer.java b/core/src/mindustry/graphics/FogRenderer.java index b63878dadd..352e71e1ac 100644 --- a/core/src/mindustry/graphics/FogRenderer.java +++ b/core/src/mindustry/graphics/FogRenderer.java @@ -18,9 +18,6 @@ import static mindustry.Vars.*; /** Highly experimental fog-of-war renderer. */ public class FogRenderer{ - public static final Color - staticColor = new Color(0f, 0f, 0f, 1f), - dynamicColor = new Color(0f, 0f, 0f, 0.5f); private FrameBuffer staticFog = new FrameBuffer(), dynamicFog = new FrameBuffer(); private LongSeq events = new LongSeq(); private Rect rect = new Rect(); @@ -114,17 +111,18 @@ public class FogRenderer{ dynamicFog.getTexture().setFilter(TextureFilter.linear); Draw.shader(Shaders.fog); - Draw.color(dynamicColor); + Draw.color(state.rules.dynamicColor); Draw.fbo(dynamicFog.getTexture(), world.width(), world.height(), tilesize); - Draw.color(staticColor); + Draw.color(state.rules.staticColor); Draw.fbo(staticFog.getTexture(), world.width(), world.height(), tilesize); Draw.shader(); } void poly(Rect check, float x, float y, float rad){ - if(check.overlaps(x - rad, y - rad, rad * 2f, rad * 2f)){ - Fill.poly(x, y, 20, rad); - } + //todo clipping messes up the minimap + //if(check.overlaps(x - rad, y - rad, rad * 2f, rad * 2f)){ + Fill.poly(x, y, 20, rad); + //} } void renderEvent(long e){ diff --git a/core/src/mindustry/graphics/MinimapRenderer.java b/core/src/mindustry/graphics/MinimapRenderer.java index c7a0b53e67..1724fb5ec3 100644 --- a/core/src/mindustry/graphics/MinimapRenderer.java +++ b/core/src/mindustry/graphics/MinimapRenderer.java @@ -155,11 +155,12 @@ public class MinimapRenderer{ Tmp.tr1.set(dynamicTex); Tmp.tr1.set(region.u, 1f - region.v, region.u2, 1f - region.v2); - Draw.color(FogRenderer.dynamicColor); + Draw.color(state.rules.dynamicColor); Draw.rect(Tmp.tr1, x + w/2f, y + h/2f, w, h); Tmp.tr1.texture = staticTex; - Draw.color(FogRenderer.staticColor); + //must be black to fit with borders + Draw.color(0f, 0f, 0f, state.rules.staticColor.a); Draw.rect(Tmp.tr1, x + w/2f, y + h/2f, w, h); Draw.color(); diff --git a/core/src/mindustry/type/UnitType.java b/core/src/mindustry/type/UnitType.java index fcb2e93820..d325ba714d 100644 --- a/core/src/mindustry/type/UnitType.java +++ b/core/src/mindustry/type/UnitType.java @@ -466,7 +466,7 @@ public class UnitType extends UnlockableContent{ } if(fogRadius < 0){ - fogRadius = Math.max(lightRadius * 2.5f, 1f) / 8f; + fogRadius = Math.max(lightRadius * 3.1f, 1f) / 8f; } if(weapons.isEmpty()){ diff --git a/core/src/mindustry/world/Block.java b/core/src/mindustry/world/Block.java index 95a6198cd4..a89752e0de 100644 --- a/core/src/mindustry/world/Block.java +++ b/core/src/mindustry/world/Block.java @@ -150,6 +150,8 @@ public class Block extends UnlockableContent implements Senseable{ public int size = 1; /** multiblock offset */ public float offset = 0f; + /** offset for iteration (internal use only) */ + public int sizeOffset = 0; /** Clipping size of this block. Should be as large as the block will draw. */ public float clipSize = -1f; /** When placeRangeCheck is enabled, this is the range checked for enemy blocks. */ @@ -1076,6 +1078,7 @@ public class Block extends UnlockableContent implements Senseable{ } offset = ((size + 1) % 2) * tilesize / 2f; + sizeOffset = -((size - 1) / 2); if(requirements.length > 0){ buildCost = 0f; diff --git a/core/src/mindustry/world/blocks/defense/BaseShield.java b/core/src/mindustry/world/blocks/defense/BaseShield.java index 455452d9fb..ccfda538fe 100644 --- a/core/src/mindustry/world/blocks/defense/BaseShield.java +++ b/core/src/mindustry/world/blocks/defense/BaseShield.java @@ -7,6 +7,7 @@ import arc.math.*; import arc.util.*; import mindustry.content.*; import mindustry.entities.*; +import mindustry.game.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.world.*; @@ -110,6 +111,12 @@ public class BaseShield extends Block{ drawShield(); } + //always visible due to their shield nature + @Override + public boolean inFogTo(Team viewer){ + return false; + } + public void drawShield(){ if(!broken){ float radius = radius(); diff --git a/core/src/mindustry/world/blocks/defense/ForceProjector.java b/core/src/mindustry/world/blocks/defense/ForceProjector.java index 137d43a6df..5dfb806130 100644 --- a/core/src/mindustry/world/blocks/defense/ForceProjector.java +++ b/core/src/mindustry/world/blocks/defense/ForceProjector.java @@ -10,6 +10,7 @@ import arc.util.io.*; import mindustry.annotations.Annotations.*; import mindustry.content.*; import mindustry.entities.*; +import mindustry.game.*; import mindustry.gen.*; import mindustry.graphics.*; import mindustry.logic.*; @@ -140,6 +141,11 @@ public class ForceProjector extends Block{ radscl = warmup = 0f; } + @Override + public boolean inFogTo(Team viewer){ + return false; + } + @Override public void updateTile(){ boolean phaseValid = itemConsumer != null && itemConsumer.valid(this);