refactor: consolidate path rendering styles into shared PATH_STYLE constant

Move path band widths, colors, and groove properties out of ZumaGame
hardcoded constants and into a single PATH_STYLE config in ZumaLogic.
Both ZumaGame and ZumaEditor now draw the path using the same nested
band strokes for a consistent concave-channel appearance.
This commit is contained in:
Brian Fertig 2026-07-28 07:27:13 -06:00
parent d08b48cdda
commit 27b8c23a82
3 changed files with 39 additions and 24 deletions

View File

@ -17,7 +17,7 @@ import { GAME_WIDTH, GAME_HEIGHT, COLORS } from '../../config.js';
import { Button } from '../../ui/Button.js';
import { playSound, SFX } from '../../ui/Sounds.js';
import {
TUNING, BALL_COLORS, LEVEL_BOUNDS, buildPath, validateLevel, validateLevelParams,
TUNING, BALL_COLORS, LEVEL_BOUNDS, PATH_STYLE, buildPath, validateLevel, validateLevelParams,
} from './ZumaLogic.js';
const FONT = 'm6x11, "Julius Sans One"';
@ -483,8 +483,7 @@ export default class ZumaEditor extends Phaser.Scene {
}
g.strokePath();
};
stroke(80, 0x241b0e);
stroke(67, 0x4a3a26);
for (const { w, color } of PATH_STYLE.bands) stroke(w, color);
// Ghost chain: the whole quota packed back from the hole — the shape of
// the moment before you lose. Makes "does this path hold the marbles I

View File

@ -5,12 +5,10 @@ import { MusicPlayer } from '../../ui/MusicPlayer.js';
import { playSound, playScifiWoosh, playScifiExplode, SFX } from '../../ui/Sounds.js';
import { api } from '../../services/api.js';
import {
TUNING, BALL_COLORS, createLevel, step, fireBall, swapBalls, rayHit,
TUNING, BALL_COLORS, PATH_STYLE, createLevel, step, fireBall, swapBalls, rayHit,
} from './ZumaLogic.js';
const BG = 0x0d1a10; // deep jungle green
const PATH_RIM = 0x241b0e;
const PATH_BED = 0x4a3a26;
const BG = 0x0d1a10; // deep jungle green
// The launcher is layered around the marble it holds: frog frame 0 sits under
// the ready marble, frame 1 (the disc with the mouth slot cut out) sits over
@ -44,9 +42,6 @@ const TUNE = {
INSERT_MS: 120, // squeeze-in tween for a landed shot
POP_FX_MS: 320, // particle burst lifetime
LASER_ALPHA: 0.55,
PATH_W_RIM: 80,
PATH_W_BED: 67,
GROOVE_STEP: 48, // px between center-groove dots
NEXT_SCALE: 0.55, // the on-deck marble shown in the frog's belly
};
@ -548,23 +543,21 @@ export default class ZumaGame extends Phaser.Scene {
drawPath() {
const samples = this.state.path.samples;
const g = this.add.graphics().setDepth(D.path);
g.lineStyle(TUNE.PATH_W_RIM, PATH_RIM, 1);
g.beginPath();
g.moveTo(samples[0].x, samples[0].y);
for (const s of samples) g.lineTo(s.x, s.y);
g.strokePath();
g.lineStyle(TUNE.PATH_W_BED, PATH_BED, 1);
g.beginPath();
g.moveTo(samples[0].x, samples[0].y);
for (const s of samples) g.lineTo(s.x, s.y);
g.strokePath();
// dotted center groove
g.fillStyle(0x6b5638, 0.55);
for (const { w, color } of PATH_STYLE.bands) {
g.lineStyle(w, color, 1);
g.beginPath();
g.moveTo(samples[0].x, samples[0].y);
for (const s of samples) g.lineTo(s.x, s.y);
g.strokePath();
}
// dotted center groove — the seam the ball rolls along, sunk into the
// bright core band above
g.fillStyle(PATH_STYLE.grooveColor, PATH_STYLE.grooveAlpha);
let nextDot = 0;
for (const s of samples) {
if (s.s >= nextDot) {
g.fillCircle(s.x, s.y, 4);
nextDot += TUNE.GROOVE_STEP;
g.fillCircle(s.x, s.y, PATH_STYLE.grooveRadius);
nextDot += PATH_STYLE.grooveStep;
}
}
this.layer.add(g);

View File

@ -56,6 +56,29 @@ export const POWER_KINDS = ['slow', 'reverse', 'accuracy', 'explosion'];
// first N of these. Lives here so the scene and the editor share one list.
export const BALL_COLORS = [0xd9403a, 0xeec23d, 0x3f7fdb, 0x43b059, 0x9b59d0, 0xd9dde3];
// The path is drawn as nested strokes on one centerline, widest first — each
// narrower band paints over the middle of the last, leaving only its outer
// edge showing as a ring. Ordered outer to inner it fakes a concave channel's
// cross-section (dark contrast border -> lit embankment lip -> shadowed wall
// -> the floor's own shadow/lit/core bands) with plain solid-color strokes,
// no per-sample normals needed since the profile is symmetric across the
// centerline. Shared by ZumaGame (draw) and ZumaEditor (preview, scaled by K).
export const PATH_STYLE = {
bands: [
{ w: 96, color: 0x0a0704 }, // outer contrast border, pops off any bg
{ w: 84, color: 0x362615 }, // embankment lip catching light
{ w: 80, color: 0x241b0e }, // embankment wall, in shadow
{ w: 71, color: 0x2e2313 }, // shadow where the wall meets the floor
{ w: 67, color: 0x4a3a26 }, // main floor
{ w: 42, color: 0x6c5735 }, // floor lit by bounced light
{ w: 20, color: 0x8f7a52 }, // pale core along the concave bottom
],
grooveStep: 48, // px between center-groove dots
grooveColor: 0x4a3a1f,
grooveAlpha: 0.4,
grooveRadius: 4,
};
// ── Seeded RNG (mulberry32, matches genRushHour.js) ─────────────────────────
export function makeRng(seed) {
let a = seed >>> 0;