[Из песочницы] Node.js + HTML5 + js = online action game
Давно задавался вопросом, а почему же написание онлайн игр на node.js является таким редким явлением, особенно на хабре? Ведь какие дифирамбы пели ноде при ее появлении, и сколько пророчили хорошего (или нехорошего) сей платформе, а новых продуктов что-то не сильно прибавляется.
Я решил проверить, действительно ли такой подход и игростроению обречен на провал, и почему. Скажу сразу, результаты меня обнадежили! Под катом подробности и проблемы, с которыми я столкнулся в процессе разработки.
Краткая предысторияБудучи студентом 4-го курса кибернетики, я получил от преподавателя по программированию предложение поучаствовать в конкурсе, проводимом ШАГ-ом и еще несколькими компании в совместительстве. Конкурс «Золотой байт» проводится не первый год и я подумал, что это замечательная возможность опробовать себя на поприще игростроения. Имея опыт работы 1,5 года в веб-студии в качестве разработчика (php, js, html, ну все как обычно), я решил долго не колебаться и подал заявку в номинацию «Game design». Благо у нас с другом (художник-любитель), были наработки (в мыслях) о концепции браузерной игры.Поехали! Суть игры вкратце.Браузерный тайм киллер. Две команды пластиковых солдатиков бегают по компьютерному столу и уничтожают друг друга, борясь за владение столом. Команда побеждает набрав определенное количество убийств. Управление: WASD+мышь.
Дизайн-документ был составлен за пару дней, отправлен и одобрен жюри конкурса. К этому моменту я уже определил платформу, на которой будет основываться серверная часть, клиент, в общем, основную архитектуру. Решение было принято в пользу Node.js (сервер), js + html5 (клиент). Данные о карте, предметах, доступных юнитах хранятся в xml формате и лежат на сервере.
Наброски юнитов рисовались пока я пилил код.
Особенности и предысторию к игре тут выкладывать, думаю, не уместно.
Логика Итак, перед мной встало несколько проблем реализации, и поскольку с нодой я до сих пор дел не имел, пришлось подстраиваться под обстановку.В качестве способа связи клиент-сервер я выбрал Web sockets, подключил socket.io, пару шаманств и танцев и вуаля, коннект есть. Первые наброски а-ля передвижение и синхронизация проводились с отрисоваными коряво в пеинте картинками (для наглядности).
Данные летают в json формате.
Процесс происходящего в бэкграунде был примерно таков.
Пользователь заходит на сайт, получает первичные данные о карте, всю необходимую служебную информацию, first packet. Пользователь видит главный экран. — Загрузка необходимых картинок (preload). Пользователя анонимно коннектит socket.io с сервером, регистрирует его в сесию. Пользователь выбирает за какую сторону он будет играть — отсылается запрос, ставится пометка о стороне. Пользователь выбирает за какого персонажа он будет играть — отсылается запрос, ставится пометка о персонаже. Игрока помещают на точку респауна, исходя из настроек карты. Начинается процесс обмена данными с сервером, ну и сама игра (ниже алгоритм). Алгоритм синхронизации действий был придуман следующий:
На сервере стоит интервал, 50 мс, который отсылает всем подключенным юзерам необходимую инфу, о местоположении и действиях игроков.(отсылается список объектов игроков). У пользователей стоит catch-event на сообщения и когда они его ловят, проверяют какой именно пакет пришел, main/first/system и т.д. В ответ от пользователя летит пакет с текущим действием юзера. Летят только нажатые клавиши, все вычисления происходят на сервере (можно ли туда пойти, где окажешься и т.д. и т.п.). И так по кругу.
Отрисовка В качестве поля для отрисовки я использовал canvas. После недолгого просмотра популярных библиотек, я подумал что я все же делаю это больше для себя, а не для конкурса. А ведь куда приятнее писать свой велосипед, особенно в новой для меня сфере, так что было принято решение писать свой небольшой движок отрисовки.Ну и как полагается, в ход пошли setInterval, requestAnimationFrame, и все знания, что остались по геометрии и элементарной алгебре.После отрисовки бэкграунда выбиралась та активная область экрана, которую видно пользователю, минус разница в площади отрисовываемого объекта. В данном периметре производится рендеринг активной зоны. На сервере все регулярно сортируется по мере дальности от экрана (по высоте), чтобы картинка солдата стоящего дальше не накладывалась на солдата, стоящего ближе к экрану.
К этому моменту у меня уже был готовый набор спрайтов для отрисовки юнита. Я добавил в движок метод отрисовки анимации спрайтов, как результат получил следующее:
Итак, на данный момент у меня было готово:
Отрисовка юнитов с анимацией Отрисовка предметов Неровные страницы стола (невозможность пройти за них) Передвижение по карте Спрайты юнитов были отрендерены в 3Dmax и склеены вместе. Выглядело это вот так (кликабельно):
Ну и, конечно же, боевка Боевая часть реализована достаточно просто. При клике левой кнопкой мыши по полю, персонаж разворачивается в ту сторону и бьет. Правая кнопка мыши — блок в сторону по направлению мышки. У персонажа есть определенные характеристики, которые обуславливают его скорость/живучесть/усталость/дальность_удара/дмг и т.д. И опять же, все вычисления происходят на сервере, игроку приходит только результат его нажатия на клавиши.
Немного служебной информации/статистики Сервер VPS за 5 евро в месяц: CPU 1200 Mhz, ОЗУ 256Мб, ОС Debian.Карта 3000 на 3000 (одномерный массив с последующим преобразованием). При старте сервера инициализируется, занимает 900 мс. Когда был двумерным массивом, занимал 6500 мс.
5Мб канал клиента. 40 подключений (20 на 20). Обеспечивался обмен данными и поддерживался постоянный фпс без проседаний 30–60.
Еще немного картинок: Главный экран:
Отскроллили колесиком мыши:
Победа синей команды:
Кроссбраузерность предусмотрена для Chrome, Mozilla, Opera, Explorer 10+. В общем все, что поддерживает canvas и Websockets.
Так же была адаптированная версия для тех, кто зашел с телефона (интерфейс не допилен, но работает).
Итог Вся работа заняла около полутора месяца трудов после учебы и работы.Ссылку на игру не дам, бедный сервер не выдержит хабраэффекта, да и не готов я еще к нагрузочному тестированию.На конкурсе в своем городе мы с другом заняли 2-е место, что в принципе не расстроило меня, а лишь подстегнуло. Игру делал скорее для себя, но в будущем, возможно переделаем графику, и можно будет выкладывать в общий доступ, но об этом говорить еще рано.Для тех, кто хочет посмотреть мой корявый код, вот репозиторий на git. Только не плюйтесь, уже сейчас вижу, на сколько все коряво, хотя делал всего пол года назад: https://github.com/amikstrike/wn
Спасибо за внимание!