mirror of
https://github.com/Anuken/Mindustry.git
synced 2026-01-25 22:12:16 -08:00
Enable full customization of core launching/landing animations. (#9693)
* Extract all updates and draws of core launch/land animations to CoreBlock/CoreBuild * Re-add removed methods as deprecated * Fixed tests failing * anuke said no * Extract launch effect
This commit is contained in:
parent
1f5d8b1f04
commit
bfd8dbd769
6 changed files with 221 additions and 138 deletions
|
|
@ -28,6 +28,7 @@ import mindustry.net.*;
|
|||
import mindustry.service.*;
|
||||
import mindustry.ui.dialogs.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.blocks.storage.*;
|
||||
import mindustry.world.meta.*;
|
||||
|
||||
import java.io.*;
|
||||
|
|
@ -105,8 +106,8 @@ public class Vars implements Loadable{
|
|||
public static final float invasionGracePeriod = 20;
|
||||
/** min armor fraction damage; e.g. 0.05 = at least 5% damage */
|
||||
public static final float minArmorDamage = 0.1f;
|
||||
/** land/launch animation duration */
|
||||
public static final float coreLandDuration = 160f;
|
||||
/** @deprecated see {@link CoreBlock#landDuration} instead! */
|
||||
public static final @Deprecated float coreLandDuration = 160f;
|
||||
/** size of tiles in units */
|
||||
public static final int tilesize = 8;
|
||||
/** size of one tile payload (^2) */
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@ import mindustry.net.*;
|
|||
import mindustry.type.*;
|
||||
import mindustry.ui.dialogs.*;
|
||||
import mindustry.world.*;
|
||||
import mindustry.world.blocks.storage.*;
|
||||
import mindustry.world.blocks.storage.CoreBlock.*;
|
||||
|
||||
import java.io.*;
|
||||
|
|
@ -191,43 +192,29 @@ public class Control implements ApplicationListener, Loadable{
|
|||
|
||||
Events.run(Trigger.newGame, () -> {
|
||||
var core = player.bestCore();
|
||||
|
||||
if(core == null) return;
|
||||
|
||||
camera.position.set(core);
|
||||
player.set(core);
|
||||
|
||||
float coreDelay = 0f;
|
||||
|
||||
if(!settings.getBool("skipcoreanimation") && !state.rules.pvp){
|
||||
coreDelay = coreLandDuration;
|
||||
coreDelay = core.landDuration();
|
||||
//delay player respawn so animation can play.
|
||||
player.deathTimer = Player.deathDelay - coreLandDuration;
|
||||
player.deathTimer = Player.deathDelay - core.landDuration();
|
||||
//TODO this sounds pretty bad due to conflict
|
||||
if(settings.getInt("musicvol") > 0){
|
||||
Musics.land.stop();
|
||||
Musics.land.play();
|
||||
Musics.land.setVolume(settings.getInt("musicvol") / 100f);
|
||||
//TODO what to do if another core with different music is already playing?
|
||||
Music music = core.landMusic();
|
||||
music.stop();
|
||||
music.play();
|
||||
music.setVolume(settings.getInt("musicvol") / 100f);
|
||||
}
|
||||
|
||||
app.post(() -> ui.hudfrag.showLand());
|
||||
renderer.showLanding();
|
||||
|
||||
Time.run(coreLandDuration, () -> {
|
||||
Fx.launch.at(core);
|
||||
Effect.shake(5f, 5f, core);
|
||||
core.thrusterTime = 1f;
|
||||
|
||||
if(state.isCampaign() && Vars.showSectorLandInfo && (state.rules.sector.preset == null || state.rules.sector.preset.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);
|
||||
}
|
||||
});
|
||||
renderer.showLanding(core);
|
||||
}
|
||||
|
||||
if(state.isCampaign()){
|
||||
|
||||
//don't run when hosting, that doesn't really work.
|
||||
if(state.rules.sector.planet.prebuildBase){
|
||||
toBePlaced.clear();
|
||||
|
|
|
|||
|
|
@ -13,7 +13,6 @@ import arc.scene.ui.layout.*;
|
|||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
import mindustry.*;
|
||||
import mindustry.content.*;
|
||||
import mindustry.game.EventType.*;
|
||||
import mindustry.gen.*;
|
||||
import mindustry.graphics.*;
|
||||
|
|
@ -30,11 +29,6 @@ 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 Interp landInterp = Interp.pow3;
|
||||
|
||||
public final BlockRenderer blocks = new BlockRenderer();
|
||||
public final FogRenderer fog = new FogRenderer();
|
||||
public final MinimapRenderer minimap = new MinimapRenderer();
|
||||
|
|
@ -55,18 +49,15 @@ public class Renderer implements ApplicationListener{
|
|||
public TextureRegion[] bubbles = new TextureRegion[16], splashes = new TextureRegion[12];
|
||||
public TextureRegion[][] fluidFrames;
|
||||
|
||||
//currently landing core, null if there are no cores or it has finished landing.
|
||||
private @Nullable CoreBuild landCore;
|
||||
private @Nullable CoreBlock launchCoreType;
|
||||
private Color clearColor = new Color(0f, 0f, 0f, 1f);
|
||||
private float
|
||||
//seed for cloud visuals, 0-1
|
||||
cloudSeed = 0f,
|
||||
//target camera scale that is lerp-ed to
|
||||
targetscale = Scl.scl(4),
|
||||
//current actual camera scale
|
||||
camerascale = targetscale,
|
||||
//minimum camera zoom value for landing/launching; constant TODO make larger?
|
||||
minZoomScl = Scl.scl(0.02f),
|
||||
//starts at coreLandDuration, ends at 0. if positive, core is landing.
|
||||
landTime,
|
||||
//timer for core landing particles
|
||||
|
|
@ -113,10 +104,6 @@ public class Renderer implements ApplicationListener{
|
|||
setupBloom();
|
||||
}
|
||||
|
||||
Events.run(Trigger.newGame, () -> {
|
||||
landCore = player.bestCore();
|
||||
});
|
||||
|
||||
EnvRenderers.init();
|
||||
for(int i = 0; i < bubbles.length; i++) bubbles[i] = atlas.find("bubble-" + i);
|
||||
for(int i = 0; i < splashes.length; i++) splashes[i] = atlas.find("splash-" + i);
|
||||
|
|
@ -181,32 +168,26 @@ public class Renderer implements ApplicationListener{
|
|||
enableEffects = settings.getBool("effects");
|
||||
drawDisplays = !settings.getBool("hidedisplays");
|
||||
drawLight = settings.getBool("drawlight", true);
|
||||
pixelate = Core.settings.getBool("pixelate");
|
||||
pixelate = settings.getBool("pixelate");
|
||||
|
||||
//don't bother drawing landing animation if core is null
|
||||
if(landCore == null) landTime = 0f;
|
||||
if(landTime > 0){
|
||||
if(!state.isPaused()){
|
||||
CoreBuild build = landCore == null ? player.bestCore() : landCore;
|
||||
if(build != null){
|
||||
build.updateLandParticles();
|
||||
}
|
||||
}
|
||||
if(!state.isPaused()) landCore.updateLaunching();
|
||||
|
||||
if(!state.isPaused()){
|
||||
landTime -= Time.delta;
|
||||
}
|
||||
float fin = landTime / coreLandDuration;
|
||||
if(!launching) fin = 1f - fin;
|
||||
camerascale = landInterp.apply(minZoomScl, Scl.scl(4f), fin);
|
||||
weatherAlpha = 0f;
|
||||
camerascale = landCore.zoomLaunching();
|
||||
|
||||
//snap camera to cutscene core regardless of player input
|
||||
if(landCore != null){
|
||||
camera.position.set(landCore);
|
||||
}
|
||||
if(!state.isPaused()) landTime -= Time.delta;
|
||||
}else{
|
||||
weatherAlpha = Mathf.lerpDelta(weatherAlpha, 1f, 0.08f);
|
||||
}
|
||||
|
||||
if(landCore != null && landTime <= 0f){
|
||||
landCore.endLaunch();
|
||||
landCore = null;
|
||||
}
|
||||
|
||||
camera.width = graphics.getWidth() / camerascale;
|
||||
camera.height = graphics.getHeight() / camerascale;
|
||||
|
||||
|
|
@ -304,7 +285,7 @@ public class Renderer implements ApplicationListener{
|
|||
graphics.clear(clearColor);
|
||||
Draw.reset();
|
||||
|
||||
if(Core.settings.getBool("animatedwater") || animateShields){
|
||||
if(settings.getBool("animatedwater") || animateShields){
|
||||
effectBuffer.resize(graphics.getWidth(), graphics.getHeight());
|
||||
}
|
||||
|
||||
|
|
@ -393,7 +374,10 @@ public class Renderer implements ApplicationListener{
|
|||
|
||||
Draw.draw(Layer.overlayUI, overlays::drawTop);
|
||||
if(state.rules.fog) Draw.draw(Layer.fogOfWar, fog::drawFog);
|
||||
Draw.draw(Layer.space, this::drawLanding);
|
||||
Draw.draw(Layer.space, () -> {
|
||||
if(landCore == null || landTime <= 0f) return;
|
||||
landCore.drawLanding(launching && launchCoreType != null ? launchCoreType : (CoreBlock)landCore.block);
|
||||
});
|
||||
|
||||
Events.fire(Trigger.drawOver);
|
||||
blocks.drawBlocks();
|
||||
|
|
@ -481,61 +465,6 @@ public class Renderer implements ApplicationListener{
|
|||
if(state.rules.customBackgroundCallback != null && customBackgrounds.containsKey(state.rules.customBackgroundCallback)){
|
||||
customBackgrounds.get(state.rules.customBackgroundCallback).run();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
if(launching) fout = 1f - fout;
|
||||
float fin = 1f - fout;
|
||||
float scl = Scl.scl(4f) / camerascale;
|
||||
float pfin = Interp.pow3Out.apply(fin), pf = Interp.pow2In.apply(fout);
|
||||
|
||||
//draw particles
|
||||
Draw.color(Pal.lightTrail);
|
||||
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();
|
||||
|
||||
CoreBlock block = launching && launchCoreType != null ? launchCoreType : (CoreBlock)build.block;
|
||||
block.drawLanding(build, build.x, build.y);
|
||||
|
||||
Draw.color();
|
||||
Draw.mixcol(Color.white, Interp.pow5In.apply(fout));
|
||||
|
||||
//accent tint indicating that the core was just constructed
|
||||
if(launching){
|
||||
float f = Mathf.clamp(1f - fout * 12f);
|
||||
if(f > 0.001f){
|
||||
Draw.mixcol(Pal.accent, f);
|
||||
}
|
||||
}
|
||||
|
||||
//draw clouds
|
||||
if(state.rules.cloudColor.a > 0.0001f){
|
||||
float scaling = cloudScaling;
|
||||
float sscl = Math.max(1f + Mathf.clamp(fin + cfinOffset)* cfinScl, 0f) * camerascale;
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void scaleCamera(float amount){
|
||||
|
|
@ -580,6 +509,13 @@ public class Renderer implements ApplicationListener{
|
|||
return landTime;
|
||||
}
|
||||
|
||||
public float getLandTimeIn(){
|
||||
if(landCore == null) return 0f;
|
||||
float fin = landTime / landCore.landDuration();
|
||||
if(!launching) fin = 1f - fin;
|
||||
return fin;
|
||||
}
|
||||
|
||||
public float getLandPTimer(){
|
||||
return landPTimer;
|
||||
}
|
||||
|
|
@ -588,25 +524,37 @@ public class Renderer implements ApplicationListener{
|
|||
this.landPTimer = landPTimer;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void showLanding(){
|
||||
launching = false;
|
||||
camerascale = minZoomScl;
|
||||
landTime = coreLandDuration;
|
||||
cloudSeed = Mathf.random(1f);
|
||||
var core = player.bestCore();
|
||||
if(core != null) showLanding(core);
|
||||
}
|
||||
|
||||
public void showLanding(CoreBuild landCore){
|
||||
this.landCore = landCore;
|
||||
launching = false;
|
||||
landTime = landCore.landDuration();
|
||||
|
||||
landCore.beginLaunch(null);
|
||||
camerascale = landCore.zoomLaunching();
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void showLaunch(CoreBlock coreType){
|
||||
Vars.ui.hudfrag.showLaunch();
|
||||
Vars.control.input.config.hideConfig();
|
||||
Vars.control.input.inv.hide();
|
||||
launchCoreType = coreType;
|
||||
var core = player.team().core();
|
||||
if(core != null) showLaunch(core, coreType);
|
||||
}
|
||||
|
||||
public void showLaunch(CoreBuild landCore, CoreBlock coreType){
|
||||
control.input.config.hideConfig();
|
||||
control.input.inv.hide();
|
||||
|
||||
this.landCore = landCore;
|
||||
launching = true;
|
||||
landCore = player.team().core();
|
||||
cloudSeed = Mathf.random(1f);
|
||||
landTime = coreLandDuration;
|
||||
if(landCore != null){
|
||||
Fx.coreLaunchConstruct.at(landCore.x, landCore.y, coreType.size);
|
||||
}
|
||||
landTime = landCore.landDuration();
|
||||
launchCoreType = coreType;
|
||||
|
||||
landCore.beginLaunch(coreType);
|
||||
}
|
||||
|
||||
public void takeMapScreenshot(){
|
||||
|
|
@ -648,7 +596,7 @@ public class Renderer implements ApplicationListener{
|
|||
Fi file = screenshotDirectory.child("screenshot-" + Time.millis() + ".png");
|
||||
PixmapIO.writePng(file, fullPixmap);
|
||||
fullPixmap.dispose();
|
||||
app.post(() -> ui.showInfoFade(Core.bundle.format("screenshot", file.toString())));
|
||||
app.post(() -> ui.showInfoFade(bundle.format("screenshot", file.toString())));
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -35,6 +35,7 @@ import mindustry.maps.*;
|
|||
import mindustry.type.*;
|
||||
import mindustry.ui.*;
|
||||
import mindustry.world.blocks.storage.*;
|
||||
import mindustry.world.blocks.storage.CoreBlock.*;
|
||||
|
||||
import static arc.Core.*;
|
||||
import static mindustry.Vars.*;
|
||||
|
|
@ -1244,7 +1245,8 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
|
|||
|
||||
Events.fire(new SectorLaunchLoadoutEvent(sector, from, loadout));
|
||||
|
||||
if(settings.getBool("skipcoreanimation")){
|
||||
CoreBuild core = player.team().core();
|
||||
if(core == null || settings.getBool("skipcoreanimation")){
|
||||
//just... go there
|
||||
control.playSector(from, sector);
|
||||
//hide only after load screen is shown
|
||||
|
|
@ -1256,9 +1258,9 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
|
|||
//allow planet dialog to finish hiding before actually launching
|
||||
Time.runTask(5f, () -> {
|
||||
Runnable doLaunch = () -> {
|
||||
renderer.showLaunch(schemCore);
|
||||
renderer.showLaunch(core, schemCore);
|
||||
//run with less delay, as the loading animation is delayed by several frames
|
||||
Time.runTask(coreLandDuration - 8f, () -> control.playSector(from, sector));
|
||||
Time.runTask(core.landDuration() - 8f, () -> control.playSector(from, sector));
|
||||
};
|
||||
|
||||
//load launchFrom sector right before launching so animation is correct
|
||||
|
|
@ -1276,7 +1278,6 @@ public class PlanetDialog extends BaseDialog implements PlanetInterfaceRenderer{
|
|||
}else if(mode == select){
|
||||
listener.get(sector);
|
||||
}else if(mode == planetLaunch){ //TODO make sure it doesn't have a base already.
|
||||
|
||||
//TODO animation
|
||||
//schematic selection and cost handled by listener
|
||||
listener.get(sector);
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@ import mindustry.input.*;
|
|||
import mindustry.net.Packets.*;
|
||||
import mindustry.type.*;
|
||||
import mindustry.ui.*;
|
||||
import mindustry.world.blocks.storage.*;
|
||||
import mindustry.world.blocks.storage.CoreBlock.*;
|
||||
|
||||
import static mindustry.Vars.*;
|
||||
import static mindustry.gen.Tex.*;
|
||||
|
|
@ -584,6 +586,8 @@ public class HudFragment{
|
|||
}
|
||||
}
|
||||
|
||||
/** @deprecated see {@link CoreBuild#beginLaunch(CoreBlock)} */
|
||||
@Deprecated
|
||||
public void showLaunch(){
|
||||
float margin = 30f;
|
||||
|
||||
|
|
@ -602,6 +606,8 @@ public class HudFragment{
|
|||
Core.scene.add(image);
|
||||
}
|
||||
|
||||
/** @deprecated see {@link CoreBuild#beginLaunch(CoreBlock)} */
|
||||
@Deprecated
|
||||
public void showLand(){
|
||||
Image image = new Image();
|
||||
image.color.a = 1f;
|
||||
|
|
|
|||
|
|
@ -1,11 +1,15 @@
|
|||
package mindustry.world.blocks.storage;
|
||||
|
||||
import arc.*;
|
||||
import arc.audio.*;
|
||||
import arc.func.*;
|
||||
import arc.graphics.*;
|
||||
import arc.graphics.g2d.*;
|
||||
import arc.math.*;
|
||||
import arc.math.geom.*;
|
||||
import arc.scene.actions.*;
|
||||
import arc.scene.event.*;
|
||||
import arc.scene.ui.*;
|
||||
import arc.scene.ui.layout.*;
|
||||
import arc.struct.*;
|
||||
import arc.util.*;
|
||||
|
|
@ -29,6 +33,9 @@ import mindustry.world.modules.*;
|
|||
import static mindustry.Vars.*;
|
||||
|
||||
public class CoreBlock extends StorageBlock{
|
||||
protected static final float cloudScaling = 1700f, cfinScl = -2f, cfinOffset = 0.3f, calphaFinOffset = 0.25f, cloudAlpha = 0.81f;
|
||||
protected static final float[] cloudAlphas = {0, 0.5f, 1f, 0.1f, 0, 0f};
|
||||
|
||||
//hacky way to pass item modules between methods
|
||||
private static ItemModule nextItems;
|
||||
protected static final float[] thrusterSizes = {0f, 0f, 0f, 0f, 0.3f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 1f, 0f};
|
||||
|
|
@ -42,6 +49,12 @@ public class CoreBlock extends StorageBlock{
|
|||
public boolean incinerateNonBuildable = false;
|
||||
|
||||
public UnitType unitType = UnitTypes.alpha;
|
||||
public float landDuration = 160f;
|
||||
public Music landMusic = Musics.land;
|
||||
public Effect launchEffect = Fx.launch;
|
||||
|
||||
public Interp landZoomInterp = Interp.pow3;
|
||||
public float landZoomFrom = 0.02f, landZoomTo = 4f;
|
||||
|
||||
public float captureInvicibility = 60f * 15f;
|
||||
|
||||
|
|
@ -217,11 +230,8 @@ public class CoreBlock extends StorageBlock{
|
|||
}
|
||||
|
||||
public void drawLanding(CoreBuild build, float x, float y){
|
||||
float fout = renderer.getLandTime() / coreLandDuration;
|
||||
|
||||
if(renderer.isLaunching()) fout = 1f - fout;
|
||||
|
||||
float fin = 1f - fout;
|
||||
float fin = renderer.getLandTimeIn();
|
||||
float fout = 1f - fin;
|
||||
|
||||
float scl = Scl.scl(4f) / renderer.getDisplayScale();
|
||||
float shake = 0f;
|
||||
|
|
@ -312,6 +322,17 @@ public class CoreBlock extends StorageBlock{
|
|||
public float iframes = -1f;
|
||||
public float thrusterTime = 0f;
|
||||
|
||||
protected float cloudSeed;
|
||||
|
||||
//utility methods for less Block-to-CoreBlock casts. also allows for more customization
|
||||
public float landDuration(){
|
||||
return landDuration;
|
||||
}
|
||||
|
||||
public Music landMusic(){
|
||||
return landMusic;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void draw(){
|
||||
//draw thrusters when just landed
|
||||
|
|
@ -331,6 +352,115 @@ public class CoreBlock extends StorageBlock{
|
|||
}
|
||||
}
|
||||
|
||||
// `launchType` is null if it's landing instead of launching.
|
||||
public void beginLaunch(@Nullable CoreBlock launchType){
|
||||
cloudSeed = Mathf.random(1f);
|
||||
if(launchType != null){
|
||||
Fx.coreLaunchConstruct.at(x, y, launchType.size);
|
||||
}
|
||||
|
||||
if(!headless){
|
||||
// Add fade-in and fade-out foreground when landing or launching.
|
||||
if(renderer.isLaunching()){
|
||||
float margin = 30f;
|
||||
|
||||
Image image = new Image();
|
||||
image.color.a = 0f;
|
||||
image.touchable = Touchable.disabled;
|
||||
image.setFillParent(true);
|
||||
image.actions(Actions.delay((landDuration() - margin) / 60f), Actions.fadeIn(margin / 60f, Interp.pow2In), Actions.delay(6f / 60f), Actions.remove());
|
||||
image.update(() -> {
|
||||
image.toFront();
|
||||
ui.loadfrag.toFront();
|
||||
if(state.isMenu()){
|
||||
image.remove();
|
||||
}
|
||||
});
|
||||
Core.scene.add(image);
|
||||
}else{
|
||||
Image image = new Image();
|
||||
image.color.a = 1f;
|
||||
image.touchable = Touchable.disabled;
|
||||
image.setFillParent(true);
|
||||
image.actions(Actions.fadeOut(35f / 60f), Actions.remove());
|
||||
image.update(() -> {
|
||||
image.toFront();
|
||||
ui.loadfrag.toFront();
|
||||
if(state.isMenu()){
|
||||
image.remove();
|
||||
}
|
||||
});
|
||||
Core.scene.add(image);
|
||||
|
||||
Time.run(landDuration(), () -> {
|
||||
launchEffect.at(this);
|
||||
Effect.shake(5f, 5f, this);
|
||||
thrusterTime = 1f;
|
||||
|
||||
if(state.isCampaign() && Vars.showSectorLandInfo && (state.rules.sector.preset == null || state.rules.sector.preset.showSectorLandInfo)){
|
||||
ui.announce("[accent]" + state.rules.sector.name() + "\n" +
|
||||
(state.rules.sector.info.resources.any() ? "[lightgray]" + Core.bundle.get("sectors.resources") + "[white] " +
|
||||
state.rules.sector.info.resources.toString(" ", UnlockableContent::emoji) : ""), 5);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void endLaunch(){}
|
||||
|
||||
public void drawLanding(CoreBlock block){
|
||||
var clouds = Core.assets.get("sprites/clouds.png", Texture.class);
|
||||
|
||||
float fin = renderer.getLandTimeIn();
|
||||
float cameraScl = renderer.getDisplayScale();
|
||||
|
||||
float fout = 1f - fin;
|
||||
float scl = Scl.scl(4f) / cameraScl;
|
||||
float pfin = Interp.pow3Out.apply(fin), pf = Interp.pow2In.apply(fout);
|
||||
|
||||
//draw particles
|
||||
Draw.color(Pal.lightTrail);
|
||||
Angles.randLenVectors(1, pfin, 100, 800f * scl * pfin, (ax, ay, ffin, ffout) -> {
|
||||
Lines.stroke(scl * ffin * pf * 3f);
|
||||
Lines.lineAngle(x + ax, y + ay, Mathf.angle(ax, ay), (ffin * 20 + 1f) * scl);
|
||||
});
|
||||
Draw.color();
|
||||
|
||||
block.drawLanding(this, x, y);
|
||||
|
||||
Draw.color();
|
||||
Draw.mixcol(Color.white, Interp.pow5In.apply(fout));
|
||||
|
||||
//accent tint indicating that the core was just constructed
|
||||
if(renderer.isLaunching()){
|
||||
float f = Mathf.clamp(1f - fout * 12f);
|
||||
if(f > 0.001f){
|
||||
Draw.mixcol(Pal.accent, f);
|
||||
}
|
||||
}
|
||||
|
||||
//draw clouds
|
||||
if(state.rules.cloudColor.a > 0.0001f){
|
||||
float scaling = cloudScaling;
|
||||
float sscl = Math.max(1f + Mathf.clamp(fin + cfinOffset) * cfinScl, 0f) * cameraScl;
|
||||
|
||||
Tmp.tr1.set(clouds);
|
||||
Tmp.tr1.set(
|
||||
(Core.camera.position.x - Core.camera.width/2f * sscl) / scaling,
|
||||
(Core.camera.position.y - Core.camera.height/2f * sscl) / scaling,
|
||||
(Core.camera.position.x + Core.camera.width/2f * sscl) / scaling,
|
||||
(Core.camera.position.y + Core.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, Core.camera.position.x, Core.camera.position.y, Core.camera.width, Core.camera.height);
|
||||
Draw.reset();
|
||||
}
|
||||
}
|
||||
|
||||
public void drawThrusters(float frame){
|
||||
float length = thrusterLength * (frame - 1f) - 1f/4f;
|
||||
for(int i = 0; i < 4; i++){
|
||||
|
|
@ -409,9 +539,19 @@ public class CoreBlock extends StorageBlock{
|
|||
thrusterTime -= Time.delta/90f;
|
||||
}
|
||||
|
||||
/** @return Camera zoom while landing or launching. May optionally do other things such as setting camera position to itself. */
|
||||
public float zoomLaunching(){
|
||||
Core.camera.position.set(this);
|
||||
return landZoomInterp.apply(Scl.scl(landZoomFrom), Scl.scl(landZoomTo), renderer.getLandTimeIn());
|
||||
}
|
||||
|
||||
public void updateLaunching(){
|
||||
updateLandParticles();
|
||||
}
|
||||
|
||||
public void updateLandParticles(){
|
||||
float time = renderer.isLaunching() ? coreLandDuration - renderer.getLandTime() : renderer.getLandTime();
|
||||
float tsize = Mathf.sample(thrusterSizes, (time + 35f) / coreLandDuration);
|
||||
float in = renderer.getLandTimeIn() * landDuration();
|
||||
float tsize = Mathf.sample(thrusterSizes, (in + 35f) / landDuration());
|
||||
|
||||
renderer.setLandPTimer(renderer.getLandPTimer() + tsize * Time.delta);
|
||||
if(renderer.getLandTime() >= 1f){
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue