Burrr.io: многопользовательская игра в реальном времени про буры на круглой планете

Буры прокапывают круглую планету, растут, охотятся друг на друга и прячутся в тишине. Burrr.io — браузерная игра для компьютера и телефона: без установки, без регистрации, один клик по «Играть» — а за ней сервер на Go, который ведёт каждый матч, и рендер, настроенный так, чтобы телефон оставался холодным.

Burrr.io: многопользовательская игра в реальном времени про буры на круглой планете
Смотреть проект:
burrr.io
Burrr.io: многопользовательская игра в реальном времени про буры на круглой планете

Идея

Burrr.io — наш собственный продукт, а не заказ: многопользовательская игра в жанре .io — открываешь ссылку, вводишь ник, жмёшь «Играть», и через несколько секунд ты на общей карте с другими игроками. Вы управляете буром — круглой пилой, которая прокладывает туннели в земле, собирает руду и кристаллы, растёт вместе с очками и сражается с другими бурами. Игра работает в браузере на компьютере и на телефоне, на английском, испанском и русском.

У жанра известная слабость: через несколько минут всё сводится к «зажал кнопку и кружишь». Цель дизайна Burrr.io — обратная: настоящий выбор каждую минуту — куда копать, прятаться или нападать, стоит ли глубина риска.

Геймплей

Карта — планета в разрезе. Гравитация тянет к ядру, а породы лежат кольцами: мягкий грунт у поверхности, глубже глина и камень, затем базальт и магма, в ядре — лава. Чем глубже, тем труднее копать и тем богаче руда.

Грунт живой. Песок и гравий лежат линзами внутри прочной породы и обрушиваются в туннель под ними — на того, кто там копает. Подземные озёра затапливают туннели, когда кто-то пробивает их стенку, лава обжигает, газовые карманы отравляют или взрываются. Старые туннели постепенно зарастают, поэтому планета никогда не оказывается выкопанной.

Каждые несколько минут карта меняет планы всем: извержение магмы поднимается от ядра и выдавливает всю комнату к поверхности, или где-то падает метеорит, полный кристаллов, и становится местом, за которое дерутся.

Информация — оружие. Каждый бур видит только то, что в его прямой видимости: порода закрывает обзор, а по туннелю видно дальше, — остальное скрыто туманом войны. Каждый бур шумит — чем он крупнее и быстрее, тем громче, — и миникарта показывает расходящиеся круги этого шума, а не точные позиции. Заглушите двигатель — и вы исчезнете с сонара у всех: так становятся возможны засады.

Между матчами у игрока остаётся лёгкая прокачка: монеты из выкопанного золота, ежедневная награда, растущая с серией дней, арсенал предметов (мины, бластер, лазер, рывок, турель и другие) и двадцать воинских званий со знаками различия рядом с каждым ником — сразу видно, кто перед тобой. Сверху — медали за боевые подвиги и достижения за мирные: прокопать планету насквозь через ядро и выйти с другой стороны — это отдельная окраска корпуса.

Два режима: каждый сам за себя — до 40 игроков — и захват флага, где две команды прорываются к укреплённой базе соперника. Друзья могут попасть на одну карту вместе по коду или ссылке. В чате только готовые фразы, без свободного текста, который пришлось бы модерировать.

Сервер решает всё

В многопользовательской игре всё, что доверено клиенту, кто-нибудь подделает. В Burrr.io браузер отправляет только ввод — курс, ускорение, использовать предмет, тишина. Всё остальное считается на нашем сервере: движение, копание, урон, физика песка, воды, лавы и газа, боты, события карты. Логика игры идёт с частотой 20 тактов в секунду, физика грунта — 10.

Сервер написан на Go: каждая комната — одна карта и одна горутина, а такт не выделяет память. Протокол — наш собственный компактный двоичный формат поверх WebSocket; каждый игрок получает в каждом такте только то, что видит его бур, и только изменившиеся поля. Туман войны соблюдается на сервере: клиент просто никогда не получает позиции игроков, которых не видит, поэтому взломанному клиенту нечего раскрыть. Протокол описан один раз на Go, а общие тестовые векторы гарантируют, что клиент на TypeScript декодирует ровно то, что кодирует сервер.

Сама карта не стоит трафика. Планета генерируется из зерна, и генерация на Go и на TypeScript совпадает бит в бит — тесты сверяют контрольные суммы, — поэтому клиент строит ту же планету сам, а сервер присылает только то, что изменилось с тех пор.

Прогресс, статистика и таблицы лидеров тоже живут на сервере, в MySQL, поэтому их нельзя отредактировать в браузере.

Боты, которые играют как люди

Пустая комната — мёртвая игра, поэтому боты дополняют комнату «каждый сам за себя» до пятнадцати участников и уступают место, когда заходит живой игрок. Они сделаны неотличимыми от людей: в протоколе нет флага «бот», у них правдоподобные ники, те же окраски и пилы, что у людей, и звания по их силе, так что знак различия говорит правду и о боте. Решения они принимают только по тому, что видят и слышат, — тот же туман войны и тот же сонар, что у человека, поэтому тишина и засады работают и против них. Они учитывают опасности и события карты, а после гибели возвращаются через несколько секунд или иногда уходят из комнаты насовсем — и вместо них заходит кто-то новый.

