tilesetName = RomSprites::SHEET; $this->baseY = $tileY * 32; } protected function tick(array $player): void { $riding = $this->onLeft || $this->wasOnLeft; $this->weightY += $this->weightSpeed; $this->weightSpeed += self::GRAVITY; if ($this->push === null && $this->weightSpeed >= 0 && $this->weightY >= 0) { if ($this->depth !== 0) { $this->depth = self::MAX - (int)floor($this->weightY); if ($this->depth <= 0) { // Sonic rides the rising pad at the weight's speed and keeps it at the impact if ($riding) { $this->launch = $this->weightSpeed; $this->sounds[] = 0x04; } $this->rest(); } } else { $this->rest(); } } if ($this->landing !== null && $this->depth !== self::MAX) { $this->push = $this->landing; } $this->landing = null; if ($this->push !== null) { // every frame Sonic falls on it: the weight takes his speed, the pad goes down by it $this->weightSpeed = -$this->push; $this->depth += (int)floor($this->push); $this->push += self::GRAVITY; if ($this->depth >= self::MAX) { $this->depth = self::MAX; $this->push = null; } } $this->wasOnLeft = $this->onLeft; $this->onLeft = false; } private function rest(): void { $this->depth = 0; $this->weightSpeed = 0; $this->weightY = self::MAX; } /** Tops of the pads: [x, y, width, pad] for the ground of the GameObjectManager. */ public function getPads(): array { return [ [$this->x, $this->baseY + 16 + $this->depth, 24, 'left'], [$this->x + 40, $this->baseY + 16 + self::MAX - $this->depth, 24, 'right'], ]; } /** Sonic stands on a pad this frame ($vy: his speed in px/s when he lands). */ public function stand(string $pad, float $vy): void { if ($pad !== 'left') return; // a landing (not riding the pad): it pushes the pad down unless it is already down if (!$this->wasOnLeft && !$this->onLeft && $vy >= 0 && $this->push === null) { $this->landing = $vy / Player::V_SCALE; } $this->onLeft = true; } /** Speed (px/s, upwards, positive) Sonic is thrown at, once. */ public function takeLaunch(): ?float { $launch = $this->launch; $this->launch = null; return $launch === null ? null : $launch * Player::V_SCALE; } public function render(float $cameraX, float $cameraY): void { foreach ($this->getPads() as [$x, $y]) { $this->blit(RomSprites::SEESAW_PAD, $x, $y + 1, $cameraX, $cameraY); } $this->blit(RomSprites::SEESAW_WEIGHT, $this->x + 44, $this->baseY + $this->weightY + 1, $cameraX, $cameraY); } }