commit ed650a88a4639f1b2b544b431f5f6e21203abba1
parent c4578d57ea48bb50f909851757590f8bf6e9eb0f
Author: Kyle Barlow <kb@kylebarlow.com>
Date: Wed, 22 Apr 2026 11:20:37 -0700
fix(fire-truck): refactor animations to use Phaser timers
Diffstat:
1 file changed, 32 insertions(+), 52 deletions(-)
diff --git a/games/fire-truck/game.js b/games/fire-truck/game.js
@@ -99,9 +99,10 @@ class FireTruckScene extends Phaser.Scene {
this.sirenOsc1 = null;
this.sirenOsc2 = null;
this.sirenGain = null;
- this.sirenInterval = null;
+ this.sirenTimer = null;
+ this.sirenHi = true;
this.lightPhase = 0;
- this.lightInterval = null;
+ this.lightTimer = null;
}
// ── Preload ────────────────────────────────────────────────────────────────
@@ -429,41 +430,6 @@ class FireTruckScene extends Phaser.Scene {
gfx.fillStyle(bldg.fill);
- // Draw facade as stacked horizontal slices for correct fill
- // Use polygon approach: 4 corners of the facade face
- const topY = Math.min(yNearTop, yFarTop, 0);
- const bottomY = Math.max(yNearBottom, yFarBottom, horizY);
-
- if (bottomY <= topY) continue;
-
- // Interpolate x-left/right at each screen row between horizY and bottomY
- // Near edge: at y approaching horizY, x → horizon vanishing point; at yNearBottom x = xNearBottom
- // Far edge: similar but for far Z
- // Simpler: just draw a filled trapezoid using fillPoints
- if (side < 0) {
- // Left side: facade from sidewalk edge to screen left
- // Near wall x = xNearBottom (at bottom) to xNearTop (at top)
- // Fill screen left (x=0) to wall face
- const pts = [
- { x: 0, y: topY },
- { x: xFarTop, y: topY },
- { x: xFarBottom, y: horizY },
- { x: xNearBottom, y: yNearBottom },
- { x: 0, y: yNearBottom },
- ];
- gfx.fillPoints(pts.map(p => new Phaser.Geom.Point(p.x, p.y)), true);
- } else {
- // Right side
- const pts = [
- { x: xFarTop, y: topY },
- { x: W, y: topY },
- { x: W, y: yNearBottom },
- { x: xNearBottom, y: yNearBottom },
- { x: xFarBottom, y: horizY },
- ];
- gfx.fillPoints(pts.map(p => new Phaser.Geom.Point(p.x, p.y)), true);
- }
-
// Windows — draw a grid on the facade for the nearest segment
if (pNearB.visible && pNearB.scale > 0.015) {
this._drawWindows(gfx, bldg.win, side, xNearBottom, yNearBottom, pNearB.scale, H);
@@ -830,13 +796,20 @@ class FireTruckScene extends Phaser.Scene {
if (this.lightsOn) {
this.lightBarL.setVisible(true);
this.lightBarR.setVisible(true);
- this.lightInterval = setInterval(() => {
- this.lightPhase = 1 - this.lightPhase;
- this.lightBarL.setFillStyle(this.lightPhase ? 0xE63946 : 0x220000);
- this.lightBarR.setFillStyle(this.lightPhase ? 0x220022 : 0x1D7CF2);
- }, 280);
+ this.lightTimer = this.time.addEvent({
+ delay: 280,
+ callback: () => {
+ this.lightPhase = 1 - this.lightPhase;
+ this.lightBarL.setFillStyle(this.lightPhase ? 0xE63946 : 0x220000);
+ this.lightBarR.setFillStyle(this.lightPhase ? 0x220022 : 0x1D7CF2);
+ },
+ loop: true
+ });
} else {
- clearInterval(this.lightInterval);
+ if (this.lightTimer) {
+ this.lightTimer.remove();
+ this.lightTimer = null;
+ }
this.lightBarL.setVisible(false);
this.lightBarR.setVisible(false);
}
@@ -861,19 +834,26 @@ class FireTruckScene extends Phaser.Scene {
this.sirenOsc1.frequency.value = 770; this.sirenOsc1.connect(this.sirenGain); this.sirenOsc1.start();
this.sirenOsc2 = ctx.createOscillator(); this.sirenOsc2.type = 'sawtooth';
this.sirenOsc2.frequency.value = 570; this.sirenOsc2.connect(this.sirenGain); this.sirenOsc2.start();
- let hi = true;
- this.sirenInterval = setInterval(() => {
- if (!this.sirenOsc1) return;
- const t = this.getAudioCtx().currentTime;
- this.sirenOsc1.frequency.linearRampToValueAtTime(hi ? 960 : 770, t + 0.45);
- this.sirenOsc2.frequency.linearRampToValueAtTime(hi ? 700 : 570, t + 0.45);
- hi = !hi;
- }, 450);
+ this.sirenHi = true;
+ this.sirenTimer = this.time.addEvent({
+ delay: 450,
+ callback: () => {
+ if (!this.sirenOsc1) return;
+ const t = this.getAudioCtx().currentTime;
+ this.sirenOsc1.frequency.linearRampToValueAtTime(this.sirenHi ? 960 : 770, t + 0.45);
+ this.sirenOsc2.frequency.linearRampToValueAtTime(this.sirenHi ? 700 : 570, t + 0.45);
+ this.sirenHi = !this.sirenHi;
+ },
+ loop: true
+ });
} catch (_) {}
}
_stopSiren() {
- clearInterval(this.sirenInterval);
+ if (this.sirenTimer) {
+ this.sirenTimer.remove();
+ this.sirenTimer = null;
+ }
try {
if (this.sirenOsc1) { this.sirenOsc1.stop(); this.sirenOsc1 = null; }
if (this.sirenOsc2) { this.sirenOsc2.stop(); this.sirenOsc2 = null; }