<?phpnamespace App\Game;use App\Engine\Map\Level;/** What the HD renderer needs from the world: the things to draw and the lights of the moment. */final class HdView{ /** Light colours of things (r, g, b 0..1, radius). */ private const GLOW = [ 'lamp' => [1.0, 0.85, 0.5, 300], 'column' => [0.3, 0.9, 1.0, 240], 'orb' => [0.3, 0.5, 1.0, 220], 'redkey' => [1.0, 0.2, 0.15, 110], 'bluekey' => [0.2, 0.4, 1.0, 110], 'yellowkey' => [1.0, 0.9, 0.2, 110], 'acidball' => [0.35, 1.0, 0.25, 260], 'plasma' => [0.3, 0.55, 1.0, 300], 'ionball' => [0.3, 0.95, 1.0, 300], 'barrel' => [0.25, 0.9, 0.25, 90], 'vial' => [0.2, 0.5, 1.0, 80], 'cells' => [0.2, 0.8, 1.0, 70], ]; /** @return array<int, array> [x, y, z, angle, sprite, frame, bright, light 0..1] */ public static function things(World $w, float $alpha, float $ex, float $ey, float $angle): array { $out = []; $fx = cos($angle); $fy = sin($angle); foreach ($w->mobjs as $mo) { if ($mo === $w->player->mo || !$mo->visible || $mo->sprite === '') { continue; } $x = $mo->px + ($mo->x - $mo->px) * $alpha; $y = $mo->py + ($mo->y - $mo->py) * $alpha; $dx = $x - $ex; $dy = $y - $ey; if ($dx * $fx + $dy * $fy < -64 || $dx * $dx + $dy * $dy > 3000 * 3000) { continue; } $out[] = [$x, $y, $mo->pz + ($mo->z - $mo->pz) * $alpha, $mo->angle, $mo->sprite, $mo->frame, $mo->bright, ($mo->sector === null ? 160 : $mo->sector->light) / 255]; } return $out; } /** The 8 lights that matter most here: [x, y, z, radius, r, g, b]. */ public static function lights(World $w, float $ex, float $ey, float $ez, float $angle): array { $p = $w->player; $all = []; if ($p->flashTics > 0) { $k = $p->weapon === 5 ? [0.4, 1.0, 1.1] : [1.5, 1.1, 0.6]; $all[] = [$ex + cos($angle) * 24, $ey + sin($angle) * 24, $ez - 6, 480, ...$k]; } foreach ($w->mobjs as $mo) { $g = self::GLOW[$mo->type] ?? null; if ($g === null && $mo->bright) { // explosions, muzzle flashes of the monsters, sparks $g = match (true) { $mo->type === 'puff' => [0.8, 0.6, 0.3, 80], $mo->type === 'barrel' => [1.4, 0.8, 0.35, 380], default => [0.9, 0.55, 0.25, 200], }; } if ($g === null || $mo->removed) { continue; } $all[] = [$mo->x, $mo->y, $mo->z + max(8, $mo->height * 0.7), $g[3], $g[0], $g[1], $g[2]]; } usort($all, fn ($a, $b) => (hypot($a[0] - $ex, $a[1] - $ey) - $a[3]) <=> (hypot($b[0] - $ex, $b[1] - $ey) - $b[3])); return array_slice($all, 0, 8); } /** Lights of a level without a world (the title screen): its lamps and columns. */ public static function levelLights(Level $level, float $ex, float $ey): array { $all = []; foreach ($level->things as $t) { $g = self::GLOW[$t['type']] ?? null; if ($g !== null) { $z = $level->sectorAt($t['x'], $t['y'])->floor + 50; $all[] = [$t['x'], $t['y'], $z, $g[3], $g[0], $g[1], $g[2]]; } } usort($all, fn ($a, $b) => hypot($a[0] - $ex, $a[1] - $ey) <=> hypot($b[0] - $ex, $b[1] - $ey)); return array_slice($all, 0, 8); }}