square number (mod 12) => flash */ private array $flash = []; protected function melodyNotes(): string { return 'D4'; } protected function headingText(): string { return 'DO NOT STARE TOO LONG'; } protected function hookText(): string { return 'THE TUNNEL NEVER ENDS'; } protected function captionText(): string { return $this->t('DEPTH {n}', ['n' => (int)floor($this->time / self::PERIOD * self::RINGS)]); } protected function build(): void { $this->flash = []; $this->flashed = -1.0; } /** how many squares have gone by the middle line (a float: its fraction moves them) */ public function depth(): float { return $this->time / self::PERIOD * self::RINGS; } protected function tick(float $dt): void { $d = $this->depth(); $n = (int)floor($d); if ($n > $this->flashed) { $this->flashed = $n; if ($n > 0 || $d > 0.0) { $i = $n % self::RINGS; $this->flash[$i] = 1.0; $this->play(Scale::freq(Scale::MINOR_PENTA, 4 + [0, 2, 4, 2, 5, 4, 2, 0, 1, 3, 2, 4][$i], 62), 'marimba', 0.5, 0.3, 0.0); if ($i % 4 === 0) { $this->pad([Scale::freq(Scale::MINOR_PENTA, 0, 50), Scale::freq(Scale::MINOR_PENTA, 2, 50)], 3.2, 0.06); } $this->pulse = 1.0; $this->tint = Gfx::hsv($i / self::RINGS); } } foreach ($this->flash as $i => $f) { $this->flash[$i] = max(0.0, $f - $dt * 2.2); } } protected function drawWorld(Renderer $r): void { $d = $this->depth(); $base = floor($d); $frac = $d - $base; $cx = $r->getWidth() / 2; $cy = 262.0; // squares from the nearest (big) to the farthest (small); square j (0 = the one at the middle line) has radius R_MIN * ratio^(count - j - frac) $count = 17; for ($j = -3; $j < $count; $j++) { $g = (int)($base + $j); // the number of this square: its colour and twist $rad = self::R_MIN * self::RATIO ** ($count - $j - $frac - 3); if ($rad < 3 || $rad > 420) { continue; } $gi = (($g % self::RINGS) + self::RINGS) % self::RINGS; $hue = $gi / self::RINGS; $angle = $g * M_PI / 2 / self::RINGS + $this->time / self::PERIOD * M_PI / 2; $light = 0.55 + 0.45 * ($rad / 120 > 1 ? 1 : $rad / 120); $f = $this->flash[$gi] ?? 0.0; $rgb = Gfx::mix(Gfx::hsv($hue + 0.55, 0.62, $light), [255, 255, 255], $f * 0.7); $thick = max(1.0, $rad * 0.085) + $f * 1.5; $this->frame($r, $cx, $cy, $rad, $angle, $thick, $rgb); } Gfx::glow($r, $cx, $cy, 4, [255, 255, 255], 0.8); Gfx::disc($r, $cx, $cy, 2.2, [255, 255, 255]); } /** a hollow square: four bars */ private function frame(Renderer $r, float $cx, float $cy, float $rad, float $angle, float $thick, array $rgb): void { $pts = []; for ($i = 0; $i < 4; $i++) { $a = $angle + M_PI / 4 + $i * M_PI / 2; $pts[] = [$cx + cos($a) * $rad * M_SQRT2, $cy + sin($a) * $rad * M_SQRT2]; } for ($i = 0; $i < 4; $i++) { [$x1, $y1] = $pts[$i]; [$x2, $y2] = $pts[($i + 1) % 4]; if (max($x1, $x2) < -10 || min($x1, $x2) > 280 || max($y1, $y2) < -10 || min($y1, $y2) > 490) { continue; } Gfx::bar($r, $x1, $y1, $x2, $y2, $thick, $rgb); } } }