Compare commits

...

2 Commits

Author SHA1 Message Date
Brian Fertig 0c416f362b feat(mastermind): improve UI layout and enhance peg reveal animation
- Relocate Leave button to the bottom of the game screen
- Extend peg reveal animation duration to 2.3s with smoother tick timing
- Introduce MASTERMIND_CALCULATE sound effect to play during the reveal
- Update audio preload and SFX registry to support the new sound
2026-05-31 10:19:42 -06:00
Brian Fertig 13b9d0d1cc Turn arrow placement 2026-05-31 10:01:18 -06:00
4 changed files with 15 additions and 8 deletions

Binary file not shown.

View File

@ -43,8 +43,9 @@ const DEPTH = {
};
// ── Layout ───────────────────────────────────────────────────────────────────
const PANEL_TOP = 200; // top of each trace panel frame
const SECRET_Y = PANEL_TOP + 50; // secret-code row inside the panel header
const PANEL_TOP = 200; // top of each trace panel frame
const SECRET_Y = PANEL_TOP + 50; // secret-code row inside the panel header
const TURN_ARROW_Y = SECRET_Y + 300; // yellow turn-indicator arrow
const ROWS_TOP = PANEL_TOP + 100; // first guess row
const ROW_H = 46;
const PEG_R = 16;
@ -87,7 +88,7 @@ export default class MastermindGame extends Phaser.Scene {
this.rightLayer = this.add.container(0, 0).setDepth(DEPTH.rows);
this.composeLayer = this.add.container(0, 0).setDepth(DEPTH.compose);
new Button(this, GAME_WIDTH - 120, 60, 'Leave', () => this.scene.start('GameMenu'), {
new Button(this, GAME_WIDTH - 120, GAME_HEIGHT - 60, 'Leave', () => this.scene.start('GameMenu'), {
variant: 'ghost', width: 160, height: 46, fontSize: 20,
}).setDepth(DEPTH.ui);
@ -206,7 +207,7 @@ export default class MastermindGame extends Phaser.Scene {
'user-select:none',
].join(';');
this._turnArrowEl = el;
this.turnArrow = this.add.dom(GAME_WIDTH / 2, SECRET_Y, el).setVisible(false);
this.turnArrow = this.add.dom(GAME_WIDTH / 2, TURN_ARROW_Y, el).setVisible(false);
}
// Point the arrow toward the active panel and pulse it back and forth that way.
@ -216,7 +217,7 @@ export default class MastermindGame extends Phaser.Scene {
const baseX = GAME_WIDTH / 2;
const left = side === 'player';
this._turnArrowEl.textContent = left ? '◀' : '▶';
this.turnArrow.setVisible(true).setPosition(baseX, SECRET_Y).setScale(1);
this.turnArrow.setVisible(true).setPosition(baseX, TURN_ARROW_Y).setScale(1);
this._turnTween = this.tweens.add({
targets: this.turnArrow,
x: baseX + (left ? -22 : 22),
@ -595,10 +596,14 @@ export default class MastermindGame extends Phaser.Scene {
this.fxLayer.add(peg);
pegsObjs.push(peg);
}
// 2.3 seconds total: 32 ticks at ~72ms each
const totalDuration = 2300;
const tickInterval = totalDuration / 32;
playSound(this, SFX.MASTERMIND_CALCULATE);
let ticks = 0;
const maxTicks = 9;
const maxTicks = 32;
const ev = this.time.addEvent({
delay: 70, repeat: maxTicks,
delay: tickInterval, repeat: maxTicks,
callback: () => {
ticks++;
pegsObjs.forEach((p, c) => {

View File

@ -69,6 +69,7 @@ export default class PreloadScene extends Phaser.Scene {
this.load.audio('sfx-mastermind-access-denied', '/assets/fx/mastermind-access-denied.mp3');
this.load.audio('sfx-mastermind-color', '/assets/fx/mastermind-color.mp3');
this.load.audio('sfx-mastermind-match', '/assets/fx/mastermind-match.mp3');
this.load.audio('sfx-mastermind-calculate', '/assets/fx/mastermind-calculate.mp3');
this.load.audio('sfx-roulette', '/assets/fx/roulette.mp3');
this.load.audio('sfx-battleship-hit', '/assets/fx/battleship-hit.mp3');
this.load.audio('sfx-battleship-miss', '/assets/fx/battleship-miss.mp3');

View File

@ -24,7 +24,8 @@ export const SFX = {
MASTERMIND_GRANTED: 'sfx-mastermind-access-granted',
MASTERMIND_DENIED: 'sfx-mastermind-access-denied',
MASTERMIND_COLOR: 'sfx-mastermind-color',
MASTERMIND_MATCH: 'sfx-mastermind-match',
MASTERMIND_MATCH: 'sfx-mastermind-match',
MASTERMIND_CALCULATE: 'sfx-mastermind-calculate',
};
export function playSound(scene, key) {