Игра, которая не должна греть телефон

Телефон платит за каждый кадр нагревом и батареей, поэтому производительность — правило проекта, а не доработка в конце. Клиент рисует на PixiJS (WebGL); грунт рисует наш собственный шейдер, и это самое дорогое, что делает игра: каждая выборка текстуры в нём выполняется для каждого из сотен тысяч пикселей шестьдесят раз в секунду. Поэтому данные каждой клетки готовятся один раз на процессоре при загрузке куска карты, ранние выходы из шейдера обязаны давать ровно ту же картинку, а грунт и спрайты рисуются в двух разных разрешениях.

Та же дисциплина проходит через весь клиент: всё, что выводится из состояния игры, считается раз в такт или при изменении, а не каждый кадр; HTML-интерфейс получает только действительно изменившиеся значения; звук без громкости ничего не стоит; есть уровни качества графики и режим экономии батареи. Каждое изменение на этих путях измеряется на настоящем телефоне до и после. Профилирование на Galaxy S23 по счётчику заряда снизило собственное потребление игры примерно с 460 до 350 мА — на четверть.

Перенос симуляции из браузера на сервер служит той же цели: телефону больше не нужно считать мир и ботов, он только рисует то, что присылает сервер.

Инфраструктура

Клиент статический, его раздаёт Cloudflare Pages; игровой сервер и база данных работают на сервере Hetzner в Германии. Push в основную ветку разворачивается через GitLab CI. Деплой не обрывает матчи: новый процесс сервера запускается рядом со старым на тех же портах, а старый перестаёт принимать соединения и доигрывает свои комнаты — игроки режима «каждый сам за себя» переходят в новый процесс, начиная новую жизнь, а матчи захвата флага идут до конца.

Вместимость измеряется, а не предполагается: нагрузочный инструмент подключает к продакшену имитированных клиентов. Когда 160 из них заполняют четыре комнаты по 40, такт сервера занимает около 18 мс из бюджета в 50 мс — после раунда профилирования, убравшего повторную работу из восприятия и сетевых снимков. Админ-страница собирает продуктовую аналитику без cookie и подсказывает, когда понадобится сервер мощнее.

Технологии

- Клиент: TypeScript + Vite, PixiJS 8 (WebGL), собственный шейдер грунта, интерфейс на HTML/CSS
- Игровой сервер: Go (горутина на комнату, логика 20 тактов/с, физика грунта 10 Гц, такт без выделения памяти)
- Протокол: WebSocket, собственный двоичный формат, общие тестовые векторы для Go и TypeScript
- Карта: процедурная круглая планета, одинаково генерируемая из зерна на клиенте и сервере
- База данных: MySQL 8.4 (гостевые аккаунты, прогресс, статистика, таблицы лидеров, аналитика)
- Хостинг: Cloudflare Pages (клиент), Hetzner, Германия (сервер и база данных)
- CI/CD: GitLab CI, Docker, деплой, который даёт идущим матчам доиграть
- Инструменты: бенчмарк симуляции с контрольными суммами состояния, нагрузочные клиенты, админ-страница с продуктовой аналитикой
- Языки: английский, испанский, русский

Результат

Браузерная игра, которая запускается одним кликом на компьютере или телефоне, где каждый матч — живая планета: порода, которая обрушивается и затапливается, соперники, которых слышишь раньше, чем видишь, и боты, которых не отличить от людей. Под ней — авторитетный сервер на Go, который не оставляет читерам ничего для подделки, и рендер, измеренный на настоящем телефоне, чтобы матч не превращал его в грелку.

Играть в Burrr.io

Похожие кейсы

Estimia: честные цены на окна для всей Испании

Estimia: честные цены на окна для всей Испании

Покупка окон в Испании — это погоня за непрозрачными сметами установщиков, каждый из которых считает по-своему. Estimia решает это реальным онлайн-калькулятором, честными общенациональными ценами и 156 региональными страницами на основе реальных климатических данных и испанского строительного кодекса — и всё это на статическом сайте, который загружается мгновенно.

Ventanas Fraktal: 700+ страниц с мультиязычным SEO

Ventanas Fraktal: 700+ страниц с мультиязычным SEO

Полноценный каталог с десятками продуктов, техническими характеристиками, тремя языками и региональными страницами под каждую провинцию Испании. 700+ страниц на статической генерации с мгновенной загрузкой.

Web.Yatoday: Сайт как услуга

Web.Yatoday: Сайт как услуга

Создать платформу для запуска сайтов малому бизнесу с тремя требованиями: максимальная скорость загрузки, нулевое техническое обслуживание со стороны клиента, возможность масштабировать на десятки проектов без роста операционных затрат.