| /** | |
| * GameClock β continuous game-time cycle (GTA-style). | |
| * | |
| * gameTime: 0..1 represents the full 24-hour cycle. | |
| * 0.00 / 1.00 β midnight | |
| * 0.22 β sunrise | |
| * 0.50 β noon | |
| * 0.78 β sunset | |
| * | |
| * dayDurationSeconds controls how fast time passes (default 120s = 2 minutes per game day, | |
| * a bit faster than GTA so kids see day β night within one play session). | |
| * | |
| * Optional jumpToLevel(t01) snaps the clock to a sensible time-of-day for the current grade: | |
| * level low β bright morning | |
| * level mid β noon β afternoon | |
| * level high β sunset β night | |
| * After a snap, time keeps progressing forward β so the BG never goes static. | |
| */ | |
| export class GameClock { | |
| constructor({ dayDurationSeconds = 120, startTime = 0.30 } = {}) { | |
| this.dayDurationSeconds = dayDurationSeconds; | |
| this.gameTime = startTime; // 0..1 | |
| } | |
| update(dt) { | |
| this.gameTime = (this.gameTime + dt / this.dayDurationSeconds) % 1; | |
| } | |
| /** | |
| * Jump time forward so the look matches the current level intensity. | |
| * Only nudges forward (no rewind) so the cycle keeps marching. | |
| */ | |
| jumpToLevel(t01) { | |
| // Map level intensity to a "preferred" time-of-day: | |
| // t=0 β 0.30 (mid-morning), t=0.5 β 0.55 (mid-afternoon), t=1 β 0.92 (deep night) | |
| const target = 0.30 + t01 * 0.62; | |
| // Take the shortest forward jump | |
| let delta = target - this.gameTime; | |
| if (delta < 0) delta += 1; | |
| if (delta > 0.02) this.gameTime = target; | |
| } | |
| // 50/50 split β 10 minutes of day and 10 minutes of night for a 20-minute cycle. | |
| // Sunrise is at gameTime 0.25, sunset at 0.75. | |
| isDay() { return this.gameTime >= 0.25 && this.gameTime < 0.75; } | |
| isNight() { return !this.isDay(); } | |
| /** Returns 0..1 fraction of the daylight arc (only valid during day). */ | |
| dayPhase() { | |
| if (!this.isDay()) return -1; | |
| return (this.gameTime - 0.25) / 0.5; // 0.25..0.75 β 0..1 | |
| } | |
| /** Returns 0..1 fraction of the night arc (wraps over midnight). */ | |
| nightPhase() { | |
| if (this.isDay()) return -1; | |
| const t = this.gameTime >= 0.75 ? this.gameTime - 0.75 : (1 - 0.75) + this.gameTime; | |
| return t / 0.5; // 0.75..1.25 β 0..1 | |
| } | |
| } | |