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

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

View File

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

View File

@ -35,12 +35,25 @@ abstract class BuilderComp implements Posc, Teamc, Rotc{
@SyncLocal Queue<BuildPlan> 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);
}
}

View File

@ -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. */

View File

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

View File

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

View File

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

View File

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

View File

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

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.
*/
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){

View File

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