Inloggen
NL
games/doom-jumphp / src / Engine / Art.php · commit 8e1cb9f
<?phpnamespace App\Engine;/** * Every picture of the game (assets/data/art.pak, made by tools/make-art.php): wall textures (column-major), * flats (64 x 64 row-major), sprites (column-major, index 255 transparent), first-person weapons, status bar. * Darkened copies are made on demand with strtr() and kept: the renderer then reads plain bytes. */final class Art{    public array $walls;    public array $flats;    public array $sprites;    public array $weapons;    public array $hud;    public array $sky;    /** @var array<string, array<int, string>> */    private array $wallShades = [];    private array $flatShades = [];    private array $spriteShades = [];    /** animated flats: base name => current frame name */    public array $flatFrame = [];    private static ?self $instance = null;    public function __construct(string $pakFile)    {        $pak = unserialize((string)file_get_contents($pakFile));        if (!is_array($pak)) {            throw new \RuntimeException("Cannot read $pakFile");        }        $this->walls = $pak['walls'];        $this->flats = $pak['flats'];        $this->sprites = $pak['sprites'];        $this->weapons = $pak['weapons'];        $this->hud = $pak['hud'];        $this->sky = $pak['sky'];        foreach ($this->walls as &$w) {            $w['wmask'] = $w['w'] - 1;            $w['hmask'] = $w['h'] - 1;        }        unset($w);    }    /** One instance for the whole program: the pack is read once. */    public static function get(string $pakFile): self    {        return self::$instance ??= new self($pakFile);    }    public function wall(string $name, int $level): string    {        return $this->wallShades[$name][$level] ??= Palette::darken($this->walls[$name]['px'] ?? $this->walls['TECH']['px'], $level);    }    public function flat(string $name, int $level): string    {        $name = $this->flatFrame[$name] ?? $name;        return $this->flatShades[$name][$level] ??= Palette::darken($this->flats[$name] ?? $this->flats['FLOOR1'], $level);    }    /** The shaded column-major pixels of a sprite picture. */    public function spritePixels(array $pic, string $key, int $level): string    {        return $this->spriteShades[$key][$level] ??= Palette::darken($pic['px'], $level);    }    /** Animated flats: ACID1 -> ACID1..3, a frame every 8 tics (p_spec.c's anims). */    public function animate(int $tic): void    {        $k = intdiv($tic, 8) % 3 + 1;        foreach (['ACID', 'LAVA', 'BLOOD'] as $base) {            for ($i = 1; $i <= 3; $i++) {                $this->flatFrame[$base . $i] = $base . ((($i - 1 + $k - 1) % 3) + 1);            }        }    }    /**     * The picture of a sprite frame for a view rotation 1..8 (0 = the same for every angle).     * @return array{0: array, 1: string}|null the picture and its cache key     */    public function spriteFrame(string $sprite, string $frame, int $rot): ?array    {        $f = $this->sprites[$sprite][$frame] ?? null;        if ($f === null) {            return null;        }        if (isset($f[0])) {            return [$f[0], "$sprite$frame" . '0'];        }        return [$f[$rot], "$sprite$frame$rot"];    }}