Polish Mahjong layout: reposition portraits and reference panel
- Rename card back themes (Cthulhu, Cyberpunk, Nautical, etc.) and update artwork assets to match - Move player portraits just left of each seat's tiles so they read as belonging to that player without covering any tile - Reposition the "Hands" reference button clear of seat 2's melds/bonus tiles, and hide seat 1's portrait video while the panel covers it - Auto-close the open reference panel whenever claim or win/kong buttons appear so nothing clickable is hidden
This commit is contained in:
parent
93db9ef9dc
commit
3c2cf462ed
Binary file not shown.
|
Before Width: | Height: | Size: 2.2 MiB After Width: | Height: | Size: 2.3 MiB |
Binary file not shown.
|
|
@ -1,13 +1,13 @@
|
||||||
{
|
{
|
||||||
"default": "back-0",
|
"default": "back-0",
|
||||||
"cardBacks": [
|
"cardBacks": [
|
||||||
{ "id": "back-0", "name": "Card Back 1", "key": "cardbacks", "spriteIndex": 0, "fallbackColor": "#1a3a6b" },
|
{ "id": "back-0", "name": "Cthulhu", "key": "cardbacks", "spriteIndex": 0, "fallbackColor": "#1a3a6b" },
|
||||||
{ "id": "back-1", "name": "Card Back 2", "key": "cardbacks", "spriteIndex": 1, "fallbackColor": "#1a3a6b" },
|
{ "id": "back-1", "name": "Cyberpunk", "key": "cardbacks", "spriteIndex": 1, "fallbackColor": "#1a3a6b" },
|
||||||
{ "id": "back-2", "name": "Card Back 3", "key": "cardbacks", "spriteIndex": 2, "fallbackColor": "#1a3a6b" },
|
{ "id": "back-2", "name": "Nautical", "key": "cardbacks", "spriteIndex": 2, "fallbackColor": "#1a3a6b" },
|
||||||
{ "id": "back-3", "name": "Card Back 4", "key": "cardbacks", "spriteIndex": 3, "fallbackColor": "#1a3a6b" },
|
{ "id": "back-3", "name": "Steampunk", "key": "cardbacks", "spriteIndex": 3, "fallbackColor": "#1a3a6b" },
|
||||||
{ "id": "back-4", "name": "Card Back 5", "key": "cardbacks", "spriteIndex": 4, "fallbackColor": "#1a3a6b" },
|
{ "id": "back-4", "name": "Jungle", "key": "cardbacks", "spriteIndex": 4, "fallbackColor": "#1a3a6b" },
|
||||||
{ "id": "back-5", "name": "Card Back 6", "key": "cardbacks", "spriteIndex": 5, "fallbackColor": "#1a3a6b" },
|
{ "id": "back-5", "name": "Hi Tech", "key": "cardbacks", "spriteIndex": 5, "fallbackColor": "#1a3a6b" },
|
||||||
{ "id": "back-6", "name": "Card Back 7", "key": "cardbacks", "spriteIndex": 6, "fallbackColor": "#1a3a6b" },
|
{ "id": "back-6", "name": "Fall Mountain", "key": "cardbacks", "spriteIndex": 6, "fallbackColor": "#1a3a6b" },
|
||||||
{ "id": "back-7", "name": "Card Back 8", "key": "cardbacks", "spriteIndex": 7, "fallbackColor": "#1a3a6b" }
|
{ "id": "back-7", "name": "Neon Miami", "key": "cardbacks", "spriteIndex": 7, "fallbackColor": "#1a3a6b" }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -81,7 +81,17 @@ export default class MahjongGame extends Phaser.Scene {
|
||||||
const { tracks, volume } = getGameSoundtrack(this);
|
const { tracks, volume } = getGameSoundtrack(this);
|
||||||
if (tracks.length) new MusicPlayer(this, tracks, volume);
|
if (tracks.length) new MusicPlayer(this, tracks, volume);
|
||||||
} catch { /* optional */ }
|
} catch { /* optional */ }
|
||||||
this.add.rectangle(GAME_WIDTH / 2, GAME_HEIGHT / 2, GAME_WIDTH, GAME_HEIGHT, FELT).setDepth(DEPTH.bg);
|
// Backdrop: the playfield chosen on the opponent-select screen (image
|
||||||
|
// texture, or the generated canvas texture for the "colored" playfields),
|
||||||
|
// falling back to its flat color and finally to the classic deep green.
|
||||||
|
const pf = this.playfield;
|
||||||
|
if (pf?.key && this.textures.exists(pf.key)) {
|
||||||
|
this.add.image(GAME_WIDTH / 2, GAME_HEIGHT / 2, pf.key)
|
||||||
|
.setDisplaySize(GAME_WIDTH, GAME_HEIGHT).setDepth(DEPTH.bg);
|
||||||
|
} else {
|
||||||
|
const color = pf?.fallbackColor ? parseInt(pf.fallbackColor.replace('#', ''), 16) : FELT;
|
||||||
|
this.add.rectangle(GAME_WIDTH / 2, GAME_HEIGHT / 2, GAME_WIDTH, GAME_HEIGHT, color).setDepth(DEPTH.bg);
|
||||||
|
}
|
||||||
|
|
||||||
const names = [auth.user?.username ?? 'You'];
|
const names = [auth.user?.username ?? 'You'];
|
||||||
const skills = { 0: 5 };
|
const skills = { 0: 5 };
|
||||||
|
|
@ -130,11 +140,16 @@ export default class MahjongGame extends Phaser.Scene {
|
||||||
}
|
}
|
||||||
|
|
||||||
buildPortraits() {
|
buildPortraits() {
|
||||||
|
// Each portrait sits just to the left of its own tiles, at the vertical
|
||||||
|
// centre of that area (rows/columns are all centred on their midpoints),
|
||||||
|
// so it reads as belonging to that player without ever covering a tile.
|
||||||
|
// Keep ~18-20px clearance: human hand left edge ≥ 391 (14 tiles), left
|
||||||
|
// column left edge 133, right column left edge 1836, top row ≥ 616.
|
||||||
const spots = [
|
const spots = [
|
||||||
{ x: 90, y: 870, r: 46 }, // human — bottom left
|
{ x: 325, y: 975, r: 46 }, // human — left of the bottom hand row
|
||||||
{ x: 1830, y: 170, r: 40 }, // seat 1 — right
|
{ x: 1778, y: 580, r: 40 }, // seat 1 — left of the right column
|
||||||
{ x: 560, y: 95, r: 40 }, // seat 2 — top
|
{ x: 558, y: 70, r: 40 }, // seat 2 — left of the top row
|
||||||
{ x: 90, y: 310, r: 40 }, // seat 3 — left
|
{ x: 75, y: 580, r: 40 }, // seat 3 — left of the left column
|
||||||
];
|
];
|
||||||
for (let seat = 0; seat < 4; seat++) {
|
for (let seat = 0; seat < 4; seat++) {
|
||||||
const { x, y, r } = spots[seat];
|
const { x, y, r } = spots[seat];
|
||||||
|
|
@ -219,7 +234,10 @@ export default class MahjongGame extends Phaser.Scene {
|
||||||
}).setOrigin(0.5));
|
}).setOrigin(0.5));
|
||||||
this.refPanel = panel;
|
this.refPanel = panel;
|
||||||
|
|
||||||
this.refBtn = new Button(this, 1810, 44, 'Hands', () => this.toggleReference(), {
|
// Parked just left of the reference panel's open position (1490) so it
|
||||||
|
// never ends up under it; y=210 clears seat 2's melds (y≤98) and bonus
|
||||||
|
// tiles (y≤157), which sit at x 1330+.
|
||||||
|
this.refBtn = new Button(this, 1399, 210, 'Hands', () => this.toggleReference(), {
|
||||||
width: 150, height: 52, fontSize: 22, variant: 'ghost',
|
width: 150, height: 52, fontSize: 22, variant: 'ghost',
|
||||||
}).setDepth(DEPTH.ref + 1);
|
}).setDepth(DEPTH.ref + 1);
|
||||||
}
|
}
|
||||||
|
|
@ -233,6 +251,15 @@ export default class MahjongGame extends Phaser.Scene {
|
||||||
ease: 'Quad.Out',
|
ease: 'Quad.Out',
|
||||||
});
|
});
|
||||||
this.refBtn.setLabel(this.refOpen ? 'Close' : 'Hands');
|
this.refBtn.setLabel(this.refOpen ? 'Close' : 'Hands');
|
||||||
|
// Seat 1's portrait sits under the open panel. Its <video> is a DOM node
|
||||||
|
// that always renders above canvas content, so hide it while covered.
|
||||||
|
this.portraitCtrls[1]?.controller?.setVideoVisible?.(!this.refOpen);
|
||||||
|
}
|
||||||
|
|
||||||
|
// The claim row and the self win/kong buttons sit under the open panel's
|
||||||
|
// footprint — close it whenever they appear so nothing clickable is covered.
|
||||||
|
closeReferenceIfOpen() {
|
||||||
|
if (this.refOpen) this.toggleReference();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── tile drawing ──────────────────────────────────────────────────────────────
|
// ── tile drawing ──────────────────────────────────────────────────────────────
|
||||||
|
|
@ -382,7 +409,7 @@ export default class MahjongGame extends Phaser.Scene {
|
||||||
bx += 40;
|
bx += 40;
|
||||||
}
|
}
|
||||||
} else { // sides — vertical column of rotated backs
|
} else { // sides — vertical column of rotated backs
|
||||||
const x = seat === 1 ? 1858 : 62;
|
const x = seat === 1 ? 1858 : 155; // columns stay right of their portraits (seat 1: 1778+40, seat 3: 75+40)
|
||||||
let y = 580 - ((n - 1) * step) / 2;
|
let y = 580 - ((n - 1) * step) / 2;
|
||||||
for (let i = 0; i < n; i++) {
|
for (let i = 0; i < n; i++) {
|
||||||
const back = this.makeTileBack(SM_W, SM_H);
|
const back = this.makeTileBack(SM_W, SM_H);
|
||||||
|
|
@ -390,7 +417,7 @@ export default class MahjongGame extends Phaser.Scene {
|
||||||
this.dyn.add(back);
|
this.dyn.add(back);
|
||||||
y += step;
|
y += step;
|
||||||
}
|
}
|
||||||
const mx = seat === 1 ? 1745 : 175;
|
const mx = seat === 1 ? 1745 : 270; // melds/bonus offset from their column
|
||||||
let my = 330;
|
let my = 330;
|
||||||
for (const m of p.melds) {
|
for (const m of p.melds) {
|
||||||
const row = this.makeMeldRow(m, 38, 52, false);
|
const row = this.makeMeldRow(m, 38, 52, false);
|
||||||
|
|
@ -481,6 +508,7 @@ export default class MahjongGame extends Phaser.Scene {
|
||||||
btn.setVisible(!!spec);
|
btn.setVisible(!!spec);
|
||||||
if (spec) btn.setLabel(`Kong ${shortName(spec.kind)}`);
|
if (spec) btn.setLabel(`Kong ${shortName(spec.kind)}`);
|
||||||
});
|
});
|
||||||
|
if (show && (acts?.canWin || this.kongSpecs.length > 0)) this.closeReferenceIfOpen();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── human input ───────────────────────────────────────────────────────────────
|
// ── human input ───────────────────────────────────────────────────────────────
|
||||||
|
|
@ -521,6 +549,7 @@ export default class MahjongGame extends Phaser.Scene {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
this.claimResolve = resolve;
|
this.claimResolve = resolve;
|
||||||
this.chowOptions = opts.chows;
|
this.chowOptions = opts.chows;
|
||||||
|
this.closeReferenceIfOpen();
|
||||||
const visible = [];
|
const visible = [];
|
||||||
if (opts.win) visible.push(this.claimBtns.win);
|
if (opts.win) visible.push(this.claimBtns.win);
|
||||||
if (opts.kong) visible.push(this.claimBtns.kong);
|
if (opts.kong) visible.push(this.claimBtns.kong);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue