Add sound effects and music to slot machine game with victory animations and stage transitions
This commit is contained in:
parent
1ca2579b64
commit
c3eba35be7
Binary file not shown.
|
After Width: | Height: | Size: 74 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -46,6 +46,10 @@ export class LossAnimation {
|
|||
// Screen tint to dark red briefly
|
||||
scene.cameras.main.flash(800, 150, 0, 0, true);
|
||||
|
||||
// Play a random no-match voice line
|
||||
const pick = Phaser.Math.Between(1, 6);
|
||||
scene.sound.play(`sfx-nomatch-${pick}`);
|
||||
|
||||
// Tween devil + money up to sin box
|
||||
scene.tweens.add({
|
||||
targets: [devilGfx, moneyText],
|
||||
|
|
|
|||
|
|
@ -64,14 +64,25 @@ export class SlotMachine {
|
|||
|
||||
const payout = win ? results[0].payout : 0;
|
||||
|
||||
// Loop the spin sound for the duration of the spin
|
||||
this._spinSound = this.scene.sound.add('sfx-spin', { loop: true });
|
||||
this._spinSound.play();
|
||||
|
||||
let doneCount = 0;
|
||||
const totalReels = this.reels.length;
|
||||
const stopDelays = [800, 1300, 1800]; // ms before each reel starts decelerating
|
||||
|
||||
this.reels.forEach((reel, i) => {
|
||||
reel.spin(results[i], stopDelays[i], () => {
|
||||
// Play a thud for each reel landing
|
||||
this.scene.sound.play('sfx-stop');
|
||||
|
||||
doneCount++;
|
||||
if (doneCount === totalReels) {
|
||||
// All reels stopped — kill the spin loop
|
||||
this._spinSound.stop();
|
||||
this._spinSound.destroy();
|
||||
this._spinSound = null;
|
||||
onComplete({ win, symbols: results, payout });
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,10 +3,17 @@ import { MatchBanner } from './MatchBanner.js';
|
|||
export class WinAnimation {
|
||||
// playerBoxCenter, lordBoxCenter: { x, y } screen positions of fund boxes
|
||||
play(scene, originX, originY, playerBoxCenter, lordBoxCenter, symbol, onComplete) {
|
||||
// Play a random match voice line as the banner appears
|
||||
scene.sound.play(`sfx-match-${Phaser.Math.Between(1, 6)}`);
|
||||
|
||||
new MatchBanner().play(scene, symbol.label, () => {
|
||||
// Flash the screen gold
|
||||
scene.cameras.main.flash(1200, 255, 215, 0, true);
|
||||
|
||||
// Loop coins sound for the duration of the coin animation
|
||||
const coinsSound = scene.sound.add('sfx-coins', { loop: true });
|
||||
coinsSound.play();
|
||||
|
||||
const totalCoins = 20;
|
||||
const playerCoins = Math.round(totalCoins * 0.6);
|
||||
const lordCoins = totalCoins - playerCoins;
|
||||
|
|
@ -165,6 +172,8 @@ export class WinAnimation {
|
|||
container.destroy();
|
||||
finished++;
|
||||
if (finished === totalCoins) {
|
||||
coinsSound.stop();
|
||||
coinsSound.destroy();
|
||||
stopPlayer();
|
||||
stopLord();
|
||||
scene.tweens.add({
|
||||
|
|
|
|||
|
|
@ -26,6 +26,22 @@ export default class BootScene extends Phaser.Scene {
|
|||
// Victory videos
|
||||
this.load.video('lord-victory', 'assets/video/lord-victory.mp4', true);
|
||||
this.load.video('sin-victory', 'assets/video/sin-victory.mp4', true);
|
||||
|
||||
// Background music
|
||||
this.load.audio('music-01-02', 'assets/music/stage-01-02.mp3');
|
||||
this.load.audio('music-03-04', 'assets/music/stage-03-04.mp3');
|
||||
this.load.audio('music-05-06', 'assets/music/stage-05-06.mp3');
|
||||
this.load.audio('music-lord-victory', 'assets/music/lord-victory.mp3');
|
||||
this.load.audio('music-sin-victory', 'assets/music/sin-victory.mp3');
|
||||
|
||||
// Sound effects
|
||||
this.load.audio('sfx-spin', 'assets/fx/spin.mp3');
|
||||
this.load.audio('sfx-stop', 'assets/fx/stop.mp3');
|
||||
for (let i = 1; i <= 6; i++) {
|
||||
this.load.audio(`sfx-nomatch-${i}`, `assets/fx/nomatch${i}.mp3`);
|
||||
this.load.audio(`sfx-match-${i}`, `assets/fx/match${i}.mp3`);
|
||||
}
|
||||
this.load.audio('sfx-coins', 'assets/fx/coins.mp3');
|
||||
}
|
||||
|
||||
create() {
|
||||
|
|
|
|||
|
|
@ -23,6 +23,8 @@ export default class GameScene extends Phaser.Scene {
|
|||
this._currentStage = 2;
|
||||
this._activeVideo = null;
|
||||
this._gameOver = false;
|
||||
this._currentMusicKey = null;
|
||||
this._musicSound = null;
|
||||
const vidX = this._vidX;
|
||||
const vidY = this._vidY;
|
||||
const vidW = this._vidW;
|
||||
|
|
@ -36,6 +38,7 @@ export default class GameScene extends Phaser.Scene {
|
|||
|
||||
// Start with the stage-02 loop (game begins at stage 2)
|
||||
this._setVideo('stage-02', true);
|
||||
this._switchMusic(this._getMusicKey(2));
|
||||
|
||||
// Gradient backdrop behind title — opaque on left, fades to transparent
|
||||
const titleBg = this.add.graphics();
|
||||
|
|
@ -101,13 +104,25 @@ export default class GameScene extends Phaser.Scene {
|
|||
if (!this._gameOver) this.slotMachine.setEnabled(true);
|
||||
}, this);
|
||||
|
||||
// Victory: play the victory video and shatter the losing vial
|
||||
// Victory: play the victory video, music, and shatter the losing vial
|
||||
this.game.events.on('vial-winner', ({ winner }) => {
|
||||
this._gameOver = true;
|
||||
const lordWins = winner.toLowerCase().includes('lord');
|
||||
const key = lordWins ? 'lord-victory' : 'sin-victory';
|
||||
this._setVideo(key, false);
|
||||
|
||||
// Fade out background music and play the victory track once
|
||||
if (this._musicSound) {
|
||||
const outgoing = this._musicSound;
|
||||
this._musicSound = null;
|
||||
this._currentMusicKey = null;
|
||||
this.tweens.add({
|
||||
targets: outgoing, volume: 0, duration: 1000,
|
||||
onComplete: () => { outgoing.stop(); outgoing.destroy(); },
|
||||
});
|
||||
}
|
||||
this.sound.play(lordWins ? 'music-lord-victory' : 'music-sin-victory');
|
||||
|
||||
// Shatter the losing vial after a brief dramatic pause
|
||||
this.time.delayedCall(550, () => {
|
||||
if (lordWins) {
|
||||
|
|
@ -250,6 +265,8 @@ export default class GameScene extends Phaser.Scene {
|
|||
const oldStage = this._currentStage;
|
||||
this._currentStage = newStage;
|
||||
|
||||
this._switchMusic(this._getMusicKey(newStage));
|
||||
|
||||
const pad = n => String(n).padStart(2, '0');
|
||||
const direction = newStage > oldStage ? 1 : -1;
|
||||
const transitions = [];
|
||||
|
|
@ -261,4 +278,33 @@ export default class GameScene extends Phaser.Scene {
|
|||
if (!this._gameOver) this._setVideo(`stage-${pad(newStage)}`, true);
|
||||
});
|
||||
}
|
||||
|
||||
/** Map a stage number to its music track key. */
|
||||
_getMusicKey(stage) {
|
||||
if (stage <= 2) return 'music-01-02';
|
||||
if (stage <= 4) return 'music-03-04';
|
||||
return 'music-05-06';
|
||||
}
|
||||
|
||||
/** Crossfade from the current music track to newKey (no-op if already playing). */
|
||||
_switchMusic(newKey) {
|
||||
if (newKey === this._currentMusicKey) return;
|
||||
this._currentMusicKey = newKey;
|
||||
|
||||
// Fade out and destroy the outgoing track
|
||||
if (this._musicSound) {
|
||||
const outgoing = this._musicSound;
|
||||
this.tweens.add({
|
||||
targets: outgoing,
|
||||
volume: 0,
|
||||
duration: 1000,
|
||||
onComplete: () => { outgoing.stop(); outgoing.destroy(); },
|
||||
});
|
||||
}
|
||||
|
||||
// Fade in the incoming track from silence
|
||||
this._musicSound = this.sound.add(newKey, { loop: true, volume: 0 });
|
||||
this._musicSound.play();
|
||||
this.tweens.add({ targets: this._musicSound, volume: 1, duration: 1000 });
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue