NL

SONIC PHP

door davidnurdin · Platformers
5,0 (1)
▶ Spelen 💬 Reacties van spelers Broncode 🕘 Versies Bewerken GitHub
. / src / Entities / Objects / Capsule.php · commit a20d00e
<?phpnamespace App\Entities\Objects;use App\Entities\GameObject;use App\Gfx\Gfx;/** * Animal capsule (object $25, doObjectCode_boss_capsule): 28x64, Y + 16 on load. Its top is rounded (_750e); * standing in the middle pushes the button down (_7540) and opens it: 8 explosions 20 frames apart, then the * top part is gone (no sprite, broken base _757c) and a freed animal comes out every 16 frames (12 in all) * while the act-complete countdown ($D289 = $A0 frames) runs. */class Capsule extends GameObject{    private const CLOSED = [[403, 97, 32, 64], [436, 97, 32, 64]];    private const PRESSED = [[469, 100, 32, 61]];    private const BROKEN = [[468, 162, 33, 24]];    // _750e: height of the top under Sonic's centre, 3 = on the button    private const PROFILE = [0x15, 0x12, 0x11, 0x10, 0x10, 0x0F, 0x0E, 0x0D, 3, 3, 3, 3, 3, 3, 3, 3,        3, 3, 3, 3, 3, 3, 3, 3, 0x0D, 0x0E, 0x0F, 0x10, 0x10, 0x11, 0x12, 0x15];    private const FRAME = 1 / 60;    private bool $opened = false;    private int $frames = 0;    private float $clock = 0;    private int $explosions = 0;    private int $animals = 0;    private bool $finished = false;    public function __construct(Gfx $sdl, int $tileX, int $tileY)    {        parent::__construct($sdl, 0x25, 'Capsule', $tileX * 32, $tileY * 32 + 16, 0x1C, 0x40);        $this->tilesetName = 'doctor';        $this->frameDuration = 16 / 60;        $this->animations = [            'closed' => ['flags' => [], 'coords' => self::frames(self::CLOSED)],            'pressed' => ['flags' => [], 'coords' => self::frames(self::PRESSED)],            'broken' => ['flags' => [], 'coords' => self::frames(self::BROKEN)],        ];        $this->setAnimation('closed');    }    public function isOpened(): bool { return $this->opened; }    public function isFinished(): bool { return $this->finished; }    /** Top of the capsule, where Sonic can stand (the button). */    public function getTop(): float    {        return $this->y + ($this->isBroken() ? self::PROFILE[0] + 24 : 3);    }    /** Height of the rounded top under a centre X, null outside of it. */    public function getTopAt(float $centerX): ?float    {        $rel = (int)floor($centerX - $this->x);        if ($rel < 0 || $rel > 31 || $this->isBroken()) return null;        return $this->y + self::PROFILE[$rel];    }    /** Sonic stands on the button (the middle of the top): drawn pushed down. */    public function isButtonAt(float $centerX): bool    {        $rel = (int)floor($centerX - $this->x);        return $rel >= 0 && $rel <= 31 && self::PROFILE[$rel] === 3;    }    public function press(): void    {        if (!$this->isBroken()) $this->setAnimation('pressed');    }    public function release(): void    {        $this->setAnimation('closed');    }    private function isBroken(): bool    {        return $this->opened && $this->explosions >= 8;    }    public function open(): void    {        if ($this->opened) return;        $this->opened = true;        $this->frames = 0;    }    /** Returns events: ['explosion', x, y] / ['part', BossPart] / ['complete']. */    public function think(float $deltaTime): array    {        $events = [];        $this->updateSprite($deltaTime);        if (!$this->opened || $this->finished) return $events;        $this->clock += $deltaTime;        while ($this->clock >= self::FRAME) {            $this->clock -= self::FRAME;            $this->frames++;            if ($this->explosions < 8) {                if ($this->frames % 20 === 0) {                    $this->explosions++;                    $events[] = ['explosion', $this->x + mt_rand(0, 28), $this->y + mt_rand(0, 48)];                    if ($this->explosions === 8) {                        $events[] = ['music', 'actcomplete'];                        $this->setAnimation('broken');                        $this->frames = 0;                    }                }                continue;            }            if ($this->animals < 12 && $this->frames % 16 === 0) {                $this->animals++;                $bird = mt_rand(0, 1) === 1;                $animal = (new BossPart($this->sdl, $this->x + 8 + 6, $this->y + 0x1A, $bird ? BossPart::BIRD : BossPart::RABBIT, 0.15))                    ->withVelocity(mt_rand(-90, 90), -mt_rand(120, 240));                $animal->harmful = false;                $animal->gravity = 600;                $animal->hopper = !$bird;                $animal->life = 4;                if ($bird) {                    $animal->gravity = -120;                }                $events[] = ['part', $animal];            }            if ($this->frames >= 0xA0 + 60) {                $this->finished = true;                $events[] = ['complete'];            }        }        return $events;    }}