pendulum => swings completed (the right end reached) */ private array $swings = []; /** @var array */ private array $flash = []; protected function melodyNotes(): string { return 'C4'; } protected function headingText(): string { return 'PENDULUM WAVE'; } protected function hookText(): string { return 'WAIT FOR THEM TO LINE UP'; } protected function captionText(): string { return $this->t('SWINGS {n}', ['n' => array_sum($this->swings)]); } protected function build(): void { $this->swings = array_fill(0, self::COUNT, -1); $this->flash = array_fill(0, self::COUNT, 0.0); } /** the angle of pendulum $i at $time (it is at its right end whenever $time * (14 + i) / PERIOD is a whole number) */ public static function angle(int $i, float $time): float { return 0.27 * cos(2 * M_PI * (14 + $i) * $time / self::PERIOD); } public function swings(int $i): int { return $this->swings[$i]; } protected function tick(float $dt): void { for ($i = 0; $i < self::COUNT; $i++) { $n = (int)floor((14 + $i) * $this->time / self::PERIOD + 1e-9); if ($n > $this->swings[$i]) { $this->swings[$i] = $n; $this->flash[$i] = 1.0; $this->play(Scale::freq(Scale::MAJOR_PENTA, 2 + $i, 55), 'marimba', 0.8, 0.12, 0.0); $this->pulse = max($this->pulse, 0.3); $this->tint = Gfx::hsv($i / self::COUNT); } $this->flash[$i] = max(0.0, $this->flash[$i] - $dt * 3.5); } } protected function drawWorld(Renderer $r): void { $gap = (270 - 50) / (self::COUNT - 1); Gfx::bar($r, 18, self::TOP, 252, self::TOP, 4, [120, 126, 190]); for ($i = 0; $i < self::COUNT; $i++) { $len = 300.0 / (1 + 0.78 * ($i / (self::COUNT - 1))) ** 2; // longer ones swing slower $px = 25 + $i * $gap; $a = self::angle($i, $this->time); $x = $px + sin($a) * $len; $y = self::TOP + cos($a) * $len; $rgb = Gfx::hsv($i / self::COUNT * 0.85 + 0.02, 0.55, 1.0); $f = $this->flash[$i]; Gfx::bar($r, $px, self::TOP, $x, $y, 0.9, Gfx::mix(Gfx::BG_BOTTOM, $rgb, 0.75)); Gfx::glow($r, $x, $y, 7 + 3 * $f, $rgb, 0.6 + 0.8 * $f); Gfx::disc($r, $x, $y, 7 + 1.5 * $f, Gfx::mix($rgb, [255, 255, 255], $f * 0.8)); Gfx::disc($r, $x - 2.2, $y - 2.4, 2, [255, 255, 255], 190); } } }