New core landing animation

This commit is contained in:
Anuken 2021-07-26 19:29:14 -04:00
parent aab79a90fb
commit c19a7e8452
23 changed files with 201 additions and 43 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 874 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 871 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 528 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 512 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -352,3 +352,4 @@
63354=payload-launch-pad|block-payload-launch-pad-ui
63353=silicon-arc-furnace|block-silicon-arc-furnace-ui
63352=metal-floor-4|block-metal-floor-4-ui
63351=invincible|status-invincible-ui

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.4 KiB

After

Width:  |  Height:  |  Size: 114 KiB

View File

@ -105,6 +105,8 @@ public class Vars implements Loadable{
public static final float minArmorDamage = 0.1f;
/** launch animation duration */
public static final float launchDuration = 140f;
/** land animation duration */
public static final float coreLandDuration = 150f;
/** size of tiles in units */
public static final int tilesize = 8;
/** size of one tile payload (^2) */
@ -144,6 +146,8 @@ public class Vars implements Loadable{
public static int maxTextureSize = 2048;
/** Whether to show the core landing animation. */
public static boolean showLandAnimation = true;
/** Whether to show sector info upon landing. */
public static boolean showSectorLandInfo = true;
/** Whether to check for memory use before taking screenshots. */
public static boolean checkScreenshotMemory = true;
/** Whether to prompt the user to confirm exiting. */

View File

@ -1377,6 +1377,7 @@ public class Blocks implements ContentList{
health = 3500;
itemCapacity = 9000;
size = 4;
thrusterLength = 34/4f;
unitCapModifier = 16;
researchCostMultiplier = 0.07f;
@ -1389,6 +1390,7 @@ public class Blocks implements ContentList{
health = 6000;
itemCapacity = 13000;
size = 5;
thrusterLength = 40/4f;
unitCapModifier = 24;
researchCostMultiplier = 0.11f;

View File

@ -1862,6 +1862,13 @@ public class Fx{
Lines.poly(e.x, e.y, 6, e.rotation + e.fin());
}),
coreLandDust = new Effect(100f, e -> {
color(e.color, e.fout(0.1f));
rand.setSeed(e.id);
Tmp.v1.trns(e.rotation, e.finpow() * 90f * rand.random(0.2f, 1f));
Fill.circle(e.x + Tmp.v1.x, e.y + Tmp.v1.y, 8f * rand.random(0.6f, 1f) * e.fout(0.2f));
}).layer(Layer.block + 1f),
unitShieldBreak = new Effect(35, e -> {
if(!(e.data instanceof Unitc)) return;
@ -1955,8 +1962,5 @@ public class Fx{
}
Lines.endLine();
}).followParent(false),
coreLand = new Effect(120f, e -> {
});
}).followParent(false);
}

View File

@ -2,6 +2,7 @@ package mindustry.content;
import arc.graphics.*;
import mindustry.ctype.*;
import mindustry.graphics.*;
import mindustry.graphics.g3d.*;
import mindustry.maps.planet.*;
import mindustry.type.*;
@ -38,6 +39,7 @@ public class Planets implements ContentList{
atmosphereRadOut = 0.3f;
startSector = 15;
alwaysUnlocked = true;
landCloudColor = Pal.spore.cpy().a(0.5f);
}};
}
}

View File

