- PVSM.RU - https://www.pvsm.ru -
Несколько месяцев назад мы с коллегами решили сделать многопользовательскую realtime игру, которая могла бы работать в вебе. Мы решили использовать node.js для нашего сервера. Это решение привело к очень убедительному успеху — наш сервер работал несколько месяцев без единого падения или перезагрузки процесса.
Мы решили написать нашу игру на node.js, потому что мы слышали много хорошего об этой платформе и очень хотели немного с ней поиграть. И это было потрясающе — мы очень быстро вошли в тему. Для node.js существует множество любопытных библиотек, способных решать абсолютно разные задачи. Побочным преимуществом использования node для серверной части является, собственно, javascript — очень простой в обращении язык. Это позволило нам сфокусироваться на проблемах, которые встречаются во всех realtime играх, без лишней суеты, ограничений и необходимости компилировать код, как это случается при использовании менее динамических языков.
Также node.js проявил себя как очень легковесный язык, даже в моменты пиковой нагрузки. Для нашей игры, процесс node.js использовал только один поток и потреблял всего около 3-4% CPU при одновременной работе 8-10 копий игры, каждая со своим собственным движком обнаружения столкновений.
Изначальный (наивный) подход при написании многопользовательской realtime игры выглядит так:
var info = {};
info.position = {x:10, y:15};
info.velocity = {x:0.5,y: 0.2};
info.currentWeapon = 1;
info.radius = 10;
this.netChannel.send( info );
Сервер пересылает все полученные пакеты данных каждому подключенному клиенту:
function broadcastInfo( sendingClient, messageInfo )
{
for(var aClient in allClients) {
if(aClient != sendingClient) {
aClient.connection.send( messageInfo );
}
}
}
При данном подходе, вы не можете доверять информации о местонахождении пользователя, которую он вам передает. Пользователь всегда будет сообщать, что он находится там, где ему надо, попадает во всех противников со стопроцентной точностью и имеет полный запас здоровья.
Иногда этот эффект называют «прыгающий мячик» (bouncing ball). Он связан с необходимостью экстраполяции положения объекта пока не пришел следующий пакет, основываясь на скорости объекта, и дальнейшей «подстройкой» положения и т.д… Когда мячик находится на вершине параболы, по которой он движется, скорость равна нулю. Поэтому, предсказывая его движение, основываясь на скорости, мы получим абсолютно ту же точку, в которой он находится, и мячик зависнет в воздухе, пока неожиданно не обрушится резко вниз.
Наконец, еще одной серьезной проблемой является потеря пакетов. Если один из пакетов, изображенных на рисунке пунктирной линией, не дойдет до получателя, объект будет следовать по неверной траектории. И чем дальше — тем хуже. Конечно, время измеряется в миллисекундах, и это не конец света. Однако на деле это выглядит весьма неестественно, так как объекты реального мира не могут перемещаться мгновенно.
В процессе разработки игры, мы решили узнать, как эту проблему принято решать на практике. Ведь кто-то уже делал многопользовательские realtime игры. Мы нашли несколько интересных источников информации, в частности, свободный исходный код Quakeworld и некоторые технические описания от сотрудников Valve.
В этой модели имеется единый авторитетный сервер, который и моделирует игру. А также клиенты, посылающие лишь свои данные ввода. Например, я посылаю только информацию о том, что моя клавиша «пробел» была нажата, а сервер определяет, что это обозначает в терминах игры. Благодаря данной модели, мы освободились от множества проблем предыдущей реализации.
Наша нервная система может подстраиваться под задержку. Если мы используем одно и то же небольшое время задержки для отрисовки объекта, человек с легкостью подстраивается под это и перестает замечать задержку вообще. Ключевым моментом, разрешающим нашу проблему, является то, что мы рендерим мир для всех клиентов в прошедшем времени, таким, каким он был N миллисекунд назад. Число N выбирается произвольно. Например, мы использовали 75 миллисекунд.
Мы преданно верим в open-source, поэтому решили под конец разработки немного вычистить код и выложить как open-source проект. Так как мы не особо преуспели в выборе хороших имен, мы назвали его RealtimeMultiplayerNodeJS.
RealtimeMultiplayerNodeJS — это фреймворк, предназначенный специально для создания многопользовательских realtime игр с использованием HTML5 и клиент-серверной модели. В этой модели, пользователи посылают только данные ввода, а сама игра моделируется на сервере. Клиенты интерполируют мир между двумя его состояниями, основываясь на текущем времени рендеринга.
Это демо сделано с целью показать идею синхронизирующихся физических процессов, когда все моделирование происходит на сервере. Для создания мира используется Box2D.js. Также показана синхронизация взаимодействия нескольких пользователей, а также пример отправки сообщения на сервер с его последующей интерпретацией снова на стороне клиента.
Наиболее простое, но интересное демо, которое мы смогли придумать. Объекты движутся слева направо.
Демонстрация простого движка обработки столкновений CircleCollision, который предоставляет простейшую информацию о столкновениях и генерирует событие, когда два объекта сталкиваются. Это демо также показывает реализацию специального типа объекта, который контролируется подключенным пользователем с помощью клавиатуры.
(actual time)
(snapshot interval) |
| |
_ (rendered time) |
/ | /
v v / |
------|-----|----v|---|----|----|--v--------->
0.0sec 0.1sec 0.2sec 0.3sec time
| |
/
------/----/
|
|
(interpolation time)
Автор: simbajoe
Источник [2]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/node-js/39508
Ссылки в тексте:
[1] репозиторий: https://github.com/onedayitwillmake/RealtimeMultiplayerNodeJs
[2] Источник: http://habrahabr.ru/post/182678/
Нажмите здесь для печати.