- PVSM.RU - https://www.pvsm.ru -

Bomberman Online и хабраэффект — 450 игроков на одной карте. Отчёт и детали игрового движка

Bomberman Online и хабраэффект — 450 игроков на одной карте. Отчёт и детали игрового движка

Как и обещали в топике-анонсе [1] нашей игры [2], выкладываем отчёт о хабраэффекте и детали игрового движка.

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

 

Статистика за 3 недели

Зарегистрировано игроков: 4 663
Сыграно раундов: 2 252
Кол-во игроков (включая гостей): 13 402
Кол-во фрагов: 469 534
Кол-во смертей: 545 957
Кол-во забитых мячей: 1 707 (WTF [3]?)

[во время хабраэффекта]
Игроков онлайн (максимум): 453
Загрузка ЦП: 168%
Использование памяти: 1.65 ГБ
Трафик (максимум): исходящий 24 Мбит/с | входящий 9 Мбит/с

(Графики кликабельны)

[Engine] Connections [1 [4]]
Bomberman Online и хабраэффект — 450 игроков на одной карте. Отчёт и детали игрового движка [5]
[Engine] Main cycle time [2 [6]]
Bomberman Online и хабраэффект — 450 игроков на одной карте. Отчёт и детали игрового движка [7]
[Engine] Bytes per send [3 [8]]
Bomberman Online и хабраэффект — 450 игроков на одной карте. Отчёт и детали игрового движка [9]
[Server] CPU usage
Bomberman Online и хабраэффект — 450 игроков на одной карте. Отчёт и детали игрового движка [10]
[Server] Memory usage
Bomberman Online и хабраэффект — 450 игроков на одной карте. Отчёт и детали игрового движка [11]

ТТХ

Хостинг [12]: выделенный сервер [12] в ЦОД Владимир (который любезно предоставлен на время хабратестирования)

1. Игровой движок на Java & Jetty
2. HAProxy — проксирование вебсокетов
3. Nginx — статика и проксирование к ноде
4. Веб-функционал — Node.js (packages: express, mysql, request, nodemailer, validator, moment, forever)
5. Клиентсайд — GWT, транслируемый в javascript

 

Детали игрового движка

Далее — от лица Jedi_Knight [13] (автора движка).

Разработка игровых приложений на канвасе — перспективное направление, в котором сейчас двигаются многие группы разработчиков, например эстонский проект mightyfingers.com [14]

Некоторые идеи взяты из статьи www.html5rocks.com/en/tutorials/canvas/performance/ [15]

Основы Тайлизма на HTML5 canvas

Терминология: тайл — один квадратик, например 32×32; чанк — 8×8 тайлов.

Рассмотрим особенности тайлового движка. Вот модель, к которой я пришёл:

1) Субпиксельная прорисовка для тайлов просто не нужна.

2) Используется несколько прозрачных canvas-ов, расположенных друг на друге. Если terrain не модифицировался, не было скроллинга, то его можно не перерисовывать — это даёт небольшой прирост производительности (по сравнению с оптимизацией кешом).

3) Так же как и в модели игры, всё поле делится на чанки 8×8. Поскольку 64 вызова drawImage для изображений 32×32 стоят гораздо дороже одного вызова для 256×256, видимые чанки отрисовываются в кеш, состоящих из двух слоёв: под игроком и над ним.

4) Кеш ассоциативный, то есть пара canvas'ов используется нескольким чанкам на карте: чанк с координатами (X, Y) использует кеш с координатами (X mod A, Y mod B) где (A, B) — размеры кеша. При этом размеры кеша должны быть такими, чтобы на экране не появлялись одновременно два чанка с общим кешом, будет гонка.

5) Кроме canvas-ов в кеше запоминаются номера тайлов из текстуры, которые генерируются по логической карте. По номеру можно однозначно отрисовать тайл.

6) При изменении видимого чанка, соответствующий ему объект в кеше помечается как грязный, требующий перерисовки. При этом соседние чанки тоже могут быть помечены как грязные: мало ли, вдруг туда тень новая падает, или там надо нарисовать срез камня.

7) В случае если требуется перерисовать грязный или новый чанк, снала в буфер кладется таблица 10×10 — чанк и окружающие его тайлы. По этому буферу генерируется массив номеров тайлов — он уже 8×8. Номер тайла также может содержать информацию о тени, падающей на этот тайл. В тех местах, где номер тайла изменился с прошлого раза, происходит перерисовка.

8) Для тайлов удобнее использовать не drawImage, а createPattern и fillRect. fillRect также удобнее тем, что им можно нарисовать несколько одинаковых подряд идущих тайлов, и это будет быстрее.
Данный тест раскрывает странный эффект: что для текстур 32×32 есть существенный прирост производительности на айпаде в 2.5 раза:
jsperf.com/canvas-texture-draw-vs-fill [16]

Bomberman Online и хабраэффект — 450 игроков на одной карте. Отчёт и детали игрового движка9) И наконец зачем всё это надо: при скроллинге вместо рисования кучи мелких изображений 32×32 происходит рисование из кеша. Вызовов drawImage существенно меньше, это серьёзно влияет на производительность.

