RU

Elfs & Orcs Tower Defense

автор: malabke · Стратегия
5,0 (1)
▶ Играть 💬 Отзывы Исходники 🕘 Версии Править GitHub
games/elfs-orcs-tower-defense / src / View3d / Props.php · commit 65500d9
<?phpnamespace App\View3d;/** * The small things of the battle in 3D: projectiles (each facing +x, about its own length), walls and traps on the * road, the mound of an enemy under the road, and the plain shapes (disc, ring, ball) used for shadows, ranges, * blasts and glows. */final class Props{    /** A flat disc of radius 1 facing up, white (tinted when drawn). */    public static function disc(): Mesh    {        return (new Mesh())->cyl([0, 0, 0], 1.0, 1.0, 0.02, [1.0, 1.0, 1.0], 20);    }    /** A soft shadow of radius 1 (material SOFT: the shader fades it out towards its edge). */    public static function softDisc(): Mesh    {        return (new Mesh())->material(Mesh::SOFT)->cyl([0, 0, 0], 1.0, 1.0, 0.01, [1.0, 1.0, 1.0], 20);    }    /** A flat ring of outer radius 1, inner 0.93. */    public static function ring(): Mesh    {        $m = new Mesh();        $w = [1.0, 1.0, 1.0];        for ($i = 0; $i < 40; $i++) {            $a = 2 * M_PI * $i / 40;            $b = 2 * M_PI * ($i + 1) / 40;            $m->quad([[cos($a) * 0.93, 0.0, sin($a) * 0.93], [cos($a), 0.0, sin($a)], [cos($b), 0.0, sin($b)], [cos($b) * 0.93, 0.0, sin($b) * 0.93]],                [0, 1, 0], [$w, $w, $w, $w]);        }        return $m;    }    /** A ball of radius 1. */    public static function ball(): Mesh    {        return (new Mesh())->ball([0, 0, 0], [1.0, 1.0, 1.0], [1.0, 1.0, 1.0], 8, 5);    }    /** What flies: a model by kind (arrow bolt javelin stone rock pitch spark orb note star). */    public static function projectile(string $kind): Mesh    {        $m = new Mesh();        $wood = Mesh::rgb('#d8c8a0');        switch ($kind) {            case 'bolt':                $m->box([0, 0, 0], [5.0, 0.8, 0.8], Mesh::rgb('#8a8a94'));                $m->cyl([2.5, 0, 0], 0.9, 0.0, 2.0, Mesh::rgb('#d0d0d8'), 4, [0, 0, -M_PI / 2]);                break;            case 'javelin':                $m->box([0, 0, 0], [8.0, 0.7, 0.7], Mesh::rgb('#9a7040'));                $m->cyl([4.0, 0, 0], 0.9, 0.0, 2.6, Mesh::rgb('#d0d0d8'), 4, [0, 0, -M_PI / 2]);                break;            case 'stone':                $m->ball([0, 0, 0], [1.1, 1.1, 1.1], Mesh::rgb('#c0c0b4'), 5, 3);                break;            case 'rock':                $m->ball([0, 0, 0], [2.6, 2.3, 2.6], Mesh::rgb('#7a766c'), 6, 4);                break;            case 'pitch':                $m->ball([0, 0, 0], [2.2, 2.2, 2.2], Mesh::rgb('#241c24'), 6, 4);                $m->ball([0, 1.4, 0], [1.3, 1.6, 1.3], Mesh::rgb('#ff8a20', 1.4), 5, 3);                break;            case 'spark':                $m->ball([0, 0, 0], [1.6, 1.6, 1.6], Mesh::rgb('#ffa030', 1.5), 5, 3);                break;            case 'orb':                $m->ball([0, 0, 0], [2.0, 2.0, 2.0], Mesh::rgb('#9ab8ff', 1.4), 6, 4);                $m->ball([0, 0, 0], [1.0, 1.0, 1.0], Mesh::rgb('#ffffff', 1.4), 5, 3);                break;            case 'note':                $m->ball([0, 0, 0], [1.5, 1.3, 1.5], Mesh::rgb('#ffdc5a', 1.4), 5, 3);                $m->box([1.0, 2.2, 0], [0.5, 3.6, 0.5], Mesh::rgb('#ffdc5a', 1.4));                break;            case 'star':                $m->box([0, 0, 0], [4.4, 0.8, 0.8], Mesh::rgb('#fff08c', 1.5));                $m->box([0, 0, 0], [0.8, 4.4, 0.8], Mesh::rgb('#fff08c', 1.5));                $m->box([0, 0, 0], [0.8, 0.8, 4.4], Mesh::rgb('#fff08c', 1.5));                break;            default: // arrow                $m->box([0, 0, 0], [6.0, 0.5, 0.5], $wood);                $m->cyl([3.0, 0, 0], 0.8, 0.0, 1.8, Mesh::rgb('#d0d0d8'), 4, [0, 0, -M_PI / 2]);                $m->box([-2.8, 0, 0], [1.4, 0.2, 1.6], Mesh::rgb('#e8e0c8'));        }        return $m;    }    /** A wall of stakes across the road, facing +x (it lies along z). $stone: a stone rampart. */    public static function wall(bool $stone, bool $standing, bool $spiked): Mesh    {        $m = new Mesh();        $wood = Mesh::rgb('#9a7040');        $dark = Mesh::rgb('#6a4a26');        $rock = Mesh::rgb('#9a9a92');        if (!$standing) {            foreach ([-10.0, -4.0, 3.0, 9.0] as $z) {                $m->slab([0, 0, $z], [2.0, 2.4, 1.8], $dark, [0, 0, 0.3]);            }            return $m;        }        if ($stone) {            $m->slab([0, 0, 0], [5.0, 12.0, 28.0], $rock);            for ($z = -12.0; $z <= 12.0; $z += 6.0) {                $m->slab([0, 12.0, $z], [5.4, 2.4, 3.4], Mesh::rgb('#7a7a74'));            }            return $m;        }        foreach ([-12.0, -8.0, -4.0, 0.0, 4.0, 8.0, 12.0] as $i => $z) {            $h = 12.0 + ($i % 2) * 2.0;            $m->cyl([0, 0, $z], 1.7, 1.5, $h, $i % 2 ? $dark : $wood, 5);            $m->cyl([0, $h, $z], 1.7, 0.0, 3.4, $wood, 5);        }        $m->slab([1.6, 4.0, 0], [0.8, 1.4, 27.0], $dark);        if ($spiked) {            foreach ([-10.0, -3.0, 4.0, 10.0] as $z) {                $m->cyl([2.6, 6.0, $z], 0.8, 0.0, 4.4, Mesh::rgb('#b8b8c0'), 4, [0, 0, -M_PI / 2]);            }        }        return $m;    }    /** A trap on the road: open jaws (armed) or a closed plate. */    public static function trap(bool $armed): Mesh    {        $m = new Mesh();        $iron = Mesh::rgb($armed ? '#b0b0b8' : '#5a5048');        $m->slab([0, 0, 0], [9.0, 0.7, 7.0], Mesh::rgb('#4a4038'));        if ($armed) {            foreach ([-1, 1] as $side) {                for ($i = -3; $i <= 3; $i += 2) {                    $m->cyl([$i * 1.2, 0.7, $side * 2.6], 0.55, 0.0, 2.4, $iron, 4, [0, 0, 0.0]);                }            }        }        return $m;    }    /** The earth that moves above a tunnelling enemy. */    public static function mound(): Mesh    {        $m = new Mesh();        $m->ball([0, 0.4, 0], [5.0, 2.8, 4.2], Mesh::rgb('#8a6444'), 6, 3);        $m->ball([-3.0, 0.3, 1.5], [2.4, 1.4, 2.0], Mesh::rgb('#a07a54'), 5, 3);        return $m;    }}