Мультиплеерная игрушка на php и javascript: SDL, devtools-protocol

Давно, когда веб развивался, JavaScript обрастал возможностями, PHP завоевывал мир, появлялись первые
игры в браузере, а каждый юный разработчик, мечтал написать свою игрушку. С тех пор утекло много воды, php
потерял часть популярности, а JavaScript стал зрелым и развитым, но я все равно решил реализовать давнюю
мечту, и написать на этих языках.
Для разнообразия я напишу клиента на PHP, а сервер на JavaScript
С нуля придумывать сбалансированный сюжет и геймплей тяжело, поэтому я буду портировать одну старую игрушку
Jump ‘n Bump
Есть прекрасный порт на javascript с которым я буду сверяться, но он
без мультиплеера. Хорошо реализована клиентская часть, но именно её я собираюсь писать на PHP. Так что придется
построчно копировать и преобразовывать.
Клиент
Начнем с клиентской части. Это графика, анимация, управление и звук (правда, звуки сейчас не
реализованы).
Возможностей рисовать окошки и графику на php не так уж много, но есть PHP-модуль PHP-SDL.
SDL - это свободная кроссплатформенная мультимедийная библиотека, реализующая единый программный интерфейс к графической подсистеме, звуковым устройствам и средствам ввода для широкого спектра платформ.
То что надо.
Установка
Модуль sdl-php на OSX с M1 через pecl не устанавливается, но легко собирается:
1 | phpize |
Получившийся файл можно добавить в php.ini, либо указать при запуске
1 | php -d "extension=./bin/sdl.so" ./jnb.php |
Также потребуется парочка библиотек - react/promise для промисов и ratchet/pawl для работы с веб-сокетами. Их можно
установить через
1 | composer install |
Сервер
Сервер я буду писать на JavaScript. Проще всего было бы сделать это на Node.js, но, поскольку, JavaScript это
браузерный язык, я предпочту писать серверную часть в браузере.
Браузер можно запускать в headless режиме на сервере, поэтому браузерное окошко нам не будет мешать. Но для разработки
можно запускать браузер со средствами разработчика.
Взаимодействие с сервером
Итак, серверная часть запущена в браузере, а клиентская должна с ней взаимодействовать: получать координаты соперников и
отправлять свои действия. И, для нормального мультиплеера, хочется взаимодействовать по сети.
Решение есть - можно запускать браузер с поддержкой удаленной отладки, а PHP-клиенты будут подключаться как отладочные
инструменты. Я запускаю отдельный процесс хромиума с параметром --remote-debugging-port
1 | /Applications/Chromium-102.app/Contents/MacOS/Chromium --remote-debugging-port=9222 jnb.html |
Таким образом, клиентская часть может делать запросы на сервер, на котором запущен браузер, на порт 9222, подключаться
по веб-сокетам, вызывать функции через console API, читать вывод в консоль.
Подключение к инстансу
Первым запросом получим список открытых вкладок (GET /json/list)
1 | $service_url = 'http://127.0.0.1:9222/json/list'; |
В ответ получаем JSON содежащий список вкладок. Скорее всего, вкладка только одна, но если открыты инструменты
разработчика, то в получим дополнительно запись о них. Поэтому лучше проверять url вкладки, например,
при помощи функции str_ends_with
У найденной вкладке будет значение webSocketDebuggerUrl - адрес, по которому следует соединяться вебсокетом.
1 | foreach ($tabs as $tab) { |
По веб-сокета будут приходить ответы за запросы клиента, мы будем их получать в одном обработчике, который будет
распределять ответы по id, и вызывать callback-функцию. Список обработчиков будет храниться в переменной $callbacks
1 | $connection->on('message', function($msg) { |
В объект $callbacks складываются колбэки при вызове функций. Вызов функций осуществляется отправкой в веб-сокет
сообщения
1 | { |
А так выглядит вызов функции на PHP. Возвращается Promise, генерируется id, а в объекте $callbacks запоминается
функция, которую надо вызвать (потом, когда из вебсокета придет ответ по этой функции, колбэк будет вызван и Promise станет
заершенным)
1 | function runtime_evaluate($code) { |