feat(blokus): add player and opponent portraits to score panels

Integrate portrait avatars into the Blokus score panels by increasing
panel height and adjusting the layout. Added portrait graphics with
colored strokes and repositioned text elements to accommodate the new
visual components.
This commit is contained in:
Brian Fertig 2026-06-02 14:17:40 -06:00
parent aa920fddfb
commit 5c88ab7986
1 changed files with 28 additions and 8 deletions

View File

@ -5,6 +5,7 @@ import { auth } from '../../services/auth.js';
import { api } from '../../services/api.js';
import { playSound, SFX } from '../../ui/Sounds.js';
import { MusicPlayer } from '../../ui/MusicPlayer.js';
import { createOpponentPortrait, createPlayerPortrait } from '../../ui/Portrait.js';
import {
SIZE, CELL, BOARD_PX, GRID_X, GRID_Y, cellToWorld, worldToCell,
COLOR_PALETTE, cornersFor, ALL_PIECE_IDS, PIECE_SIZE, ORIENTATIONS,
@ -44,6 +45,7 @@ export default class BlokusGame extends Phaser.Scene {
this.hoverMove = null;
this.trayObjs = [];
this.scoreObjs = [];
this.opponentPortraits = [];
}
create() {
@ -255,18 +257,31 @@ export default class BlokusGame extends Phaser.Scene {
// ── Score panels + controls ──────────────────────────────────────────────────
buildScorePanels() {
this.scorePanels = [];
const panelH = 192; // 3× original height
const portraitR = 60;
const portraitY = -panelH / 2 + portraitR + 14; // centered in upper space
for (let seat = 0; seat < this.gs.players.length; seat++) {
const y = 146 + seat * 74;
const y = 221 + seat * (panelH + 10);
const container = this.add.container(SIDE_X, y).setDepth(DEPTH.hud);
const bg = this.add.graphics();
container.add(bg);
const swatch = this.add.graphics();
container.add(swatch);
const name = this.add.text(-120, -18, '', { fontFamily: 'Righteous', fontSize: '20px', color: COLORS.textHex }).setOrigin(0, 0.5);
const detail = this.add.text(-120, 14, '', { fontFamily: '"Julius Sans One"', fontSize: '16px', color: COLORS.mutedHex }).setOrigin(0, 0.5);
const score = this.add.text(150, 0, '', { fontFamily: 'Righteous', fontSize: '26px', color: COLORS.accentHex }).setOrigin(1, 0.5);
const portraitStroke = this.add.graphics().setDepth(DEPTH.hud + 1);
container.add(portraitStroke);
const name = this.add.text(-120, 60, '', { fontFamily: 'Righteous', fontSize: '20px', color: COLORS.textHex }).setOrigin(0, 0.5);
const detail = this.add.text(-120, 85, '', { fontFamily: '"Julius Sans One"', fontSize: '16px', color: COLORS.mutedHex }).setOrigin(0, 0.5);
const score = this.add.text(150, 60, '', { fontFamily: 'Righteous', fontSize: '26px', color: COLORS.accentHex }).setOrigin(1, 0.5);
container.add([name, detail, score]);
this.scorePanels.push({ container, bg, swatch, name, detail, score });
this.scorePanels.push({ container, bg, swatch, portraitStroke, name, detail, score, panelH });
// Create portrait
if (seat === 0) {
createPlayerPortrait(this, SIDE_X, y + portraitY, portraitR, DEPTH.hud + 2, 'BlokusGame');
} else {
const opp = this.opponents[seat - 1];
this.opponentPortraits[seat - 1] = createOpponentPortrait(this, opp, SIDE_X, y + portraitY, portraitR, DEPTH.hud + 2);
}
}
}
@ -283,12 +298,17 @@ export default class BlokusGame extends Phaser.Scene {
const isTurn = !this.gameOver && this.gs.current === seat;
panel.bg.clear();
panel.bg.fillStyle(COLORS.panel, isTurn ? 0.95 : 0.6);
panel.bg.fillRoundedRect(-180, -32, 360, 64, 10);
panel.bg.fillRoundedRect(-180, -panel.panelH / 2, 360, panel.panelH, 10);
panel.bg.lineStyle(isTurn ? 3 : 1, isTurn ? COLORS.accent : col.hex, isTurn ? 1 : 0.5);
panel.bg.strokeRoundedRect(-180, -32, 360, 64, 10);
panel.bg.strokeRoundedRect(-180, -panel.panelH / 2, 360, panel.panelH, 10);
panel.swatch.clear();
panel.swatch.fillStyle(col.hex, 1);
panel.swatch.fillRoundedRect(-172, -16, 28, 32, 5);
panel.swatch.fillRoundedRect(-172, panel.panelH / 2 - 44, 28, 32, 5);
// Portrait stroke — colored circle around the portrait
const portraitY = -panel.panelH / 2 + 60 + 14;
panel.portraitStroke.clear();
panel.portraitStroke.lineStyle(4, col.hex, 1);
panel.portraitStroke.strokeCircle(0, portraitY, 63);
panel.name.setText(this.playerName(seat));
panel.detail.setText(p.out ? 'done' : `${p.remaining.size} pieces left`);
panel.score.setText(`${scoreFor(p)}`);