diff --git a/frontend/src/js/background_scene.ts b/frontend/src/js/background_scene.ts index 2a9fa1bedef19b2808bc9c109979937a58cddab8..551e3ec497b48d41bd7892a819d8a908f3a7044e 100644 --- a/frontend/src/js/background_scene.ts +++ b/frontend/src/js/background_scene.ts @@ -16,11 +16,29 @@ const LAYERS = { b11: "assets/background_layers/Layer_0000_9.png", }; +// prettier-ignore +const HSL_COLORS = [ + ["#170048", "#fbb468"], // 06:00 + ["#ffefd6", "#b8ffc7"], // 09:00 + ["#ffffff", "#ffffff"], // 12:00 + ["#fff9b8", "#b0ff88"], // 15:00 + ["#def3ff", "#77e176"], // 18:00 + ["#f490ff", "#fdbf7d"], // 21:00 + ["#474095", "#2d912d"], // 00:00 + ["#ff1111", "#ff9bc0"], // 03:00 +] + +const COLORS = HSL_COLORS.map((pair) => + pair.map(Phaser.Display.Color.HexStringToColor), +); + export default class BackgroundScene extends Phaser.Scene { layers: Phaser.GameObjects.TileSprite[]; + atmosphere: Phaser.Tweens.Tween; + curtain: Phaser.GameObjects.Rectangle; constructor() { - super("head"); + super("background"); this.layers = []; } @@ -28,19 +46,92 @@ export default class BackgroundScene extends Phaser.Scene { Object.entries(LAYERS).forEach(([key, path]) => this.load.image(key, path)); } + interpColor( + source: Phaser.Display.Color, + target: Phaser.Display.Color, + t: number, + ) { + return Phaser.Display.Color.GetColor( + source.red + (target.red - source.red) * t, + source.green + (target.green - source.green) * t, + source.blue + (target.blue - source.blue) * t, + ); + } + createBackground() { const scale = this.cameras.main.height / LAYERS_HEIGHT; const width = this.cameras.main.width / scale; const height = this.cameras.main.height / scale; Object.keys(LAYERS).forEach((textureKey) => { const tileSprite = this.add.tileSprite(0, 0, width, height, textureKey); - tileSprite.setOrigin(0).setScale(scale); + tileSprite.setOrigin(0).setScale(scale).setTint( + // NOTE: this is a bit lazy but meh. + this.interpColor(COLORS[0][0], COLORS[0][0], 0), + this.interpColor(COLORS[0][0], COLORS[0][0], 0), + this.interpColor(COLORS[0][1], COLORS[0][1], 0), + this.interpColor(COLORS[0][1], COLORS[0][1], 0), + ); this.layers.push(tileSprite); }); } + createAtmosphere() { + this.atmosphere = this.tweens.addCounter({ + paused: true, + from: 0, + to: 255 * (COLORS.length - 1), + duration: 20 * 60 * 1000, // 3000 * (COLORS.length - 1), + onUpdate: (tween) => { + const value = (tween.getValue() % 256) / 256; + const i = Math.floor(tween.getValue() / 256); + const f = (i + 1) % COLORS.length; + const topCol = this.interpColor(COLORS[i][0], COLORS[f][0], value); + const botCol = this.interpColor(COLORS[i][1], COLORS[f][1], value); + this.layers.forEach((layer) => + layer.setTint(topCol, topCol, botCol, botCol), + ); + }, + }); + } + + createCurtain() { + this.curtain = this.add + .rectangle( + 0, + 0, + this.cameras.main.displayWidth, + this.cameras.main.displayHeight, + 0x000000, + 1, + ) + .setAlpha(0) + .setOrigin(0, 0); + } + + dropCurtain() { + this.tweens.add({ + targets: this.curtain, + alpha: 1, + ease: "Linear", + delay: 0, + duration: 200, + }); + } + + liftCurtain() { + this.tweens.add({ + targets: this.curtain, + alpha: 0, + ease: "Linear", + delay: 0, + duration: 200, + }); + } + create() { this.createBackground(); + this.createAtmosphere(); + this.createCurtain(); // this.scale.displaySize.setAspectRatio( // this.cameras.main.width / this.cameras.main.height, // ); diff --git a/frontend/src/js/fight_scene.ts b/frontend/src/js/fight_scene.ts index d863b7c81479d18c6815087bfa2bcf77455338ac..f0325b345fb51bb08937ec192ce3c4307a830702 100644 --- a/frontend/src/js/fight_scene.ts +++ b/frontend/src/js/fight_scene.ts @@ -11,6 +11,7 @@ import * as Types from "../../../backend/src/types"; import Foe from "./foe"; import Typewriter from "./typewriter"; import HUD from "./hud"; +import BackgroundScene from "./background_scene"; const DEVICE_KEY = "OETZI/DEVICE_ID"; @@ -192,6 +193,7 @@ export default class FightScene extends Phaser.Scene { } async create(data: { music: Phaser.Sound.BaseSound }) { + (this.scene.get("background") as BackgroundScene).atmosphere.play(); this.musicSoftReplace( this.sound.add("bkg_main_1", { loop: true }), data.music, diff --git a/frontend/src/js/game_over_scene.ts b/frontend/src/js/game_over_scene.ts index 6beb770fff5b72cc85a8ce8714033c4499db218d..3af677987fcb96466a5e36994114cff3de39190a 100644 --- a/frontend/src/js/game_over_scene.ts +++ b/frontend/src/js/game_over_scene.ts @@ -1,4 +1,5 @@ import "phaser"; +import BackgroundScene from "./background_scene"; export default class GameOverScene extends Phaser.Scene { music!: Phaser.Sound.BaseSound; @@ -23,6 +24,10 @@ export default class GameOverScene extends Phaser.Scene { } create(data: { music?: Phaser.Sound.BaseSound }) { + (this.scene.get("background") as BackgroundScene).dropCurtain(); + (this.scene.get("background") as BackgroundScene).atmosphere + .stop() + .restart(); this.musicHardReplace( this.sound.add("bkg_failure", { loop: false }), data.music, @@ -65,6 +70,7 @@ export default class GameOverScene extends Phaser.Scene { } startFight() { + (this.scene.get("background") as BackgroundScene).liftCurtain(); this.scene.start("welcome", { music: this.music }); } }