refactor: restructure game menu with two-row tab layout
- Split category tabs into two rows: row 1 (tabletop, cards, casino, word), row 2 (logic) for better screen real estate - Move title text and adjust vertical positioning to accommodate tabs - Center row 2 tabs independently based on active categories - Update game grid top position to 370px for proper spacing - Update game-icons and tab-icons assets for new layout
This commit is contained in:
parent
3d3d09a9fb
commit
58f72e3d91
Binary file not shown.
|
Before Width: | Height: | Size: 189 KiB After Width: | Height: | Size: 191 KiB |
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 88 KiB After Width: | Height: | Size: 116 KiB |
Binary file not shown.
|
|
@ -32,12 +32,12 @@ export default class GameMenuScene extends Phaser.Scene {
|
||||||
this.add.image(cx, GAME_HEIGHT / 2, 'bg-menu').setDisplaySize(GAME_WIDTH, GAME_HEIGHT);
|
this.add.image(cx, GAME_HEIGHT / 2, 'bg-menu').setDisplaySize(GAME_WIDTH, GAME_HEIGHT);
|
||||||
addFullscreenButton(this);
|
addFullscreenButton(this);
|
||||||
|
|
||||||
const titleText = this.add.text(cx, 120, 'Choose a game', {
|
const titleText = this.add.text(cx, 60, 'Choose a game', {
|
||||||
fontFamily: 'Righteous',
|
fontFamily: 'Righteous',
|
||||||
fontSize: '64px',
|
fontSize: '64px',
|
||||||
color: COLORS.textHex,
|
color: COLORS.textHex,
|
||||||
}).setOrigin(0.5).setDepth(1);
|
}).setOrigin(0.5).setDepth(1);
|
||||||
this.add.rectangle(cx, 120, titleText.width + 64, titleText.height + 28, 0x000000, 0.7);
|
this.add.rectangle(cx, 60, titleText.width + 64, titleText.height + 28, 0x000000, 0.7);
|
||||||
|
|
||||||
const loadingText = this.add.text(cx, 540, 'Loading game list…', {
|
const loadingText = this.add.text(cx, 540, 'Loading game list…', {
|
||||||
fontSize: '24px', color: COLORS.mutedHex,
|
fontSize: '24px', color: COLORS.mutedHex,
|
||||||
|
|
@ -61,12 +61,20 @@ export default class GameMenuScene extends Phaser.Scene {
|
||||||
this._gameObjects = [];
|
this._gameObjects = [];
|
||||||
this._tabs = {};
|
this._tabs = {};
|
||||||
|
|
||||||
const activeCats = CATEGORIES.filter(({ key }) => this._gamesByCategory[key].length > 0);
|
// Two-row tab layout: row 1 has 4 categories, row 2 has the rest
|
||||||
const tabSpacing = Math.min(420, 1800 / activeCats.length);
|
const ROW1_KEYS = ['tabletop', 'cards', 'casino', 'word'];
|
||||||
const tabStartX = cx - (tabSpacing * (activeCats.length - 1)) / 2;
|
const ROW2_KEYS = ['logic'];
|
||||||
|
const ROW1 = CATEGORIES.filter(c => ROW1_KEYS.includes(c.key));
|
||||||
|
const ROW2 = CATEGORIES.filter(c => ROW2_KEYS.includes(c.key));
|
||||||
|
const activeRow1 = ROW1.filter(({ key }) => this._gamesByCategory[key].length > 0);
|
||||||
|
const activeRow2 = ROW2.filter(({ key }) => this._gamesByCategory[key].length > 0);
|
||||||
|
|
||||||
activeCats.forEach(({ key, label }, i) => {
|
const tabSpacing = Math.min(420, 1800 / activeRow1.length);
|
||||||
const btn = new Button(this, tabStartX + i * tabSpacing, 230, label, () => this.showCategory(key), {
|
const tabStartX = cx - (tabSpacing * (activeRow1.length - 1)) / 2;
|
||||||
|
|
||||||
|
// Row 1 tabs
|
||||||
|
activeRow1.forEach(({ key, label }, i) => {
|
||||||
|
const btn = new Button(this, tabStartX + i * tabSpacing, 170, label, () => this.showCategory(key), {
|
||||||
width: 390,
|
width: 390,
|
||||||
variant: 'ghost',
|
variant: 'ghost',
|
||||||
});
|
});
|
||||||
|
|
@ -74,8 +82,23 @@ export default class GameMenuScene extends Phaser.Scene {
|
||||||
this._tabs[key] = btn;
|
this._tabs[key] = btn;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Row 2 tabs (centered)
|
||||||
|
if (activeRow2.length > 0) {
|
||||||
|
const row2Spacing = Math.min(420, 1800 / activeRow2.length);
|
||||||
|
const row2StartX = cx - (row2Spacing * (activeRow2.length - 1)) / 2;
|
||||||
|
activeRow2.forEach(({ key, label }, i) => {
|
||||||
|
const btn = new Button(this, row2StartX + i * row2Spacing, 250, label, () => this.showCategory(key), {
|
||||||
|
width: 390,
|
||||||
|
variant: 'ghost',
|
||||||
|
});
|
||||||
|
btn.text.setX(40);
|
||||||
|
this._tabs[key] = btn;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
this._tabIcons = {};
|
this._tabIcons = {};
|
||||||
activeCats.forEach(({ key }) => {
|
const allActiveCats = [...activeRow1, ...activeRow2];
|
||||||
|
allActiveCats.forEach(({ key }) => {
|
||||||
const btn = this._tabs[key];
|
const btn = this._tabs[key];
|
||||||
const icon = this.add.image(btn.x + ICON_X_OFFSET, btn.y, 'tab-icons', TAB_ICON_FRAMES[key])
|
const icon = this.add.image(btn.x + ICON_X_OFFSET, btn.y, 'tab-icons', TAB_ICON_FRAMES[key])
|
||||||
.setDisplaySize(ICON_INACTIVE, ICON_INACTIVE);
|
.setDisplaySize(ICON_INACTIVE, ICON_INACTIVE);
|
||||||
|
|
@ -83,7 +106,7 @@ export default class GameMenuScene extends Phaser.Scene {
|
||||||
this._tabIcons[key] = icon;
|
this._tabIcons[key] = icon;
|
||||||
});
|
});
|
||||||
|
|
||||||
const startKey = activeCats.find(c => c.key === _lastCategory) ? _lastCategory : activeCats[0].key;
|
const startKey = allActiveCats.find(c => c.key === _lastCategory) ? _lastCategory : allActiveCats[0].key;
|
||||||
this.showCategory(startKey);
|
this.showCategory(startKey);
|
||||||
|
|
||||||
new Button(this, cx, GAME_HEIGHT - 100, 'Back', () => this.scene.start('Landing'), { variant: 'ghost' });
|
new Button(this, cx, GAME_HEIGHT - 100, 'Back', () => this.scene.start('Landing'), { variant: 'ghost' });
|
||||||
|
|
@ -152,7 +175,7 @@ export default class GameMenuScene extends Phaser.Scene {
|
||||||
const COLS = 3;
|
const COLS = 3;
|
||||||
const COL_SPACING = 520;
|
const COL_SPACING = 520;
|
||||||
const ROW_SPACING = 90;
|
const ROW_SPACING = 90;
|
||||||
const GRID_TOP = 340;
|
const GRID_TOP = 370;
|
||||||
const BTN_WIDTH = 360;
|
const BTN_WIDTH = 360;
|
||||||
const PADDING = 52;
|
const PADDING = 52;
|
||||||
const QBTN_SIZE = 44;
|
const QBTN_SIZE = 44;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue