Game-Polish #9
Binary file not shown.
|
Before Width: | Height: | Size: 2.5 MiB After Width: | Height: | Size: 2.3 MiB |
Binary file not shown.
|
|
@ -1,13 +1,13 @@
|
|||
{
|
||||
"default": "back-0",
|
||||
"cardBacks": [
|
||||
{ "id": "back-0", "name": "Card Back 1", "key": "cardbacks", "spriteIndex": 0, "fallbackColor": "#1a3a6b" },
|
||||
{ "id": "back-1", "name": "Card Back 2", "key": "cardbacks", "spriteIndex": 1, "fallbackColor": "#1a3a6b" },
|
||||
{ "id": "back-2", "name": "Card Back 3", "key": "cardbacks", "spriteIndex": 2, "fallbackColor": "#1a3a6b" },
|
||||
{ "id": "back-3", "name": "Card Back 4", "key": "cardbacks", "spriteIndex": 3, "fallbackColor": "#1a3a6b" },
|
||||
{ "id": "back-4", "name": "Card Back 5", "key": "cardbacks", "spriteIndex": 4, "fallbackColor": "#1a3a6b" },
|
||||
{ "id": "back-5", "name": "Card Back 6", "key": "cardbacks", "spriteIndex": 5, "fallbackColor": "#1a3a6b" },
|
||||
{ "id": "back-6", "name": "Card Back 7", "key": "cardbacks", "spriteIndex": 6, "fallbackColor": "#1a3a6b" },
|
||||
{ "id": "back-7", "name": "Card Back 8", "key": "cardbacks", "spriteIndex": 7, "fallbackColor": "#1a3a6b" }
|
||||
{ "id": "back-0", "name": "Cthulhu", "key": "cardbacks", "spriteIndex": 0, "fallbackColor": "#1a3a6b" },
|
||||
{ "id": "back-1", "name": "Cyberpunk", "key": "cardbacks", "spriteIndex": 1, "fallbackColor": "#1a3a6b" },
|
||||
{ "id": "back-2", "name": "Nautical", "key": "cardbacks", "spriteIndex": 2, "fallbackColor": "#1a3a6b" },
|
||||
{ "id": "back-3", "name": "Steampunk", "key": "cardbacks", "spriteIndex": 3, "fallbackColor": "#1a3a6b" },
|
||||
{ "id": "back-4", "name": "Jungle", "key": "cardbacks", "spriteIndex": 4, "fallbackColor": "#1a3a6b" },
|
||||
{ "id": "back-5", "name": "Hi Tech", "key": "cardbacks", "spriteIndex": 5, "fallbackColor": "#1a3a6b" },
|
||||
{ "id": "back-6", "name": "Fall Mountain", "key": "cardbacks", "spriteIndex": 6, "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);
|
||||
if (tracks.length) new MusicPlayer(this, tracks, volume);
|
||||
} 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 skills = { 0: 5 };
|
||||
|
|
@ -130,11 +140,16 @@ export default class MahjongGame extends Phaser.Scene {
|
|||
}
|
||||
|
||||
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 = [
|
||||
{ x: 90, y: 870, r: 46 }, // human — bottom left
|
||||
{ x: 1830, y: 170, r: 40 }, // seat 1 — right
|
||||
{ x: 560, y: 95, r: 40 }, // seat 2 — top
|
||||
{ x: 90, y: 310, r: 40 }, // seat 3 — left
|
||||
{ x: 325, y: 975, r: 46 }, // human — left of the bottom hand row
|
||||
{ x: 1778, y: 580, r: 40 }, // seat 1 — left of the right column
|
||||
{ x: 558, y: 70, r: 40 }, // seat 2 — left of the top row
|
||||
{ x: 75, y: 580, r: 40 }, // seat 3 — left of the left column
|
||||
];
|
||||
for (let seat = 0; seat < 4; seat++) {
|
||||
const { x, y, r } = spots[seat];
|
||||
|
|
@ -219,7 +234,10 @@ export default class MahjongGame extends Phaser.Scene {
|
|||
}).setOrigin(0.5));
|
||||
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',
|
||||
}).setDepth(DEPTH.ref + 1);
|
||||
}
|
||||
|
|
@ -233,6 +251,15 @@ export default class MahjongGame extends Phaser.Scene {
|
|||
ease: 'Quad.Out',
|
||||
});
|
||||
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 ──────────────────────────────────────────────────────────────
|
||||
|
|
@ -382,7 +409,7 @@ export default class MahjongGame extends Phaser.Scene {
|
|||
bx += 40;
|
||||
}
|
||||
} 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;
|
||||
for (let i = 0; i < n; i++) {
|
||||
const back = this.makeTileBack(SM_W, SM_H);
|
||||
|
|
@ -390,7 +417,7 @@ export default class MahjongGame extends Phaser.Scene {
|
|||
this.dyn.add(back);
|
||||
y += step;
|
||||
}
|
||||
const mx = seat === 1 ? 1745 : 175;
|
||||
const mx = seat === 1 ? 1745 : 270; // melds/bonus offset from their column
|
||||
let my = 330;
|
||||
for (const m of p.melds) {
|
||||
const row = this.makeMeldRow(m, 38, 52, false);
|
||||
|
|
@ -481,6 +508,7 @@ export default class MahjongGame extends Phaser.Scene {
|
|||
btn.setVisible(!!spec);
|
||||
if (spec) btn.setLabel(`Kong ${shortName(spec.kind)}`);
|
||||
});
|
||||
if (show && (acts?.canWin || this.kongSpecs.length > 0)) this.closeReferenceIfOpen();
|
||||
}
|
||||
|
||||
// ── human input ───────────────────────────────────────────────────────────────
|
||||
|
|
@ -521,6 +549,7 @@ export default class MahjongGame extends Phaser.Scene {
|
|||
return new Promise((resolve) => {
|
||||
this.claimResolve = resolve;
|
||||
this.chowOptions = opts.chows;
|
||||
this.closeReferenceIfOpen();
|
||||
const visible = [];
|
||||
if (opts.win) visible.push(this.claimBtns.win);
|
||||
if (opts.kong) visible.push(this.claimBtns.kong);
|
||||
|
|
|
|||
|
|
@ -55,8 +55,8 @@ export class Button extends Phaser.GameObjects.Container {
|
|||
if (this._active) return;
|
||||
const { bgHover: bgh, textHoverColor: thc, variant: v } = this.options;
|
||||
if (v === 'ghost') {
|
||||
this._drawBg(bgh, 0.18);
|
||||
this.text.setColor(COLORS.goldHex);
|
||||
this._drawBg(bgh, 0.9);
|
||||
this.text.setColor(thc);
|
||||
} else {
|
||||
this._drawBg(bgh, 1);
|
||||
this.text.setColor(thc);
|
||||
|
|
|
|||
Loading…
Reference in New Issue