diff --git a/src/scenes/GameMenuScene.js b/src/scenes/GameMenuScene.js index a335ea6..8f660b2 100644 --- a/src/scenes/GameMenuScene.js +++ b/src/scenes/GameMenuScene.js @@ -27,6 +27,16 @@ const GRID_TRAVEL = GAME_WIDTH + 800; export default class GameMenuScene extends Phaser.Scene { constructor() { super('GameMenu'); } + init(data) { + // Set when coming back from the opponent picker — restore that category. + this._initialCategory = (data && data.category) || null; + // scene.start() reuses the existing scene instance, so instance props from + // the previous visit survive — reset them so this create() starts clean + // (otherwise showCategory()'s "same category" guard swallows the restore). + this._currentCategory = null; + this._gridAnim = null; + } + async create() { playMenuMusic(); const cx = GAME_WIDTH / 2; @@ -121,9 +131,15 @@ export default class GameMenuScene extends Phaser.Scene { this._backBtn = new Button(this, cx, GAME_HEIGHT - 60, 'Back', () => this.scene.start('Landing'), { variant: 'ghost' }); + // Returning from the opponent picker: restore the category that was + // active when the game was chosen — its grid flies back in from the right. + if (this._initialCategory) { + this.showCategory(this._initialCategory); + } + // The landing scene zooms the logo out before starting us, so fade the // menu controls in to complete the handoff. - const fadeIn = [...Object.values(this._tabs), ...Object.values(this._tabIcons), this._hintText, this._backBtn]; + const fadeIn = [...Object.values(this._tabs), ...Object.values(this._tabIcons), this._hintText, this._backBtn].filter(Boolean); for (const obj of fadeIn) obj.setAlpha(0); this.tweens.add({ targets: fadeIn, diff --git a/src/scenes/OpponentSelectScene.js b/src/scenes/OpponentSelectScene.js index 1ffa67f..4b1eb9b 100644 --- a/src/scenes/OpponentSelectScene.js +++ b/src/scenes/OpponentSelectScene.js @@ -1,6 +1,7 @@ import * as Phaser from 'phaser'; import { GAME_HEIGHT, GAME_WIDTH, COLORS } from '../config.js'; import { Button } from '../ui/Button.js'; +import { Plaque } from '../ui/Plaque.js'; import { playMenuMusic, stopMenuMusic, setMenuMusicVolume } from '../ui/MenuMusic.js'; import { enqueue as enqueueSpeech, resetQueue as resetSpeechQueue } from '../ui/SpeechQueue.js'; @@ -17,8 +18,8 @@ const CARD_TILE_GAP = 14; // Opponent grid scroll area const OPP_SCROLL_W = 1780; -const OPP_SCROLL_H = 440; -const OPP_SCROLL_TOP = 155; // top edge of scroll area +const OPP_SCROLL_H = 415; +const OPP_SCROLL_TOP = 180; // top edge of scroll area (below the subtitle plaque) export default class OpponentSelectScene extends Phaser.Scene { constructor() { super('OpponentSelect'); } @@ -58,21 +59,32 @@ export default class OpponentSelectScene extends Phaser.Scene { this.add.image(cx, GAME_HEIGHT / 2, bgKey).setDisplaySize(GAME_WIDTH, GAME_HEIGHT).setDepth(-1); this.add.rectangle(cx, GAME_HEIGHT / 2, GAME_WIDTH, GAME_HEIGHT, 0x000000, 0.45).setDepth(-1); - const titleText = this.add.text(cx, 60, this.gameDef.name, { + // Brass-plaque headers, same treatment as the game menu headings. The + // subtitle plaque sits in the band between the title plaque and the + // opponent list (OPP_SCROLL_TOP) — keep those in sync if you move either. + const TITLE_Y = 55; + const PLATE_GAP = 10; + const titleText = this.add.text(cx, TITLE_Y, this.gameDef.name, { fontFamily: 'Righteous', fontSize: '52px', color: COLORS.textHex, }).setOrigin(0.5); - const titlePill = this.add.rectangle(cx, 60, titleText.width + 48, titleText.height + 20, 0x000000, 0.72); - this.children.moveBelow(titlePill, titleText); + titleText.setLetterSpacing(2); + titleText.setShadow(0, 4, 'rgba(0,0,0,0.9)', 8); + const titlePlate = new Plaque(this, titleText.width + 64, titleText.height + 28).setPosition(cx, TITLE_Y); + this.children.moveBelow(titlePlate, titleText); - const subtitleText = this.add.text(cx, 122, 'Choose your opponent', { + const subtitleText = this.add.text(cx, 0, 'Choose your opponent', { fontFamily: 'Righteous', fontSize: '36px', color: COLORS.mutedHex, }).setOrigin(0.5); - const subtitlePill = this.add.rectangle(cx, 122, subtitleText.width + 48, subtitleText.height + 20, 0x000000, 0.72); - this.children.moveBelow(subtitlePill, subtitleText); + subtitleText.setShadow(0, 3, 'rgba(0,0,0,0.8)', 5); + const subPlateH = subtitleText.height + 28; + const subtitleY = TITLE_Y + (titleText.height + 28) / 2 + PLATE_GAP + subPlateH / 2; + subtitleText.setY(subtitleY); + const subtitlePlate = new Plaque(this, subtitleText.width + 64, subPlateH, { radius: 16 }).setPosition(cx, subtitleY); + this.children.moveBelow(subtitlePlate, subtitleText); let opponents = []; try { @@ -87,7 +99,7 @@ export default class OpponentSelectScene extends Phaser.Scene { } const min = this.gameDef.minOpponents ?? 1; - new Button(this, cx - 150, 1013, 'Back', () => this.scene.start('GameMenu'), { + new Button(this, cx - 150, 1013, 'Back', () => this.scene.start('GameMenu', { category: this.gameDef.category }), { variant: 'ghost', width: 280, });