From 9f8fce72d3e972ce2edd72914c0d97959992754c Mon Sep 17 00:00:00 2001 From: Anuken Date: Fri, 25 Dec 2020 21:49:10 -0500 Subject: [PATCH] Better build beam visuals --- core/assets/shaders/blockbuild.frag | 7 +- core/assets/shaders/buildbeam.frag | 25 +++++++ core/src/mindustry/content/UnitTypes.java | 2 + core/src/mindustry/core/Renderer.java | 13 +++- .../mindustry/entities/comp/BuilderComp.java | 72 ++++++++++++++----- .../mindustry/entities/comp/BuildingComp.java | 5 +- .../src/mindustry/entities/comp/UnitComp.java | 3 + core/src/mindustry/graphics/Layer.java | 3 + core/src/mindustry/graphics/Shaders.java | 22 +++++- core/src/mindustry/type/UnitType.java | 1 + .../ui/dialogs/CustomRulesDialog.java | 2 +- .../world/blocks/ConstructBlock.java | 26 +++++-- .../blocks/distribution/StackConveyor.java | 2 +- 13 files changed, 147 insertions(+), 36 deletions(-) create mode 100644 core/assets/shaders/buildbeam.frag diff --git a/core/assets/shaders/blockbuild.frag b/core/assets/shaders/blockbuild.frag index 0c8f301350..fe877e873b 100644 --- a/core/assets/shaders/blockbuild.frag +++ b/core/assets/shaders/blockbuild.frag @@ -1,6 +1,5 @@ uniform sampler2D u_texture; -uniform vec4 u_color; uniform vec2 u_texsize; uniform vec2 u_uv; uniform vec2 u_uv2; @@ -38,11 +37,11 @@ void main(){ float dst = (abs(center.x - coords.x) + abs(center.y - coords.y))/2.0; if((mod(u_time / 1.5 + value, 20.0) < 15.0 && cont(t, v))){ - gl_FragColor = u_color; + gl_FragColor = v_color; }else if(dst > (1.0-u_progress) * (center.x)){ gl_FragColor = color; - }else if((dst + 1.0 > (1.0-u_progress) * (center.x)) && color.a > 0.1){ - gl_FragColor = u_color; + }else if((dst + 1.0 > (1.0-u_progress) * (center.x)) && color.a > 0.1){ + gl_FragColor = v_color; }else{ gl_FragColor = vec4(0.0); } diff --git a/core/assets/shaders/buildbeam.frag b/core/assets/shaders/buildbeam.frag new file mode 100644 index 0000000000..a9a0659894 --- /dev/null +++ b/core/assets/shaders/buildbeam.frag @@ -0,0 +1,25 @@ +#define HIGHP + +uniform sampler2D u_texture; +uniform vec2 u_texsize; +uniform vec2 u_invsize; +uniform float u_time; +uniform float u_dp; +uniform vec2 u_offset; + +varying vec2 v_texCoords; + +float triwave(float y){ + return abs(2.*fract(y)-1.); +} + +void main(){ + vec2 T = v_texCoords.xy; + vec2 coords = (T * u_texsize) + u_offset; + + vec4 color = texture2D(u_texture, T); + + color.a *= (0.37 + abs(sin(u_time / 15.0)) * .05 + 0.2 * (step(mod(coords.x / u_dp + coords.y / u_dp + u_time / 4.0, 10.0), 3.0))); + + gl_FragColor = color; +} diff --git a/core/src/mindustry/content/UnitTypes.java b/core/src/mindustry/content/UnitTypes.java index 9bfd066e5a..99895be719 100644 --- a/core/src/mindustry/content/UnitTypes.java +++ b/core/src/mindustry/content/UnitTypes.java @@ -1317,6 +1317,7 @@ public class UnitTypes implements ContentList{ hitSize = 32f; payloadCapacity = (3 * 3) * tilePayload; buildSpeed = 2.5f; + buildBeamOffset = 23; range = 140f; targetAir = false; targetFlag = BlockFlag.battery; @@ -1388,6 +1389,7 @@ public class UnitTypes implements ContentList{ drawShields = false; commandLimit = 6; lowAltitude = true; + buildBeamOffset = 43; ammoCapacity = 1300; ammoResupplyAmount = 20; diff --git a/core/src/mindustry/core/Renderer.java b/core/src/mindustry/core/Renderer.java index 4b05e83a68..255e21695a 100644 --- a/core/src/mindustry/core/Renderer.java +++ b/core/src/mindustry/core/Renderer.java @@ -30,6 +30,7 @@ public class Renderer implements ApplicationListener{ public @Nullable Bloom bloom; public FrameBuffer effectBuffer = new FrameBuffer(); public float laserOpacity = 1f; + public boolean animateShields; /** minZoom = zooming out, maxZoom = zooming in */ public float minZoom = 1.5f, maxZoom = 6f; @@ -69,7 +70,8 @@ public class Renderer implements ApplicationListener{ float dest = Mathf.round(targetscale, 0.5f); camerascale = Mathf.lerpDelta(camerascale, dest, 0.1f); if(Mathf.equal(camerascale, dest, 0.001f)) camerascale = dest; - laserOpacity = Core.settings.getInt("lasersopacity") / 100f; + laserOpacity = settings.getInt("lasersopacity") / 100f; + animateShields = settings.getBool("animatedshields"); if(landTime > 0){ landTime -= Time.delta; @@ -204,7 +206,7 @@ public class Renderer implements ApplicationListener{ graphics.clear(clearColor); Draw.reset(); - if(Core.settings.getBool("animatedwater") || Core.settings.getBool("animatedshields")){ + if(Core.settings.getBool("animatedwater") || animateShields){ effectBuffer.resize(graphics.getWidth(), graphics.getHeight()); } @@ -248,11 +250,16 @@ public class Renderer implements ApplicationListener{ Draw.draw(Layer.plans, overlays::drawBottom); - if(settings.getBool("animatedshields") && Shaders.shield != null){ + if(animateShields && Shaders.shield != null){ Draw.drawRange(Layer.shields, 1f, () -> effectBuffer.begin(Color.clear), () -> { effectBuffer.end(); effectBuffer.blit(Shaders.shield); }); + + Draw.drawRange(Layer.buildBeam, 1f, () -> effectBuffer.begin(Color.clear), () -> { + effectBuffer.end(); + effectBuffer.blit(Shaders.buildBeam); + }); } Draw.draw(Layer.overlayUI, overlays::drawTop); diff --git a/core/src/mindustry/entities/comp/BuilderComp.java b/core/src/mindustry/entities/comp/BuilderComp.java index b069772ee9..e724aa29ab 100644 --- a/core/src/mindustry/entities/comp/BuilderComp.java +++ b/core/src/mindustry/entities/comp/BuilderComp.java @@ -35,12 +35,25 @@ abstract class BuilderComp implements Posc, Teamc, Rotc{ @SyncLocal Queue plans = new Queue<>(1); @SyncLocal boolean updateBuilding = true; + private transient BuildPlan lastActive; + private transient int lastSize; + private transient float buildAlpha = 0f; + public boolean canBuild(){ return type.buildSpeed > 0; } @Override public void update(){ + if(!headless){ + //visual activity update + if(lastActive != null && buildAlpha <= 0.01f){ + lastActive = null; + } + + buildAlpha = Mathf.lerpDelta(buildAlpha, activelyBuilding() ? 1f : 0f, 0.15f); + } + if(!updateBuilding || !canBuild()) return; float finalPlaceDst = state.rules.infiniteResources ? Float.MAX_VALUE : buildingRange; @@ -56,9 +69,12 @@ abstract class BuilderComp implements Posc, Teamc, Rotc{ } Building core = core(); + BuildPlan current = buildPlan(); //nothing to build. - if(buildPlan() == null) return; + if(current == null) return; + + Tile tile = current.tile(); //find the next build request if(plans.size > 1){ @@ -71,11 +87,11 @@ abstract class BuilderComp implements Posc, Teamc, Rotc{ } } - BuildPlan current = buildPlan(); + lastActive = current; + buildAlpha = 1f; + if(current.breaking) lastSize = tile.block().size; - if(!within(current.tile(), finalPlaceDst)) return; - - Tile tile = world.tile(current.x, current.y); + if(!within(tile, finalPlaceDst)) return; if(!(tile.build instanceof ConstructBuild cb)){ if(!current.initialized && !current.breaking && Build.validPlace(current.block, team, current.x, current.y, current.rotation)){ @@ -204,7 +220,7 @@ abstract class BuilderComp implements Posc, Teamc, Rotc{ boolean activelyBuilding(){ //not actively building when not near the build plan if(isBuilding()){ - if(!within(buildPlan(), state.rules.infiniteResources ? Float.MAX_VALUE : buildingRange)){ + if(!state.isEditor() && !within(buildPlan(), state.rules.infiniteResources ? Float.MAX_VALUE : buildingRange)){ return false; } } @@ -218,30 +234,31 @@ abstract class BuilderComp implements Posc, Teamc, Rotc{ } public void draw(){ - if(!activelyBuilding()) return; + boolean active = activelyBuilding(); + if(!active && lastActive == null) return; Draw.z(Layer.flyingUnit); - BuildPlan plan = buildPlan(); + BuildPlan plan = active ? buildPlan() : lastActive; Tile tile = world.tile(plan.x, plan.y); var core = team.core(); - if(tile == null || (!state.rules.infiniteResources && !within(tile, buildingRange) && !state.isEditor())){ + if(tile == null || !within(plan, state.rules.infiniteResources ? Float.MAX_VALUE : buildingRange)){ return; } //draw remote plans. - if(core != null && !isLocal() && !(tile.block() instanceof ConstructBlock)){ + if(core != null && active && !isLocal() && !(tile.block() instanceof ConstructBlock)){ Draw.z(Layer.plans - 1f); drawPlan(plan, 0.5f); Draw.z(Layer.flyingUnit); } - int size = plan.breaking ? tile.block().size : plan.block.size; + int size = plan.breaking ? active ? tile.block().size : lastSize : plan.block.size; float tx = plan.drawx(), ty = plan.drawy(); - Lines.stroke(1f, Pal.accent); - float focusLen = 3.8f + Mathf.absin(Time.time, 1.1f, 0.6f); + Lines.stroke(1f, plan.breaking ? Pal.remove : Pal.accent); + float focusLen = type.buildBeamOffset + Mathf.absin(Time.time, 3f, 0.6f); float px = x + Angles.trnsx(rotation, focusLen); float py = y + Angles.trnsy(rotation, focusLen); @@ -255,16 +272,35 @@ abstract class BuilderComp implements Posc, Teamc, Rotc{ Arrays.sort(vecs, Structs.comparingFloat(vec -> -Angles.angleDist(angleTo(vec), ang))); + Vec2 close = Geometry.findClosest(x, y, vecs); + float x1 = vecs[0].x, y1 = vecs[0].y, + x2 = close.x, y2 = close.y, x3 = vecs[1].x, y3 = vecs[1].y; - Draw.alpha(1f); + Draw.z(Layer.buildBeam); - Lines.line(px, py, x1, y1); - Lines.line(px, py, x3, y3); + Draw.alpha(buildAlpha); - Fill.circle(px, py, 1.6f + Mathf.absin(Time.time, 0.8f, 1.5f)); + if(!active && !(tile.build instanceof ConstructBuild)){ + Fill.square(plan.drawx(), plan.drawy(), size * tilesize/2f); + } - Draw.color(); + if(renderer.animateShields){ + if(close != vecs[0] && close != vecs[1]){ + Fill.tri(px, py, x1, y1, x2, y2); + Fill.tri(px, py, x3, y3, x2, y2); + }else{ + Fill.tri(px, py, x1, y1, x3, y3); + } + }else{ + Lines.line(px, py, x1, y1); + Lines.line(px, py, x3, y3); + } + + Fill.square(px, py, 1.8f + Mathf.absin(Time.time, 2.2f, 1.1f), rotation + 45); + + Draw.reset(); + Draw.z(Layer.flyingUnit); } } diff --git a/core/src/mindustry/entities/comp/BuildingComp.java b/core/src/mindustry/entities/comp/BuildingComp.java index 9c4ca480f5..6dd6c6e1e4 100644 --- a/core/src/mindustry/entities/comp/BuildingComp.java +++ b/core/src/mindustry/entities/comp/BuildingComp.java @@ -199,10 +199,13 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, public void addPlan(boolean checkPrevious){ if(!block.rebuildable || (team == state.rules.defaultTeam && state.isCampaign() && !block.isVisible())) return; + Object overrideConfig = null; + if(self() instanceof ConstructBuild entity){ //update block to reflect the fact that something was being constructed if(entity.cblock != null && entity.cblock.synthetic() && entity.wasConstructing){ block = entity.cblock; + overrideConfig = entity.lastConfig; }else{ //otherwise this was a deconstruction that was interrupted, don't want to rebuild that return; @@ -223,7 +226,7 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc, } } - data.blocks.addFirst(new BlockPlan(tile.x, tile.y, (short)rotation, block.id, config())); + data.blocks.addFirst(new BlockPlan(tile.x, tile.y, (short)rotation, block.id, overrideConfig == null ? config() : overrideConfig)); } /** Configure with the current, local player. */ diff --git a/core/src/mindustry/entities/comp/UnitComp.java b/core/src/mindustry/entities/comp/UnitComp.java index e66c1131ec..004ae4a196 100644 --- a/core/src/mindustry/entities/comp/UnitComp.java +++ b/core/src/mindustry/entities/comp/UnitComp.java @@ -109,6 +109,9 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I @Replace public float clipSize(){ + if(isBuilding()){ + return state.rules.infiniteResources ? Float.MAX_VALUE : Math.max(type.clipSize, type.region.width) + buildingRange + tilesize*4f; + } return Math.max(type.region.width * 2f, type.clipSize); } diff --git a/core/src/mindustry/graphics/Layer.java b/core/src/mindustry/graphics/Layer.java index 519850a2f9..5ddea70282 100644 --- a/core/src/mindustry/graphics/Layer.java +++ b/core/src/mindustry/graphics/Layer.java @@ -65,6 +65,9 @@ public class Layer{ //overlaied UI, like block config guides overlayUI = 120, + //build beam effects + buildBeam = 122, + //shield effects shields = 125, diff --git a/core/src/mindustry/graphics/Shaders.java b/core/src/mindustry/graphics/Shaders.java index c72aa9e5b1..637b09967b 100644 --- a/core/src/mindustry/graphics/Shaders.java +++ b/core/src/mindustry/graphics/Shaders.java @@ -17,6 +17,7 @@ import static mindustry.Vars.*; public class Shaders{ public static BlockBuild blockbuild; public static @Nullable ShieldShader shield; + public static BuildBeamShader buildBeam; public static UnitBuild build; public static DarknessShader darkness; public static LightShader light; @@ -38,6 +39,7 @@ public class Shaders{ shield = null; t.printStackTrace(); } + buildBeam = new BuildBeamShader(); build = new UnitBuild(); darkness = new DarknessShader(); light = new LightShader(); @@ -161,7 +163,6 @@ public class Shaders{ } public static class BlockBuild extends LoadShader{ - public Color color = new Color(); public float progress; public TextureRegion region = new TextureRegion(); @@ -172,7 +173,6 @@ public class Shaders{ @Override public void apply(){ setUniformf("u_progress", progress); - setUniformf("u_color", color); setUniformf("u_uv", region.u, region.v); setUniformf("u_uv2", region.u2, region.v2); setUniformf("u_time", Time.time); @@ -186,6 +186,24 @@ public class Shaders{ super("shield", "screenspace"); } + @Override + public void apply(){ + setUniformf("u_dp", Scl.scl(1f)); + setUniformf("u_time", Time.time / Scl.scl(1f)); + setUniformf("u_offset", + Core.camera.position.x - Core.camera.width / 2, + Core.camera.position.y - Core.camera.height / 2); + setUniformf("u_texsize", Core.camera.width, Core.camera.height); + setUniformf("u_invsize", 1f/Core.camera.width, 1f/Core.camera.height); + } + } + + public static class BuildBeamShader extends LoadShader{ + + public BuildBeamShader(){ + super("buildbeam", "screenspace"); + } + @Override public void apply(){ setUniformf("u_dp", Scl.scl(1f)); diff --git a/core/src/mindustry/type/UnitType.java b/core/src/mindustry/type/UnitType.java index 72f7b445bf..4dde9e0c54 100644 --- a/core/src/mindustry/type/UnitType.java +++ b/core/src/mindustry/type/UnitType.java @@ -52,6 +52,7 @@ public class UnitType extends UnlockableContent{ public float groundLayer = Layer.groundUnit; public float payloadCapacity = 8; public float aimDst = -1f; + public float buildBeamOffset = 3.8f; public int commandLimit = 8; public float visualElevation = -1f; public boolean allowLegStep = false; diff --git a/core/src/mindustry/ui/dialogs/CustomRulesDialog.java b/core/src/mindustry/ui/dialogs/CustomRulesDialog.java index cfcdd85452..ece89b15f8 100644 --- a/core/src/mindustry/ui/dialogs/CustomRulesDialog.java +++ b/core/src/mindustry/ui/dialogs/CustomRulesDialog.java @@ -140,7 +140,7 @@ public class CustomRulesDialog extends BaseDialog{ title("@rules.title.resourcesbuilding"); check("@rules.infiniteresources", b -> rules.infiniteResources = b, () -> rules.infiniteResources); check("@rules.reactorexplosions", b -> rules.reactorExplosions = b, () -> rules.reactorExplosions); - check("@rules.schematic", b-> rules.schematicsAllowed = b, () -> rules.schematicsAllowed); + check("@rules.schematic", b -> rules.schematicsAllowed = b, () -> rules.schematicsAllowed); number("@rules.buildcostmultiplier", false, f -> rules.buildCostMultiplier = f, () -> rules.buildCostMultiplier, () -> !rules.infiniteResources); number("@rules.buildspeedmultiplier", f -> rules.buildSpeedMultiplier = f, () -> rules.buildSpeedMultiplier, 0.00001f, 10000f); number("@rules.deconstructrefundmultiplier", false, f -> rules.deconstructRefundMultiplier = f, () -> rules.deconstructRefundMultiplier, () -> !rules.infiniteResources); diff --git a/core/src/mindustry/world/blocks/ConstructBlock.java b/core/src/mindustry/world/blocks/ConstructBlock.java index e3deb845f9..9e6696263c 100644 --- a/core/src/mindustry/world/blocks/ConstructBlock.java +++ b/core/src/mindustry/world/blocks/ConstructBlock.java @@ -145,8 +145,9 @@ public class ConstructBlock extends Block{ * If a non-recipe block is being deconstructed, this is the block that is being deconstructed. */ public Block previous; - public Object lastConfig; - public boolean wasConstructing; + public @Nullable Object lastConfig; + public boolean wasConstructing, activeDeconstruct; + public float constructColor; @Nullable public Unit lastBuilder; @@ -176,7 +177,7 @@ public class ConstructBlock extends Block{ @Override public void tapped(){ - //if the target is constructible, begin constructing + //if the target is constructable, begin constructing if(cblock != null){ if(control.input.buildWasAutoPaused && !control.input.isBuilding && player.isBuilder()){ control.input.isBuilding = true; @@ -194,6 +195,12 @@ public class ConstructBlock extends Block{ } } + @Override + public void updateTile(){ + constructColor = Mathf.lerpDelta(constructColor, activeDeconstruct ? 1f : 0f, 0.2f); + activeDeconstruct = false; + } + @Override public void draw(){ if(!(previous == null || cblock == null || previous == cblock) && Core.atlas.isFound(previous.icon(Cicon.full))){ @@ -201,7 +208,7 @@ public class ConstructBlock extends Block{ } Draw.draw(Layer.blockBuilding, () -> { - Shaders.blockbuild.color = Pal.accent; + Draw.color(Pal.accent, Pal.remove, constructColor); Block target = cblock == null ? previous : cblock; @@ -214,11 +221,14 @@ public class ConstructBlock extends Block{ Draw.flush(); } } + + Draw.color(); }); } public void construct(Unit builder, @Nullable Building core, float amount, Object config){ wasConstructing = true; + activeDeconstruct = false; if(cblock == null){ kill(); return; @@ -254,6 +264,7 @@ public class ConstructBlock extends Block{ public void deconstruct(Unit builder, @Nullable Building core, float amount){ wasConstructing = false; + activeDeconstruct = true; float deconstructMultiplier = state.rules.deconstructRefundMultiplier; if(builder.isPlayer()){ @@ -333,7 +344,8 @@ public class ConstructBlock extends Block{ } public void setConstruct(Block previous, Block block){ - wasConstructing = true; + this.constructColor = 0f; + this.wasConstructing = true; this.cblock = block; this.previous = previous; this.accumulator = new float[block.requirements.length]; @@ -343,7 +355,9 @@ public class ConstructBlock extends Block{ public void setDeconstruct(Block previous){ if(previous == null) return; - wasConstructing = false; + + this.constructColor = 1f; + this.wasConstructing = false; this.previous = previous; this.progress = 1f; if(previous.buildCost >= 0.01f){ diff --git a/core/src/mindustry/world/blocks/distribution/StackConveyor.java b/core/src/mindustry/world/blocks/distribution/StackConveyor.java index 7deba52711..a94c69bf71 100644 --- a/core/src/mindustry/world/blocks/distribution/StackConveyor.java +++ b/core/src/mindustry/world/blocks/distribution/StackConveyor.java @@ -201,7 +201,7 @@ public class StackConveyor extends Block implements Autotiler{ if(cooldown > 0f) return; // get current item - if(lastItem == null){ + if(lastItem == null || !items.has(lastItem)){ lastItem = items.first(); }