1
0
mirror of https://github.com/Anuken/Mindustry.git synced 2024-09-21 21:38:29 +03:00

Better build beam visuals

This commit is contained in:
Anuken 2020-12-25 21:49:10 -05:00
parent 834e4f175b
commit 9f8fce72d3
13 changed files with 147 additions and 36 deletions

View File

@ -1,6 +1,5 @@
uniform sampler2D u_texture; uniform sampler2D u_texture;
uniform vec4 u_color;
uniform vec2 u_texsize; uniform vec2 u_texsize;
uniform vec2 u_uv; uniform vec2 u_uv;
uniform vec2 u_uv2; uniform vec2 u_uv2;
@ -38,11 +37,11 @@ void main(){
float dst = (abs(center.x - coords.x) + abs(center.y - coords.y))/2.0; 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))){ 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)){ }else if(dst > (1.0-u_progress) * (center.x)){
gl_FragColor = color; gl_FragColor = color;
}else if((dst + 1.0 > (1.0-u_progress) * (center.x)) && color.a > 0.1){ }else if((dst + 1.0 > (1.0-u_progress) * (center.x)) && color.a > 0.1){
gl_FragColor = u_color; gl_FragColor = v_color;
}else{ }else{
gl_FragColor = vec4(0.0); gl_FragColor = vec4(0.0);
} }

View File

@ -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;
}

View File