Зелёный, жёлтый, тени — рисуются на первом слое, каждый квадрат 32×32 может рисоваться независимо от других, так как номер тайла содержит информацию о подложке, стене и тени.
Красным рисуется второй слой, он сдвинут на 8 пикселей вверх.

 
 
 

Найденные баги

Итак, в ходе коллективного тестирования были обнаружены следующие проблемы:

1) На большой карте определённого размера внезапно заглючил тайловый кеш, что привело к диким тормозам, с которыми справлялся только хром. Всё дело было в периодической карте: размеры карты (W,H) должны делиться на размеры кеша (A, B).

Bomberman Online и хабраэффект — 450 игроков на одной карте. Отчёт и детали игрового движка

Пусть W,H=7 A,B=3, угловые чанки попадают на одну позицию кеша, а на периодической карте они попадают на один экран, что приводит к гонке. Та же ситуация наблюдается по всему “шву” карты.

2) Профилировка клиента выявила узкие места в коде, использующим java-коллекции. В этих местах коллекции заменены на самописные структуры.

3) Изменение сетевого протокола и переход с utf8 на бинарные вебсокеты в тех браузерах, где они поддерживаются (Chrome, Firefox) позволили сократить средний трафик клиента до 12 Кбит/с. Используется нативный ArrayBuffer, отмечу что в Firefox не реализован класс DataView, поэтому обходимся обычным Uint8Array.

 

На графиках в начале статьи показаны:

[1] Connections — количество активных соединений с сервером.

[2] Main cycle time — сколько занимают различные стадии главного цикла. Тик длится 100мс, preprocess — проверка команд от клиентов, tick — апдейт игрового состояния, Observers — формирование сообщений для клиентов. Total — всё вместе, и плюс время за которое сообщения уйдут в сетевой буфер. Измеряется в затраченных миллисекундах внутри одной секунды, так что когда Total приближается к 1000 — серверу плохо, начинает появляться overhead.

[3] Bytes per send — чистый трафик, отправляемый клиентам, без заголовков websocket-фреймов, в байтах/сек.

 

Изменения геймплея

Bomberman Online и хабраэффект — 450 игроков на одной карте. Отчёт и детали игрового движкаПочти всё время ушло на ускорение движка, клиента и сетевого протокола. Была проведена серьезная работа по оптимизации и рефакторингу, устранена масса багов.

Но немножко удалось сделать и по геймплею: запереть врага стало легче. Но самое главное — добавлен мячик и ворота! Забившие получают спасательный щит. Особо проворные собирают по 3 щита и бегают как супергерои :)

 

Новое нагрузочное хабратестирование. Цель — 1000 игроков онлайн на одной карте

В первый раз сервер без проблем и лагов держал 350 игроков онлайн. Сегодня он готов к 1000.

Мы приглашаем всех 8 и 9 июня, с 17 до 22 постараться достигнуть новой планки игроков онлайн. Присоединяйтесь [2], зовите друзей/коллег — мы ждём вас!

Специально для читательов мы подготовили Хабрамонитор [17], который показывает графики текущей нагрузки на движок и сервер (с интервалом в 5 минут).

Bomberman Online и хабраэффект — 450 игроков на одной карте. Отчёт и детали игрового движкаИ да пребудет с вами Сила и Фан.

Автор: demark


Сайт-источник PVSM.RU: https://www.pvsm.ru

Путь до страницы источника: https://www.pvsm.ru/java/9224

Ссылки в тексте:

[1] топике-анонсе: http://habrahabr.ru/post/143699/

[2] нашей игры: http://bombermine.ru

[3] WTF: #football

[4] 1: #g1

[5] Image: http://habrastorage.org/storage2/cb8/b86/197/cb8b86197cd42cb5ab85c25dfafc6bcd.png

[6] 2: #g2

[7] Image: http://habrastorage.org/storage2/ebc/073/8a8/ebc0738a84b13d359f242c94e6246b58.png

[8] 3: #g3

[9] Image: http://habrastorage.org/storage2/1c8/b41/751/1c8b41751de3080d0116493310affdcd.png

[10] Image: http://habrastorage.org/storage2/7d4/cde/599/7d4cde599fd12657b2b78751eaeec0f6.png

[11] Image: http://habrastorage.org/storage2/d63/e85/cc0/d63e85cc0c1a3da417389ce3657a4df7.png

[12] Хостинг: https://www.reg.ru/?rlink=reflink-717

[13] Jedi_Knight: http://habrahabr.ru/users/jedi_knight/

[14] mightyfingers.com: http://mightyfingers.com

[15] www.html5rocks.com/en/tutorials/canvas/performance/: http://www.html5rocks.com/en/tutorials/canvas/performance/

[16] jsperf.com/canvas-texture-draw-vs-fill: http://jsperf.com/canvas-texture-draw-vs-fill

[17] Хабрамонитор: http://bombermine.ru/habraeffect/