로그인
KO
games/webrtc-demo / src / Scene / TitleScene.php · commit 87ad512
<?phpnamespace App\Scene;use App\Net\Rtc;use App\Ui\Look;use JumPHP\Kernel\Platform;use JumPHP\Native\Shell;use JumPHP\Net\LobbyScene;use JumPHP\Renderer\Renderer;use JumPHP\Scene\AbstractScene;use JumPHP\Util\Lang;use JumPHP\WebRtc\WebRtc;/** The main menu: the two demos, online play, the language, the tutorial and the documentation. Keys, mouse or touch. */final class TitleScene extends AbstractScene{    private const DOCS = 'https://jumphp.net/extensions/jumphp/webrtc/';    private const BW = 190;    private const BH = 13;    private const TOP = 50;    private const GAP = 15;    private int $selected = 0;    private string $backend = '';    private string $message = '';    private float $time = 0;    public function __construct(private WebRtc $webrtc)    {    }    public function enter(array $params = []): void    {        Look::apply($this->engine, $params);        $this->selected = 0;        $this->time = 0;        $this->message = (string)($params['message'] ?? '');        $this->backend = Rtc::prepare($this->webrtc);    }    /** @return list<array{0: string, 1: callable, 2?: callable}> [text, on press, on left / right] */    private function items(): array    {        $items = [            [Lang::t('Two peers on this screen'), fn () => $this->scenes()->switchTo(LinkScene::class)],            [Lang::t('Play online (2 players)'), fn () => $this->online()],            [Lang::t('Practice against a bot'), fn () => $this->scenes()->switchTo(DuelScene::class, ['mode' => 'bot'])],            ['< ' . Lang::t('Language: {name}', ['name' => Look::LANGUAGES[$this->engine->lang->getLang()] ?? 'English']) . ' >',                fn () => Look::cycle($this->engine, 1), fn (int $dir) => Look::cycle($this->engine, $dir)],            [Lang::t('Tutorial') . '  ·  ' . Lang::t('Documentation'), fn () => $this->open(self::DOCS . 'tutoriel')],        ];        if (Platform::isDesktop()) {            $items[] = [Lang::t('Quit'), fn () => $this->engine->quit()];        }        return $items;    }    private function online(): void    {        if (!Rtc::real($this->webrtc)) {            $this->message = 'Online play needs real WebRTC: a browser, or GStreamer on Linux.';            return;        }        $this->scenes()->switchTo(LobbyScene::class, ['next' => DuelScene::class, 'nextParams' => ['mode' => 'online'],            'back' => self::class, 'players' => 2]);    }    private function open(string $url): void    {        Platform::isWasm() ? $this->engine->bridge->send('open', ['url' => $url]) : Shell::openUrl($url);    }    public function update(float $dt): void    {        $this->time += $dt;        $items = $this->items();        $n = count($items);        $a = $this->actions();        if ($a->isPressed('up')) {            $this->selected = ($this->selected + $n - 1) % $n;        }        if ($a->isPressed('down')) {            $this->selected = ($this->selected + 1) % $n;        }        $x = ($this->width() - self::BW) / 2;        foreach ($items as $i => $item) {            $y = self::TOP + $i * self::GAP;            if (Look::hover($this->engine, $x, $y, self::BW, self::BH) && $this->engine->input->getMouse()->isPressed(1)) {                $this->selected = $i;                $item[1]();                return;            }        }        $item = $items[$this->selected] ?? null;        if ($item === null) {            return;        }        if ($a->isPressed('confirm') || $a->isPressed('send')) {            $item[1]();        } elseif (isset($item[2]) && ($a->isPressed('left') || $a->isPressed('right'))) {            $item[2]($a->isPressed('left') ? -1 : 1);        }    }    public function render(Renderer $r): void    {        $r->clear(Look::BG);        $w = $this->width();        // two peers and the packets between them        for ($i = 0; $i < 4; $i++) {            $t = fmod($this->time * 0.6 + $i / 4, 1.0);            $r->fillCircle(40 + $t * ($w - 80), 18, 1.5, $i % 2 ? Look::OTHER : Look::ME);        }        $r->fillRect(28, 12, 12, 12, Look::ME);        $r->fillRect($w - 40, 12, 12, 12, Look::OTHER);        $font = $this->font();        $font->draw($r, 'WebRTC', $w / 2, 8, 2, [255, 255, 255], 'center');        $font->draw($r, Lang::t('Peer to peer from PHP, in your browser'), $w / 2, 32, 1, Look::MUTED, 'center');        $x = ($w - self::BW) / 2;        foreach ($this->items() as $i => $item) {            $y = self::TOP + $i * self::GAP;            Look::button($r, $this->engine, $x, $y, self::BW, self::BH, $item[0], $i === $this->selected);        }        $bottom = $this->height() - 12;        if ($this->message !== '') {            $font->draw($r, Lang::t($this->message), $w / 2, $bottom - 11, 1, [255, 120, 120], 'center');        }        $font->draw($r, Lang::t('WebRTC here: {what}', ['what' => Lang::t(Rtc::describe($this->backend))]), $w / 2, $bottom, 1, Look::MUTED, 'center');    }}