feat: add railway tracks and score badges to Mexican Train game
- Implement `paintRails()` to render decorative railroad ties and rails along player tracks - Add `updateScoreBadges()` to display animated score circles for each player with color-coded borders based on score thresholds - Fix double tile highlighting logic to correctly identify and style open doubles - Update tile rendering to respect double tile orientation (vertical vs horizontal) - Adjust track background colors for better visual contrast
This commit is contained in:
parent
7602da4cbe
commit
ed7da9fcf0
|
|
@ -99,6 +99,7 @@ export default class MexicanTrainGame extends Phaser.Scene {
|
|||
|
||||
this.trackGfx = this.add.graphics().setDepth(DEPTH.tile);
|
||||
this.bandGfx = this.add.graphics().setDepth(DEPTH.band);
|
||||
this.railGfx = this.add.graphics().setDepth(DEPTH.spine);
|
||||
this.spineGfx = this.add.graphics().setDepth(DEPTH.spine);
|
||||
this.hubGfx = this.add.graphics().setDepth(DEPTH.hub);
|
||||
this.markerGfx = this.add.graphics().setDepth(DEPTH.tileFx);
|
||||
|
|
@ -202,6 +203,7 @@ export default class MexicanTrainGame extends Phaser.Scene {
|
|||
// ─── Render ───────────────────────────────────────────────────────────
|
||||
refresh() {
|
||||
this.paintBands();
|
||||
this.paintRails();
|
||||
this.paintSpineAndHub();
|
||||
this.paintTracks();
|
||||
this.paintMarkers();
|
||||
|
|
@ -214,6 +216,7 @@ export default class MexicanTrainGame extends Phaser.Scene {
|
|||
`Round ${this.gs.round + 1} • Engine ${hub}-${hub} • First to ${this.gs.target} ends it — lowest score wins`,
|
||||
);
|
||||
this.updateBoneyard();
|
||||
this.updateScoreBadges();
|
||||
}
|
||||
|
||||
paintBands() {
|
||||
|
|
@ -224,11 +227,33 @@ export default class MexicanTrainGame extends Phaser.Scene {
|
|||
for (let i = 0; i < rows; i++) {
|
||||
const y = this.rowY(i);
|
||||
const active = i < this.gs.players.length && i === this.gs.current;
|
||||
g.fillStyle(active ? COLORS.accent : COLORS.panel, active ? 0.16 : 0.5);
|
||||
g.fillStyle(0x0c1a10, active ? 0.55 : 0.92);
|
||||
g.fillRoundedRect(TRACKS_LEFT - 8, y - gap / 2 + 4, TRACKS_RIGHT - TRACKS_LEFT + 16, gap - 8, 10);
|
||||
}
|
||||
}
|
||||
|
||||
paintRails() {
|
||||
const g = this.railGfx;
|
||||
g.clear();
|
||||
const rows = this.gs.players.length + 1;
|
||||
const railOff = 11; // px from lane center to each rail
|
||||
const tieHalf = 15; // tie extends 4px beyond each rail
|
||||
const tieStep = 22; // horizontal spacing between ties
|
||||
|
||||
for (let i = 0; i < rows; i++) {
|
||||
const y = this.rowY(i);
|
||||
// Ties (wood) — drawn first so rails appear on top
|
||||
g.lineStyle(4, 0x4a3018, 0.55);
|
||||
for (let x = TRACKS_LEFT; x <= TRACKS_RIGHT; x += tieStep) {
|
||||
g.lineBetween(x, y - tieHalf, x, y + tieHalf);
|
||||
}
|
||||
// Rails (metal)
|
||||
g.lineStyle(2.5, 0x908060, 0.7);
|
||||
g.lineBetween(TRACKS_LEFT, y - railOff, TRACKS_RIGHT, y - railOff);
|
||||
g.lineBetween(TRACKS_LEFT, y + railOff, TRACKS_RIGHT, y + railOff);
|
||||
}
|
||||
}
|
||||
|
||||
paintSpineAndHub() {
|
||||
const g = this.spineGfx;
|
||||
g.clear();
|
||||
|
|
@ -271,9 +296,10 @@ export default class MexicanTrainGame extends Phaser.Scene {
|
|||
}
|
||||
for (let t = start; t < tiles.length; t++) {
|
||||
const tile = tiles[t];
|
||||
const isDouble = tile.left === tile.right;
|
||||
const isOpenDouble = this.gs.openDouble?.train === key && t === tiles.length - 1;
|
||||
const border = isOpenDouble ? COLORS.danger : (tile.left === tile.right ? COLORS.gold : COLORS.accent);
|
||||
this.paintDomino(g, drawX, y, TRACK_HALF, tile.left, tile.right, false, border);
|
||||
const border = isOpenDouble ? COLORS.danger : (isDouble ? COLORS.gold : COLORS.accent);
|
||||
this.paintDomino(g, drawX, y, TRACK_HALF, tile.left, tile.right, isDouble, border);
|
||||
drawX += TRACK_PITCH;
|
||||
}
|
||||
}
|
||||
|
|
@ -377,6 +403,49 @@ export default class MexicanTrainGame extends Phaser.Scene {
|
|||
this.updateHandDots();
|
||||
}
|
||||
|
||||
updateScoreBadges() {
|
||||
const scores = this.gs.players.map(p => p.score);
|
||||
if (scores.every(s => s === 0)) {
|
||||
this._scoreBadgeCtrs?.forEach(c => c.destroy());
|
||||
this._scoreBadgeCtrs = [];
|
||||
return;
|
||||
}
|
||||
const changed = !this._lastBadgeScores || scores.some((s, i) => s !== this._lastBadgeScores[i]);
|
||||
if (!changed) return;
|
||||
this._lastBadgeScores = [...scores];
|
||||
|
||||
this._scoreBadgeCtrs?.forEach(c => c.destroy());
|
||||
this._scoreBadgeCtrs = [];
|
||||
|
||||
for (let i = 0; i < this.gs.players.length; i++) {
|
||||
const score = scores[i];
|
||||
const x = PORTRAIT_X;
|
||||
const y = this.rowY(i) - PORTRAIT_R - 20;
|
||||
const borderColor = score > 75 ? COLORS.danger
|
||||
: score > 50 ? 0xe07030
|
||||
: score > 25 ? COLORS.accent
|
||||
: COLORS.gold;
|
||||
|
||||
const c = this.add.container(x, y).setDepth(DEPTH.portrait + 2).setScale(0.1);
|
||||
const g = this.add.graphics();
|
||||
g.fillStyle(0x1e1a30, 1);
|
||||
g.fillCircle(0, 0, 22);
|
||||
g.lineStyle(2.5, borderColor, 1);
|
||||
g.strokeCircle(0, 0, 22);
|
||||
g.lineStyle(1.5, 0xffffff, 0.25);
|
||||
g.strokeCircle(0, 0, 17);
|
||||
|
||||
const fontSize = score >= 100 ? '11px' : '14px';
|
||||
const t = this.add.text(0, 0, String(score), {
|
||||
fontFamily: '"Julius Sans One"', fontSize, color: COLORS.textHex, fontStyle: 'bold',
|
||||
}).setOrigin(0.5);
|
||||
|
||||
c.add([g, t]);
|
||||
this._scoreBadgeCtrs.push(c);
|
||||
this.tweens.add({ targets: c, scale: 1, duration: 260, ease: 'Back.Out' });
|
||||
}
|
||||
}
|
||||
|
||||
updateHandDots() {
|
||||
if (!this._handDotGfx) return;
|
||||
const n = this.gs.players.length;
|
||||
|
|
@ -613,9 +682,13 @@ export default class MexicanTrainGame extends Phaser.Scene {
|
|||
const maxTiles = Math.floor((TRACKS_RIGHT - TRACKS_LEFT) / TRACK_PITCH);
|
||||
const shown = Math.min(tiles.length, maxTiles);
|
||||
const x = TRACKS_LEFT + TRACK_HALF + (shown - 1) * TRACK_PITCH;
|
||||
const lastTile = tiles[tiles.length - 1];
|
||||
const isLastDouble = lastTile && lastTile.left === lastTile.right;
|
||||
const fw = isLastDouble ? TRACK_HALF : TRACK_TILE_W;
|
||||
const fh = isLastDouble ? TRACK_TILE_W : TRACK_HALF;
|
||||
const fx = this.add.graphics().setDepth(DEPTH.tileFx);
|
||||
fx.lineStyle(4, COLORS.gold, 1);
|
||||
fx.strokeRoundedRect(x - TRACK_TILE_W / 2 - 3, y - TRACK_HALF / 2 - 3, TRACK_TILE_W + 6, TRACK_HALF + 6, 6);
|
||||
fx.strokeRoundedRect(x - fw / 2 - 3, y - fh / 2 - 3, fw + 6, fh + 6, 6);
|
||||
this.tweens.add({ targets: fx, alpha: { from: 1, to: 0 }, duration: 500, onComplete: () => fx.destroy() });
|
||||
}
|
||||
|
||||
|
|
@ -630,8 +703,9 @@ export default class MexicanTrainGame extends Phaser.Scene {
|
|||
}
|
||||
|
||||
animateTilePlay(fromX, fromY, toX, toY, tileA, tileB, onComplete) {
|
||||
const isDouble = tileA === tileB;
|
||||
const g = this.add.graphics().setDepth(DEPTH.tileFx + 2);
|
||||
this.paintDomino(g, 0, 0, TRACK_HALF, tileA, tileB, false, COLORS.accent);
|
||||
this.paintDomino(g, 0, 0, TRACK_HALF, tileA, tileB, isDouble, COLORS.accent);
|
||||
g.setPosition(fromX, fromY);
|
||||
this.tweens.add({
|
||||
targets: g,
|
||||
|
|
|
|||
Loading…
Reference in New Issue