@ -1317,6 +1317,7 @@ public class UnitTypes implements ContentList{
hitSize = 32f; hitSize = 32f;
payloadCapacity = (3 * 3) * tilePayload; payloadCapacity = (3 * 3) * tilePayload;
buildSpeed = 2.5f; buildSpeed = 2.5f;
buildBeamOffset = 23;
range = 140f; range = 140f;
targetAir = false; targetAir = false;
targetFlag = BlockFlag.battery; targetFlag = BlockFlag.battery;
@ -1388,6 +1389,7 @@ public class UnitTypes implements ContentList{
drawShields = false; drawShields = false;
commandLimit = 6; commandLimit = 6;
lowAltitude = true; lowAltitude = true;
buildBeamOffset = 43;
ammoCapacity = 1300; ammoCapacity = 1300;
ammoResupplyAmount = 20; ammoResupplyAmount = 20;

View File

@ -30,6 +30,7 @@ public class Renderer implements ApplicationListener{
public @Nullable Bloom bloom; public @Nullable Bloom bloom;
public FrameBuffer effectBuffer = new FrameBuffer(); public FrameBuffer effectBuffer = new FrameBuffer();
public float laserOpacity = 1f; public float laserOpacity = 1f;
public boolean animateShields;
/** minZoom = zooming out, maxZoom = zooming in */ /** minZoom = zooming out, maxZoom = zooming in */
public float minZoom = 1.5f, maxZoom = 6f; public float minZoom = 1.5f, maxZoom = 6f;
@ -69,7 +70,8 @@ public class Renderer implements ApplicationListener{
float dest = Mathf.round(targetscale, 0.5f); float dest = Mathf.round(targetscale, 0.5f);
camerascale = Mathf.lerpDelta(camerascale, dest, 0.1f); camerascale = Mathf.lerpDelta(camerascale, dest, 0.1f);
if(Mathf.equal(camerascale, dest, 0.001f)) camerascale = dest; 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){ if(landTime > 0){
landTime -= Time.delta; landTime -= Time.delta;
@ -204,7 +206,7 @@ public class Renderer implements ApplicationListener{
graphics.clear(clearColor); graphics.clear(clearColor);
Draw.reset(); Draw.reset();
if(Core.settings.getBool("animatedwater") || Core.settings.getBool("animatedshields")){ if(Core.settings.getBool("animatedwater") || animateShields){
effectBuffer.resize(graphics.getWidth(), graphics.getHeight()); effectBuffer.resize(graphics.getWidth(), graphics.getHeight());
} }
@ -248,11 +250,16 @@ public class Renderer implements ApplicationListener{
Draw.draw(Layer.plans, overlays::drawBottom); 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), () -> { Draw.drawRange(Layer.shields, 1f, () -> effectBuffer.begin(Color.clear), () -> {
effectBuffer.end(); effectBuffer.end();
effectBuffer.blit(Shaders.shield); 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); Draw.draw(Layer.overlayUI, overlays::drawTop);

View File

@ -35,12 +35,25 @@ abstract class BuilderComp implements Posc, Teamc, Rotc{
@SyncLocal Queue<BuildPlan> plans = new Queue<>(1); @SyncLocal Queue<BuildPlan> plans = new Queue<>(1);
@SyncLocal boolean updateBuilding = true; @SyncLocal boolean updateBuilding = true;
private transient BuildPlan lastActive;
private transient int lastSize;
private transient float buildAlpha = 0f;
public boolean canBuild(){ public boolean canBuild(){
return type.buildSpeed > 0; return type.buildSpeed > 0;
} }
@Override @Override
public void update(){ 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; if(!updateBuilding || !canBuild()) return;
float finalPlaceDst = state.rules.infiniteResources ? Float.MAX_VALUE : buildingRange; float finalPlaceDst = state.rules.infiniteResources ? Float.MAX_VALUE : buildingRange;
@ -56,9 +69,12 @@ abstract class BuilderComp implements Posc, Teamc, Rotc{
} }
Building core = core(); Building core = core();
BuildPlan current = buildPlan();
//nothing to build. //nothing to build.
if(buildPlan() == null) return; if(current == null) return;
Tile tile = current.tile();
//find the next build request //find the next build request
if(plans.size > 1){ 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; if(!within(tile, finalPlaceDst)) return;
Tile tile = world.tile(current.x, current.y);
if(!(tile.build instanceof ConstructBuild cb)){ if(!(tile.build instanceof ConstructBuild cb)){
if(!current.initialized && !current.breaking && Build.validPlace(current.block, team, current.x, current.y, current.rotation)){ 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(){ boolean activelyBuilding(){
//not actively building when not near the build plan //not actively building when not near the build plan
if(isBuilding()){ 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; return false;
} }
} }
@ -218,30 +234,31 @@ abstract class BuilderComp implements Posc, Teamc, Rotc{
} }
public void draw(){ public void draw(){
if(!activelyBuilding()) return; boolean active = activelyBuilding();
if(!active && lastActive == null) return;
Draw.z(Layer.flyingUnit); Draw.z(Layer.flyingUnit);
BuildPlan plan = buildPlan(); BuildPlan plan = active ? buildPlan() : lastActive;
Tile tile = world.tile(plan.x, plan.y); Tile tile = world.tile(plan.x, plan.y);
var core = team.core(); 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; return;
} }
//draw remote plans. //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); Draw.z(Layer.plans - 1f);
drawPlan(plan, 0.5f); drawPlan(plan, 0.5f);
Draw.z(Layer.flyingUnit); 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(); float tx = plan.drawx(), ty = plan.drawy();
Lines.stroke(1f, Pal.accent); Lines.stroke(1f, plan.breaking ? Pal.remove : Pal.accent);
float focusLen = 3.8f + Mathf.absin(Time.time, 1.1f, 0.6f); float focusLen = type.buildBeamOffset + Mathf.absin(Time.time, 3f, 0.6f);
float px = x + Angles.trnsx(rotation, focusLen); float px = x + Angles.trnsx(rotation, focusLen);
float py = y + Angles.trnsy(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))); 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, float x1 = vecs[0].x, y1 = vecs[0].y,
x2 = close.x, y2 = close.y,
x3 = vecs[1].x, y3 = vecs[1].y; x3 = vecs[1].x, y3 = vecs[1].y;
Draw.alpha(1f); Draw.z(Layer.buildBeam);
Draw.alpha(buildAlpha);
if(!active && !(tile.build instanceof ConstructBuild)){
Fill.square(plan.drawx(), plan.drawy(), size * tilesize/2f);
}
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, x1, y1);
Lines.line(px, py, x3, y3); Lines.line(px, py, x3, y3);
}
Fill.circle(px, py, 1.6f + Mathf.absin(Time.time, 0.8f, 1.5f)); Fill.square(px, py, 1.8f + Mathf.absin(Time.time, 2.2f, 1.1f), rotation + 45);
Draw.color(); Draw.reset();
Draw.z(Layer.flyingUnit);
} }
} }

View File

@ -199,10 +199,13 @@ abstract class BuildingComp implements Posc, Teamc, Healthc, Buildingc, Timerc,
public void addPlan(boolean checkPrevious){ public void addPlan(boolean checkPrevious){
if(!block.rebuildable || (team == state.rules.defaultTeam && state.isCampaign() && !block.isVisible())) return; if(!block.rebuildable || (team == state.rules.defaultTeam && state.isCampaign() && !block.isVisible())) return;
Object overrideConfig = null;
if(self() instanceof ConstructBuild entity){ if(self() instanceof ConstructBuild entity){
//update block to reflect the fact that something was being constructed //update block to reflect the fact that something was being constructed
if(entity.cblock != null && entity.cblock.synthetic() && entity.wasConstructing){ if(entity.cblock != null && entity.cblock.synthetic() && entity.wasConstructing){
block = entity.cblock; block = entity.cblock;
overrideConfig = entity.lastConfig;
}else{ }else{
//otherwise this was a deconstruction that was interrupted, don't want to rebuild that //otherwise this was a deconstruction that was interrupted, don't want to rebuild that
return; 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. */ /** Configure with the current, local player. */

View File

@ -109,6 +109,9 @@ abstract class UnitComp implements Healthc, Physicsc, Hitboxc, Statusc, Teamc, I
@Replace @Replace
public float clipSize(){ 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); return Math.max(type.region.width * 2f, type.clipSize);
} }

View File

@ -65,6 +65,9 @@ public class Layer{
//overlaied UI, like block config guides //overlaied UI, like block config guides
overlayUI = 120, overlayUI = 120,
//build beam effects
buildBeam = 122,
//shield effects //shield effects
shields = 125, shields = 125,

View File

@ -17,6 +17,7 @@ import static mindustry.Vars.*;
public class Shaders{ public class Shaders{
public static BlockBuild blockbuild; public static BlockBuild blockbuild;
public static @Nullable ShieldShader shield; public static @Nullable ShieldShader shield;
public static BuildBeamShader buildBeam;
public static UnitBuild build; public static UnitBuild build;
public static DarknessShader darkness; public static DarknessShader darkness;
public static LightShader light; public static LightShader light;
@ -38,6 +39,7 @@ public class Shaders{
shield = null; shield = null;
t.printStackTrace(); t.printStackTrace();
} }
buildBeam = new BuildBeamShader();
build = new UnitBuild(); build = new UnitBuild();
darkness = new DarknessShader(); darkness = new DarknessShader();
light = new LightShader(); light = new LightShader();
@ -161,7 +163,6 @@ public class Shaders{
} }
public static class BlockBuild extends LoadShader{ public static class BlockBuild extends LoadShader{
public Color color = new Color();
public float progress; public float progress;
public TextureRegion region = new TextureRegion(); public TextureRegion region = new TextureRegion();
@ -172,7 +173,6 @@ public class Shaders{
@Override @Override
public void apply(){ public void apply(){
setUniformf("u_progress", progress); setUniformf("u_progress", progress);
setUniformf("u_color", color);
setUniformf("u_uv", region.u, region.v); setUniformf("u_uv", region.u, region.v);
setUniformf("u_uv2", region.u2, region.v2); setUniformf("u_uv2", region.u2, region.v2);
setUniformf("u_time", Time.time); setUniformf("u_time", Time.time);
@ -198,6 +198,24 @@ public class Shaders{
} }
} }
public static class BuildBeamShader extends LoadShader{
public BuildBeamShader(){
super("buildbeam", "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);
}
}
//seed: 8kmfuix03fw //seed: 8kmfuix03fw
public static class SpaceShader extends SurfaceShader{ public static class SpaceShader extends SurfaceShader{
Texture texture; Texture texture;

View File

@ -52,6 +52,7 @@ public class UnitType extends UnlockableContent{
public float groundLayer = Layer.groundUnit; public float groundLayer = Layer.groundUnit;
public float payloadCapacity = 8; public float payloadCapacity = 8;
public float aimDst = -1f; public float aimDst = -1f;
public float buildBeamOffset = 3.8f;
public int commandLimit = 8; public int commandLimit = 8;
public float visualElevation = -1f; public float visualElevation = -1f;
public boolean allowLegStep = false; public boolean allowLegStep = false;

View File

@ -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. * If a non-recipe block is being deconstructed, this is the block that is being deconstructed.
*/ */
public Block previous; public Block previous;
public Object lastConfig; public @Nullable Object lastConfig;
public boolean wasConstructing; public boolean wasConstructing, activeDeconstruct;
public float constructColor;
@Nullable @Nullable
public Unit lastBuilder; public Unit lastBuilder;
@ -176,7 +177,7 @@ public class ConstructBlock extends Block{
@Override @Override
public void tapped(){ public void tapped(){
//if the target is constructible, begin constructing //if the target is constructable, begin constructing
if(cblock != null){ if(cblock != null){
if(control.input.buildWasAutoPaused && !control.input.isBuilding && player.isBuilder()){ if(control.input.buildWasAutoPaused && !control.input.isBuilding && player.isBuilder()){
control.input.isBuilding = true; 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 @Override
public void draw(){ public void draw(){
if(!(previous == null || cblock == null || previous == cblock) && Core.atlas.isFound(previous.icon(Cicon.full))){ 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, () -> { Draw.draw(Layer.blockBuilding, () -> {
Shaders.blockbuild.color = Pal.accent; Draw.color(Pal.accent, Pal.remove, constructColor);
Block target = cblock == null ? previous : cblock; Block target = cblock == null ? previous : cblock;
@ -214,11 +221,14 @@ public class ConstructBlock extends Block{
Draw.flush(); Draw.flush();
} }
} }
Draw.color();
}); });
} }
public void construct(Unit builder, @Nullable Building core, float amount, Object config){ public void construct(Unit builder, @Nullable Building core, float amount, Object config){
wasConstructing = true; wasConstructing = true;
activeDeconstruct = false;
if(cblock == null){ if(cblock == null){
kill(); kill();
return; return;
@ -254,6 +264,7 @@ public class ConstructBlock extends Block{
public void deconstruct(Unit builder, @Nullable Building core, float amount){ public void deconstruct(Unit builder, @Nullable Building core, float amount){
wasConstructing = false; wasConstructing = false;
activeDeconstruct = true;
float deconstructMultiplier = state.rules.deconstructRefundMultiplier; float deconstructMultiplier = state.rules.deconstructRefundMultiplier;
if(builder.isPlayer()){ if(builder.isPlayer()){
@ -333,7 +344,8 @@ public class ConstructBlock extends Block{
} }
public void setConstruct(Block previous, Block block){ public void setConstruct(Block previous, Block block){
wasConstructing = true; this.constructColor = 0f;
this.wasConstructing = true;
this.cblock = block; this.cblock = block;
this.previous = previous; this.previous = previous;
this.accumulator = new float[block.requirements.length]; this.accumulator = new float[block.requirements.length];
@ -343,7 +355,9 @@ public class ConstructBlock extends Block{
public void setDeconstruct(Block previous){ public void setDeconstruct(Block previous){
if(previous == null) return; if(previous == null) return;
wasConstructing = false;
this.constructColor = 1f;
this.wasConstructing = false;
this.previous = previous; this.previous = previous;
this.progress = 1f; this.progress = 1f;
if(previous.buildCost >= 0.01f){ if(previous.buildCost >= 0.01f){

View File

@ -201,7 +201,7 @@ public class StackConveyor extends Block implements Autotiler{
if(cooldown > 0f) return; if(cooldown > 0f) return;
// get current item // get current item
if(lastItem == null){ if(lastItem == null || !items.has(lastItem)){
lastItem = items.first(); lastItem = items.first();
} }