feat(monopoly): add sound effects for payment and pawn animations
- Play sfx-monopoly-pay when rent/payment animation begins - Play sfx-piece-click when pawn/token hop animation completes - Load new audio asset and register in SFX constants
This commit is contained in:
parent
359740f4f7
commit
c8dc0a05e0
|
|
@ -708,21 +708,56 @@ export default class MonopolyGame extends Phaser.Scene {
|
||||||
if (!isHumanTurn && !auctionIsHuman) return;
|
if (!isHumanTurn && !auctionIsHuman) return;
|
||||||
if (inAuction) return; // auction panel handles its own buttons
|
if (inAuction) return; // auction panel handles its own buttons
|
||||||
|
|
||||||
const btnY0 = this.diceY + 56;
|
|
||||||
const btnW = RP_W - 20;
|
const btnW = RP_W - 20;
|
||||||
|
const BTN_H = 52;
|
||||||
|
const BTN_GAP = 10; // spacing between buttons (62 = BTN_H + BTN_GAP)
|
||||||
|
|
||||||
|
// First pass: count buttons to determine starting Y
|
||||||
|
const p = gs.players[this.humanSeat];
|
||||||
|
const phase = gs.phase;
|
||||||
|
let btnCount = 0;
|
||||||
|
|
||||||
|
if (phase === 'preroll' || phase === 'endturn') {
|
||||||
|
if (phase === 'preroll') {
|
||||||
|
if (p.jailed) {
|
||||||
|
if (p.getOutOfJailFree > 0) btnCount++;
|
||||||
|
btnCount++;
|
||||||
|
btnCount++;
|
||||||
|
} else {
|
||||||
|
btnCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (phase === 'endturn') btnCount++;
|
||||||
|
if (PURCHASABLE.some(idx =>
|
||||||
|
canBuildHouse(gs, this.humanSeat, idx) || canBuildHotel(gs, this.humanSeat, idx))) {
|
||||||
|
btnCount++;
|
||||||
|
}
|
||||||
|
if (PURCHASABLE.some(idx => {
|
||||||
|
const own = gs.board[idx];
|
||||||
|
return own?.owner === this.humanSeat && !own.mortgaged && own.houses === 0 && !own.hotel;
|
||||||
|
}) || PURCHASABLE.some(idx => {
|
||||||
|
const own = gs.board[idx];
|
||||||
|
return own?.owner === this.humanSeat && own.mortgaged &&
|
||||||
|
p.cash >= Math.ceil(SPACES[idx].mortgage * 1.1);
|
||||||
|
})) {
|
||||||
|
btnCount++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Second pass: draw buttons aligned to board bottom (BT + BS)
|
||||||
|
const boardBottom = BT + BS;
|
||||||
|
const totalBtnH = btnCount * BTN_H + (btnCount - 1) * BTN_GAP;
|
||||||
|
const btnY0 = boardBottom - totalBtnH;
|
||||||
let yOff = 0;
|
let yOff = 0;
|
||||||
const mkBtn = (label, cb, enabled=true, opts={}) => {
|
const mkBtn = (label, cb, enabled=true, opts={}) => {
|
||||||
const btn = new Button(this, RP_X + btnW/2 + 10, btnY0 + yOff, label, cb,
|
const btn = new Button(this, RP_X + btnW/2 + 10, btnY0 + yOff, label, cb,
|
||||||
{ width: btnW, height: 52, fontSize: 22, ...opts });
|
{ width: btnW, height: BTN_H, fontSize: 22, ...opts });
|
||||||
btn.setDepth(DEPTH.ui);
|
btn.setDepth(DEPTH.ui);
|
||||||
if (!enabled) btn.setEnabled(false);
|
if (!enabled) btn.setEnabled(false);
|
||||||
this.reg(btn);
|
this.reg(btn);
|
||||||
yOff += 62;
|
yOff += BTN_H + BTN_GAP;
|
||||||
};
|
};
|
||||||
|
|
||||||
const p = gs.players[this.humanSeat];
|
|
||||||
const phase = gs.phase;
|
|
||||||
|
|
||||||
if (phase === 'preroll' || phase === 'endturn') {
|
if (phase === 'preroll' || phase === 'endturn') {
|
||||||
if (phase === 'preroll') {
|
if (phase === 'preroll') {
|
||||||
if (p.jailed) {
|
if (p.jailed) {
|
||||||
|
|
@ -810,6 +845,8 @@ export default class MonopolyGame extends Phaser.Scene {
|
||||||
|
|
||||||
await this.delay(250);
|
await this.delay(250);
|
||||||
|
|
||||||
|
playSound(this, SFX.MONOPAY);
|
||||||
|
|
||||||
// Phase 3: Amount arches to receiver's panel (1200 ms), turns green, adds plus
|
// Phase 3: Amount arches to receiver's panel (1200 ms), turns green, adds plus
|
||||||
amtTxt.setText(`+$${amount.toLocaleString()}`);
|
amtTxt.setText(`+$${amount.toLocaleString()}`);
|
||||||
amtTxt.setColor('#44FF88');
|
amtTxt.setColor('#44FF88');
|
||||||
|
|
@ -1478,8 +1515,8 @@ export default class MonopolyGame extends Phaser.Scene {
|
||||||
async executeRoll(seat) {
|
async executeRoll(seat) {
|
||||||
const d1 = Math.floor(Math.random() * 6) + 1;
|
const d1 = Math.floor(Math.random() * 6) + 1;
|
||||||
const d2 = Math.floor(Math.random() * 6) + 1;
|
const d2 = Math.floor(Math.random() * 6) + 1;
|
||||||
|
playSound(this, SFX.DICE_ROLL);
|
||||||
await this.animateDice(d1, d2);
|
await this.animateDice(d1, d2);
|
||||||
playSound(this, SFX.diceRoll);
|
|
||||||
const prevPos = this.gs.players[seat].position;
|
const prevPos = this.gs.players[seat].position;
|
||||||
const wasJailed = this.gs.players[seat].jailed;
|
const wasJailed = this.gs.players[seat].jailed;
|
||||||
this.gs = rollDice(this.gs, seat, d1, d2);
|
this.gs = rollDice(this.gs, seat, d1, d2);
|
||||||
|
|
@ -1572,7 +1609,10 @@ export default class MonopolyGame extends Phaser.Scene {
|
||||||
pawn.x = inv * inv * start.x + 2 * inv * t * ctrl.x + t * t * ex;
|
pawn.x = inv * inv * start.x + 2 * inv * t * ctrl.x + t * t * ex;
|
||||||
pawn.y = inv * inv * start.y + 2 * inv * t * ctrl.y + t * t * ey;
|
pawn.y = inv * inv * start.y + 2 * inv * t * ctrl.y + t * t * ey;
|
||||||
},
|
},
|
||||||
onComplete: hopOne,
|
onComplete: () => {
|
||||||
|
playSound(this, SFX.PIECE_CLICK);
|
||||||
|
hopOne();
|
||||||
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -138,6 +138,7 @@ export default class PreloadScene extends Phaser.Scene {
|
||||||
this.load.spritesheet('monopoly-cards', '/assets/images/monopoly-cards.png', { frameWidth: 200, frameHeight: 300 });
|
this.load.spritesheet('monopoly-cards', '/assets/images/monopoly-cards.png', { frameWidth: 200, frameHeight: 300 });
|
||||||
this.load.audio('sfx-monopoly-purchase', '/assets/fx/monopoly-purchase.mp3');
|
this.load.audio('sfx-monopoly-purchase', '/assets/fx/monopoly-purchase.mp3');
|
||||||
this.load.audio('sfx-monopoly-expense', '/assets/fx/monopoly-expense.mp3');
|
this.load.audio('sfx-monopoly-expense', '/assets/fx/monopoly-expense.mp3');
|
||||||
|
this.load.audio('sfx-monopoly-pay', '/assets/fx/monopoly-pay.mp3');
|
||||||
this.load.audio('sfx-monopoly-paid', '/assets/fx/monopoly-paid.mp3');
|
this.load.audio('sfx-monopoly-paid', '/assets/fx/monopoly-paid.mp3');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,7 @@ export const SFX = {
|
||||||
SCIFI_WOOSH: 'sfx-scifi-woosh',
|
SCIFI_WOOSH: 'sfx-scifi-woosh',
|
||||||
MONOPOLY_PURCHASE: 'sfx-monopoly-purchase',
|
MONOPOLY_PURCHASE: 'sfx-monopoly-purchase',
|
||||||
MONOPOLY_EXPENSE: 'sfx-monopoly-expense',
|
MONOPOLY_EXPENSE: 'sfx-monopoly-expense',
|
||||||
|
MONOPAY: 'sfx-monopoly-pay',
|
||||||
MONOPOLY_PAID: 'sfx-monopoly-paid',
|
MONOPOLY_PAID: 'sfx-monopoly-paid',
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue