tilesetName = RomSprites::SHEET; } public function setButton(bool $held): void { $this->held = $held; } private function state(): int { return $this->step < 1 ? 0 : ($this->step < 4 ? 1 : 2); } /** @param array $player collision rect; ['vx', 'vy'] in px/frame */ protected function tick(array $player): void { if ($this->held) { $this->previous = $this->step; if ($this->step < 5) $this->step++; } elseif ($this->step > 0) { $this->step--; } $state = $this->state(); [$ox, $oy] = self::BOX[$state]; $sx = self::heroX($player); $sy = self::heroY($player); if (!($sx <= $this->x + 0x1E && $this->x + $ox <= $sx + 24 && $sy <= $this->y + 0x16 && $this->y + $oy <= $sy + 32)) { $this->slide = null; return; } $vx = $player['vx']; $vy = $player['vy']; // _9aaf: only coming down if ($vy < 0) { $this->slide = null; return; } $index = ((int)floor($sx) + 12 - (int)$this->x) & 31; $top = $this->y + self::SURFACE[$state][$index]; if ($vy >= 3 || $state === 1) { $this->slide = null; } if ($vy >= 3) { // too fast: bounces back at half speed $this->push = [$top, $vx, -$vy / 2]; return; } if ($state === 1) { // thrown while it swings up if ($this->previous < $this->step) { $this->push = [$top, $vx + self::LAUNCH_X[$index] / 256, self::LAUNCH_Y[$index] / 256 - $vy]; } else { $this->push = [$top, $vx, $vy]; } return; } // stands on it and slides down (the air drag of the Player would eat these 1/256 px steps) $this->slide = ($this->slide ?? $vx) + ($state === 0 ? -4 : 0x1A) / 256; $this->push = [$top, $this->slide, 0]; } public function render(float $cameraX, float $cameraY): void { $this->blit(RomSprites::FLIPPER[$this->state()], $this->x, $this->y + 1, $cameraX, $cameraY); } }