@ -421,14 +421,14 @@ public class UnitTypes implements ContentList{
mechStepShake = 0.15f;
ammoType = AmmoTypes.powerHigh;
speed = 0.39f;
speed = 0.4f;
boostMultiplier = 2.2f;
engineOffset = 12f;
engineSize = 6f;
lowAltitude = true;
riseSpeed = 0.02f;
health = 7500f;
health = 8000f;
armor = 9f;
canBoost = true;
landShake = 4f;
@ -453,8 +453,8 @@ public class UnitTypes implements ContentList{
cooldownTime = 200f;
bullet = new ContinuousLaserBulletType(){{
damage = 30f;
length = 175f;
damage = 32f;
length = 180f;
hitEffect = Fx.hitMeltHeal;
drawSize = 420f;
lifetime = 160f;

View File

@ -36,7 +36,6 @@ import java.text.*;
import java.util.*;
import static arc.Core.*;
import static mindustry.Vars.net;
import static mindustry.Vars.*;
/**
@ -195,7 +194,7 @@ public class Control implements ApplicationListener, Loadable{
});
Events.run(Trigger.newGame, () -> {
Building core = player.bestCore();
var core = player.bestCore();
if(core == null) return;
@ -203,6 +202,8 @@ public class Control implements ApplicationListener, Loadable{
player.set(core);
if(showLandAnimation){
//delay player respawn so animation can play.
player.deathTimer = -70f;
//TODO this sounds pretty bad due to conflict
if(settings.getInt("musicvol") > 0){
Musics.land.stop();
@ -211,14 +212,14 @@ public class Control implements ApplicationListener, Loadable{
}
app.post(() -> ui.hudfrag.showLand());
renderer.zoomIn(Fx.coreLand.lifetime);
app.post(() -> Fx.coreLand.at(core.getX(), core.getY(), 0, core.block));
renderer.showLaunch();
Time.run(Fx.coreLand.lifetime, () -> {
Time.run(coreLandDuration, () -> {
Fx.launch.at(core);
Effect.shake(5f, 5f, core);
core.thrusterTime = 1f;
if(state.isCampaign()){
if(state.isCampaign() && Vars.showSectorLandInfo){
ui.announce("[accent]" + state.rules.sector.name() + "\n" +
(state.rules.sector.info.resources.any() ? "[lightgray]" + bundle.get("sectors.resources") + "[white] " +
state.rules.sector.info.resources.toString(" ", u -> u.emoji()) : ""), 5);
@ -328,6 +329,7 @@ public class Control implements ApplicationListener, Loadable{
slot.load();
slot.setAutosave(true);
state.rules.sector = sector;
state.rules.cloudColor = sector.planet.landCloudColor;
//if there is no base, simulate a new game and place the right loadout at the spawn position
if(state.rules.defaultTeam.cores().isEmpty() || hadNoCore){

View File

@ -18,6 +18,7 @@ import mindustry.game.EventType.*;
import mindustry.gen.*;
import mindustry.graphics.*;
import mindustry.graphics.g3d.*;
import mindustry.world.blocks.storage.*;
import mindustry.world.blocks.storage.CoreBlock.*;
import static arc.Core.*;
@ -27,6 +28,12 @@ public class Renderer implements ApplicationListener{
/** These are global variables, for headless access. Cached. */
public static float laserOpacity = 0.5f, bridgeOpacity = 0.75f;
private static final float cloudScaling = 1700f, cfinScl = -2f, cfinOffset = 0.3f, calphaFinOffset = 0.25f;
private static final float[] cloudAlphas = {0, 0.5f, 1f, 0.1f, 0, 0f};
private static final float cloudAlpha = 0.81f;
private static final float[] thrusterSize = {0f, 0f, 0f, 0f, 0.3f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 0f};
private static final Interp landInterp = Interp.pow3;
public final BlockRenderer blocks = new BlockRenderer();
public final MinimapRenderer minimap = new MinimapRenderer();
public final OverlayRenderer overlays = new OverlayRenderer();
@ -44,7 +51,8 @@ public class Renderer implements ApplicationListener{
private @Nullable CoreBuild landCore;
private Color clearColor = new Color(0f, 0f, 0f, 1f);
private float targetscale = Scl.scl(4), camerascale = targetscale, landscale, landTime, weatherAlpha, minZoomScl = Scl.scl(0.01f);
private float cloudSeed = 0f;
private float targetscale = Scl.scl(4), camerascale = targetscale, landscale, landTime, landPTimer, weatherAlpha, minZoomScl = Scl.scl(0.01f);
private float shakeIntensity, shaketime;
private Vec2 camShakeOffset = new Vec2();
@ -97,10 +105,14 @@ public class Renderer implements ApplicationListener{
drawStatus = Core.settings.getBool("blockstatus");
if(landTime > 0){
if(!state.isPaused()){
updateLandParticles();
}
if(!state.isPaused()){
landTime -= Time.delta;
}
landscale = Interp.pow5In.apply(minZoomScl, Scl.scl(4f), 1f - landTime / Fx.coreLand.lifetime);
landscale = landInterp.apply(minZoomScl, Scl.scl(4f), 1f - landTime / coreLandDuration);
camerascale = landscale;
weatherAlpha = 0f;
}else{
@ -281,45 +293,134 @@ public class Renderer implements ApplicationListener{
}
private void drawLanding(){
CoreBuild entity = landCore == null ? player.bestCore() : landCore;
//var clouds = assets.get("sprites/clouds.png", Texture.class);
if(landTime > 0 && entity != null){
float fout = landTime / Fx.coreLand.lifetime;
void updateLandParticles(){
float tsize = Mathf.sample(thrusterSize, (landTime + 35f) / coreLandDuration);
//TODO clouds
/*
float scaling = 10000f;
float sscl = 1f + fout*1.5f;
float offset = -0.38f;
landPTimer += tsize * Time.delta;
if(landCore != null && landPTimer >= 1f){
landCore.tile.getLinkedTiles(t -> {
if(Mathf.chance(0.4f)){
Fx.coreLandDust.at(t.worldx(), t.worldy(), landCore.angleTo(t) + Mathf.range(30f), Tmp.c1.set(t.floor().mapColor).mul(1.5f + Mathf.range(0.15f)));
}
});
Tmp.tr1.set(clouds);
Tmp.tr1.set((camera.position.x - camera.width/2f * sscl) / scaling, (camera.position.y - camera.height/2f * sscl) / scaling, (camera.position.x + camera.width/2f * sscl) / scaling, (camera.position.y + camera.height/2f * sscl) / scaling);
Draw.alpha(Mathf.slope(Mathf.clamp(((1f - fout) + offset)/(1f + offset))));
Draw.mixcol(Pal.spore, 0.5f);
Draw.rect(Tmp.tr1, camera.position.x, camera.position.y, camera.width, camera.height);
Draw.reset();*/
landPTimer = 0f;
}
}
TextureRegion reg = entity.block.fullIcon;
void drawLanding(){
CoreBuild build = landCore == null ? player.bestCore() : landCore;
var clouds = assets.get("sprites/clouds.png", Texture.class);
if(landTime > 0 && build != null){
float fout = landTime / coreLandDuration;
float fin = 1f - fout;
//core
var block = (CoreBlock)build.block;
TextureRegion reg = block.fullIcon;
float scl = Scl.scl(4f) / camerascale;
float s = reg.width * Draw.scl * scl * 4f * fout;
float shake = 0f;
float s = reg.width * Draw.scl * scl * 3.6f * Interp.pow2Out.apply(fout);
float rotation = Interp.pow2In.apply(fout) * 135f, x = build.x + Mathf.range(shake), y = build.y + Mathf.range(shake);
float thrustOpen = 0.25f;
float frame = fin >= thrustOpen ? 1f : fin / thrustOpen;
Draw.color(Pal.lightTrail);
Draw.rect("circle-shadow", entity.x, entity.y, s, s);
//TODO spikier heat
Draw.rect("circle-shadow", x, y, s, s);
Angles.randLenVectors(1, (1f- fout), 100, 1000f * scl * (1f-fout), (x, y, ffin, ffout) -> {
Lines.stroke(scl * ffin);
Lines.lineAngle(entity.x + x, entity.y + y, Mathf.angle(x, y), (ffin * 20 + 1f) * scl);
Draw.color(Pal.lightTrail);
float pfin = Interp.pow3Out.apply(fin), pf = Interp.pow2In.apply(fout);
//particles
Angles.randLenVectors(1, pfin, 100, 800f * scl * pfin, (ax, ay, ffin, ffout) -> {
Lines.stroke(scl * ffin * pf * 3f);
Lines.lineAngle(build.x + ax, build.y + ay, Mathf.angle(ax, ay), (ffin * 20 + 1f) * scl);
});
Draw.color();
Draw.mixcol(Color.white, fout);
Draw.rect(reg, entity.x, entity.y, reg.width * Draw.scl * scl, reg.height * Draw.scl * scl, fout * 135f);
Draw.mixcol(Color.white, Interp.pow2In.apply(fout));
Draw.scl(scl);
Draw.alpha(1f);
//thruster flame
float strength = (1f + (block.size - 3)/2.5f) * scl * Mathf.sample(thrusterSize, fin) * (0.95f + Mathf.absin(2f, 0.1f));
float offset = (block.size - 3) * 3f * scl;
for(int i = 0; i < 4; i++){
Tmp.v1.trns(i * 90 + rotation, 1f);
Tmp.v1.setLength((block.size * tilesize/2f + 1f)*scl + strength*2f + offset);
Draw.color(build.team.color);
Fill.circle(Tmp.v1.x + x, Tmp.v1.y + y, 6f * strength);
Tmp.v1.setLength((block.size * tilesize/2f + 1f)*scl + strength*0.5f + offset);
Draw.color(Color.white);
Fill.circle(Tmp.v1.x + x, Tmp.v1.y + y, 3f * strength);
}
drawThrusters(block, x, y, rotation, frame);
Drawf.spinSprite(block.region, x, y, rotation);
Draw.alpha(Interp.pow4In.apply(frame));
drawThrusters(block, x, y, rotation, frame);
Draw.alpha(1f);
Drawf.spinSprite(block.teamRegions[build.team.id], x, y, rotation);
Draw.scl();
Draw.reset();
//clouds
float scaling = cloudScaling;
float sscl = Math.max(1f + Mathf.clamp(fin + cfinOffset)* cfinScl, 0f) * landscale;
Tmp.tr1.set(clouds);
Tmp.tr1.set(
(camera.position.x - camera.width/2f * sscl) / scaling,
(camera.position.y - camera.height/2f * sscl) / scaling,
(camera.position.x + camera.width/2f * sscl) / scaling,
(camera.position.y + camera.height/2f * sscl) / scaling);
Tmp.tr1.scroll(10f * cloudSeed, 10f * cloudSeed);
Draw.alpha(Mathf.sample(cloudAlphas, fin + calphaFinOffset) * cloudAlpha);
Draw.mixcol(state.rules.cloudColor, state.rules.cloudColor.a);
Draw.rect(Tmp.tr1, camera.position.x, camera.position.y, camera.width, camera.height);
Draw.reset();
}
}
void drawThrusters(CoreBlock block, float x, float y, float rotation, float frame){
float length = block.thrusterLength * (frame - 1f) - 1f/4f;
float alpha = Draw.getColor().a;
//two passes for consistent lighting
for(int j = 0; j < 2; j++){
for(int i = 0; i < 4; i++){
var reg = i >= 2 ? block.thruster2 : block.thruster1;
float rot = (i * 90) + rotation % 90f;
Tmp.v1.trns(rot, length * Draw.xscl);
//second pass applies extra layer of shading
if(j == 1){
Tmp.v1.rotate(-90f);
Draw.alpha((rotation % 90f) / 90f * alpha);
rot -= 90f;
Draw.rect(reg, x + Tmp.v1.x, y + Tmp.v1.y, rot);
}else{
Draw.alpha(alpha);
Draw.rect(reg, x + Tmp.v1.x, y + Tmp.v1.y, rot);
}
}
}
Draw.alpha(1f);
}
public void scaleCamera(float amount){
targetscale *= (amount / 4) + 1;
clampScale();
@ -350,9 +451,10 @@ public class Renderer implements ApplicationListener{
clampScale();
}
public void zoomIn(float duration){
public void showLaunch(){
landscale = minZoomScl;
landTime = duration;
landTime = coreLandDuration;
cloudSeed = Mathf.random(1f);
}
public void takeMapScreenshot(){

View File

@ -287,6 +287,7 @@ public class World{
if(liquid != null) content.add(liquid);
}
state.rules.cloudColor = sector.planet.landCloudColor;
sector.info.resources = content.asArray();
sector.info.resources.sort(Structs.comps(Structs.comparing(Content::getContentType), Structs.comparingInt(c -> c.id)));
sector.saveInfo();

View File

@ -6,6 +6,7 @@ import arc.util.*;
import mindustry.*;
import mindustry.ai.*;
import mindustry.entities.*;
import mindustry.game.*;
import mindustry.gen.*;
import mindustry.type.*;
import mindustry.world.*;
@ -154,6 +155,7 @@ public class AIController implements UnitController{
}
protected Teamc targetFlag(float x, float y, BlockFlag flag, boolean enemy){
if(unit.team == Team.derelict) return null;
Tile target = Geometry.findClosest(x, y, enemy ? indexer.getEnemy(unit.team, flag) : indexer.getAllied(unit.team, flag));
return target == null ? null : target.build;
}

View File

@ -109,6 +109,8 @@ public class Rules{
public Team defaultTeam = Team.sharded;
/** team of the enemy in waves/sectors. */
public Team waveTeam = Team.crux;
/** color of clouds that is displayed when the player is landing */
public Color cloudColor = new Color(0f, 0f, 0f, 0f);
/** name of the custom mode that this ruleset describes, or null. */
public @Nullable String modeName;
/** Whether cores incinerate items when full, just like in the campaign. */

View File

@ -55,6 +55,8 @@ public class Planet extends UnlockableContent{
public boolean bloom = false;
/** Whether this planet is displayed. */
public boolean visible = true;
/** Tint of clouds displayed when landing. */
public Color landCloudColor = new Color(1f, 1f, 1f, 0.5f);
/** For suns, this is the color that shines on other planets. Does nothing for children. */
public Color lightColor = Color.white.cpy();
/** Atmosphere tint for landable planets. */

View File

@ -29,6 +29,10 @@ public class CoreBlock extends StorageBlock{
//hacky way to pass item modules between methods
private static ItemModule nextItems;
public @Load("@-thruster1") TextureRegion thruster1; //top right
public @Load("@-thruster2") TextureRegion thruster2; //bot left
public float thrusterLength = 14f/4f;
public UnitType unitType = UnitTypes.alpha;
public float captureInvicibility = 60f * 15f;
@ -176,6 +180,35 @@ public class CoreBlock extends StorageBlock{
public boolean noEffect = false;
public Team lastDamage = Team.derelict;
public float iframes = -1f;
public float thrusterTime = 0f;
@Override
public void draw(){
//draw thrusters when just landed
if(thrusterTime > 0){
float frame = thrusterTime;
Draw.alpha(1f);
drawThrusters(frame);
Draw.rect(block.region, x, y);
Draw.alpha(Interp.pow4In.apply(frame));
drawThrusters(frame);
Draw.reset();
drawTeamTop();
}else{
super.draw();
}
}
public void drawThrusters(float frame){
float length = thrusterLength * (frame - 1f) - 1f/4f;
for(int i = 0; i < 4; i++){
var reg = i >= 2 ? thruster2 : thruster1;
float dx = Geometry.d4x[i] * length, dy = Geometry.d4y[i] * length;
Draw.rect(reg, x + dx, y + dy, i * 90);
}
}
@Override
public void damage(@Nullable Team source, float damage){
@ -234,6 +267,7 @@ public class CoreBlock extends StorageBlock{
@Override
public void updateTile(){
iframes -= Time.delta;
thrusterTime -= Time.delta/90f;
}
@Override

View File

@ -10,4 +10,4 @@ kapt.include.compile.classpath=false
kotlin.stdlib.default.dependency=false
#needed for android compilation
android.useAndroidX=true
archash=d7b814ff69853e3bc8fa0703d3b2829cbff65e9e
archash=6e9fd338866c05cd42ec20f26ec7fa7c3a25d6d5