Player.IO. Решение проблемы задержек

Наконец-то спустя столь продолжительное время мы наконец добрались до более детального рассмотрения проблем с задержками и способов их решения. А так же ответим на вопрос попал ли первый игрок во второго игрока?

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

Чтобы мы не делали, мы не сможем полностью избавиться от этих промежутков времени — задержек. Таким образом наша основная задача сделать так, чтобы игроки не замечали этих задержек и соотвественно проблем, которые эти задержки могут порождать.

Давайте вернемся к нашей большой проблеме, что возникла у нас несколько глав назад: попал ли второй игрок в первого игрока?

Наш подход никак не может решить эту проблему, но не стоит отчаиваться. Если мы начнем искать решение для нашей проблемы, то решение начнет формироваться. Что нам нужно? Нам нужно сделать так, чтобы оба игрока были довольны. Мы хотим, чтобы наша игра была справедливой по отношению к обоим игрокам и мы хотим вознаградить того игрока, который играет хорошо. Таким образом решение становится очевидным, необходимо сделать так, чтобы второй игрок попал в первого игрока. Ведь он играл хорошо и попал в цель — это то, что он увидел у себя на экране. Но что же при этом будет с первым игроком!? Спросите вы.

Мы обманываем

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

То есть, если вы еще не догадались, то мы делаем то, что должно казаться справедливым, причем независимо от того, что игрок мог видеть на самом деле. Разве вам не кажется справедливым, если первый игрок увидит, что второй игрок стрелял в него и попал?

Все, что мы сделали здесь — это изменили вид для первого игрока, чтобы он увидел, что второй игрок стрелял в него. Мы уже решили, что второй игрок попал до того как мы послали сообщение первому игроку. Почему тогда первый игрок должен видить то, чего не происходило?

Опять же, самое важное, что мы можем сделать в реальном времени — это создать иллюзию того, что все работает гладко и нет никаких проблем. Если мы создадим хорошую и плавную работу игрового процесса, то мы становимся настоящими виртуозами своего дела. В конце концов, кто создает игру и придумывает её законы и правила!? ;)

Конечно, это не единственное решение для проблемы задержек. Есть и другие решения, которые являются более земными, но имеют при этом больше недостатков. Кроме того мы еще не закончили с текущим решением. Есть еще некоторые вопросы, которые нам необходимо решить. Например, углы стен могут создать нам много проблем.

Представим, что второй игрок стреляет в первого игрока пока он еще не успел спрятаться за стеной. Это выглядит хорошо с точки зрения второго игрока. Он получает точное попадание и все выглядит хорошо, верно?

Но давайте посмотрим на это с точки зрения первого игрока. Первый игрок видит, что он уже убежал от второго игрока в тот самый момет, когда получает пулю от второго игрока.

В этой ситуации мы не можем даже подделать попадание второго игрока в первого. Казалось бы, что мы не можем найти выход из этой ситуации даже при помощи обмана. Но, к счастью, игроки замечают эти ошибки реже, чем мы думаем. Почти каждый полноценный FPS страдает от этих ошибок. Мы можем представить себе, что игрок будет недоволен тем, что был убит когда находился за углом в безопасности, но на самом деле он скорее будет думать о том, что он был убит прежде, чем успел добраться в безопасное место и тело его персонажа по энерции улетело за угол.

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

Если игрок имеет хороший пинг (менее 100мс), то любое несоотвествие будет занимать 1/10 секунды, и если игроки доверяют вашей игре потому что она работает плавно и не подает признаков задержек и связанных с ними проблем, то у игроков не возникнет подозрений и они будут верить тому, что показывает им игра. Помните, все зависит от нашего мастерства обмана.

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

Мы должны определить, действительно ли стреляющий игрок попал в кого-то. Это немного сложнее, чем кажется. Помните статью о безопасности? Мы не можем доверять сообщениям с клиентов, которые определяют ключевые моменты в игре, следственно мы не можем отправлять с клиента информацию на сервер о том, мог попасть игрок в цель или нет согласно тому, что у него на экране. Ведь так игроки смогут обманывать нас и слать каждый раз сообщения о том, что они попали!

Но как сервер, мы знаем точно, что любой одиночный игрок видит на своем экране в любой момент с учетом существующей задержкой между сервером и клиентом.

Бинго! Отслеживая пинг мы знаем какая разница между тем, что на сервере и тем, что у игрока. Используя эту информацию мы можем восстановить то, что игрок должен видить в этот момент.

Конечно, значение пинга или плохая синхронизация может сломать эту технику, но в целом это работает хорошо. Данная техника используется в большинстве крупных играх и применима к большинству игровых механик.

Решение задачи

Конечно, наше решение выглядит весьма призрачным и непонятно насколько хорошо оно будет работать. Но, к счастью, мы можем достичь хороших результатов, правда, заплатив при этом дорогую цену.

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

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

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

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

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

Конечно, грустен и уныл тот факт, что имея такую надежную систему мы вроде как не можем её использовать. Хотя подождите, давайте попробуем посмотреть на нашу игру под другим углом. Возможно можно отказаться от использования ловкости рук и обмана игроков, чтобы скрыть ошибки. Но как!? Давайте рассмотрим способы решения проблем с точки рассмотрения игрового дизайна!

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

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

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

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

И так, мы хотим задержать отправку сообщения на 500мс. То есть нам нужно сделать так, чтобы сообщение пришло через 500мс после того, как оно было отправлено. Но на основе того, что мы подчерпнули из прошлых глав, мы помним, что нам не стоит отправлять много отдельных маленьких сообщений из-за создания лишней нагрузки на сеть, поэтому нам следует объединять всю информацию для ближайшего обновления состояния.

Однако мы не можем создать задержку на действия. Хотя есть и такие игроки, которые любят «дерганные» игры, так как они могут перемещаться моментально и убивать врага еще до того, как он сможет среагировать на их действие. Но, к сожалению, для нас дерганье может создать большие проблемы. Если кто-то движется быстро или сам по себе игровой процесс протекает быстро, то отставание сети будет более заметным. Если игрок движется за 300мс на расстояние в длину своего тела и возникнет лаг в 300мс, то игрок просто телепортируется с одного места на другое.

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

А если бы мы просто немного все замедлили, что может произойти? Наши пинги останутся такими же, но количество расстояния, которое успевает пройти за это время герой, будет значительно сокращено. Предположим, герой перемещается в три раза медленнее, чем раньше. За 300мс сообщение достигает пункта назначения и за это время герой успевает преодалеть всего 1/3 длины своего тела.

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

Раньше мы говорили о том, что следует повысить «уровень правды», теперь мы вновь поговорим еще немного об обмане. Например, если у вас есть два стреляющих друг в друга игрока, то мы в состоянии сказать попадают они в друг друга или нет, для этого нам нужно нарисовать лишь прямую линию, чтобы понять, могут они попасть или нет. Но, в связи с задержкой, которая может возникнуть, игроки могут увидеть тот факт, что они промахнулись, если мы будем показывать полет пуль. Таким образом, нам следует сделать только вспышки выстрелов, не показывая при этом самих пуль, что позволит избежать противоречий. Ведь показывая только эффекты выстрелов, мы заставляем игроков быть не уверенными в том, что они видят, и они более склонны верить тому, что говорит сервер вместо того, что мы могли бы показать.

Работа с задержкой имеет большую ответсвенность для программиста. Но все же, поговорите с теми, кто делает графику для вашей игры, чтобы быть уверенными в том, что они могут помочь замаскировать некоторые недостатки при помощи эффектов.

Почти все наши проблемы, которые связанны с задержками, возникают при взаимодействии игроков друг с другом, в отличии от нашего окружения, которое легко обрабатывать и сделать предсказуемым для игры. Мы не можем иметь каких-либо проблем с окружением! Всегда помните, что проблемы возникают тогда, когда мы взаимодействуем с другими игроками, так как не можем знать их точное положение в данный момент.

В многопользовательских играх взаимодействия между игроками очень важны — это именно то, что создает интерес и удерживает наших игроков в игре. Но необходимы ли непосредствено все эти действия? Например, насколько важно сталкиваться игрокам друг с другом? Часто такие виды столкновений будут уродливыми из-за лагов и это будет только раздражать игрока. А так же это может сделать игру не играбельной в момент, когда игроки будут пытаться пройти рядом друг с другом и врезаться или цепляться, хотя при этом игроки могут визуально не видеть причин для столкновения с другим игроком. А все из-за того, что другой игрок может предоставить не очень точную информацию о своем положении. Но еще хуже это может выглядеть в гоночной игре, где игроки перемещаются быстро. Уродливые столкновения из-за задержек в этом случае могут быть просто катастрофическими для игрового процесса и отталкивать игроков от игры. Так почему же игроки должны сталкиваться со всеми? Ведь далеко не все игроки будут думать дважды перед тем, как начнут движение через другого игрока, и такие игроки вероятно будут благодарны вам за то, что просто могут пройти через другого игрока, не задев его.

Есть еще несколько других примеров взаимодействия, которые могут оказаться не такими важными, как нам изначально может показаться, но при этом могут создавать нам и нашим игрокам много проблем. Например, нам нужно чтобы игрока отбрасывало взрывной волной от взрыва? Если игрок увидит взрыв, который произойдет позади, но при этом получит толчок в противоположную сторону как будто взрыв был перед ним, то вероятно он будет в недоумении. Причиной такой ситуации опять же может послужить не достаточно точное позиционирование.

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

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

В общем, подходите к возникающим проблемам с изобретательностью и вы станете виртуозом свого дела, которому будет подвластно сделать гладкую и убедительную игру в режиме реального времени!

 

Это вольный перевод статьи: «Building Flash Multiplayer Games — Latency»

Содержание

  1. Как создать онлайн игру? Анонс
  2. Player.IO. Введение
  3. Player.IO. Основы или первая онлайн игра
  4. Player.IO. Пошаговые игры
  5. Player.IO. Сетевые архитектуры
  6. Player.IO. Безопасность в онлайн играх
  7. Player.IO. Пример пошаговой игры
  8. Player.IO. Онлайн игры в реальном времени
  9. Player.IO. Синхронизация игроков
  10. Player.IO. Интерполяция или удивительный мир обмана
  11. Player.IO. Решение проблемы задержек
  12. Player.IO. Советы и рекомендации

 


Индикаторы: Уроки
Постоянная ссылка

 

 

Супер, спасибо!
Давно ждал статью по player.io
С нетерпением жду заключительной статьи :)

Дмитрий
27 Февраля 2013
— 13:29
#

Спасибо, очень полезные и поучительные уроки.
А когда будет продолжение уроков по Tower Defens?

Роман
27 Февраля 2013
— 23:46
#

@Роман, roadmap по туториалам на ближайшее время такой:
* Окончание переводов по Player.IO — последняя большая статья на следующей недели.
* Завершение маленькой серии по ИИ — еще две статьи в первой половине марта.
* Продолжение уроков по TD — предположительно со второй половины марта.

Все это конечно при условии если я все буду успевать :)

Еще в начале марта будет представлено много информации по Anthill которую я готовлю в течении февраля. Надеюсь, что не зря готовлю...

Ant.Karlov
28 Февраля 2013
— 01:06
#

Спасибо за статью!
Информацию по Anthill ты готовиш не зря. Я вот к примеру уже использую некоторые отдельно-взятые модули из библиотеки и слежу за обновлениями на Wiki страничке проекта. Так что с удовольствием почитаю про данный фреймворк.

Naitonium
28 Февраля 2013
— 03:48
#

Не зря, очень не зря. Спасибо тебе большое за твой труд.

Александр
28 Февраля 2013
— 05:53
#

Тоже слежу за wiki. Большое спасибо за Anthill!

Дмитрий
28 Февраля 2013
— 10:31
#

математики мало

Джуль
1 Марта 2013
— 23:47
#

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

Ant.Karlov
2 Марта 2013
— 09:55
#

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

BolT
4 Марта 2013
— 07:21
#

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

Anonymous
5 Марта 2013
— 15:47
#

Еще неплохая статья на тему синхронизации в стратегиях реального времени(что интресно, с использованием р2р-топологии): http://habrahabr.ru/post/123883/

С4
9 Марта 2013
— 22:06
#

Всё же нужно скорей закончить уроки по TD.
Уже 3-й год им! Сколько можно? Возмутительно! Я буду жаловаться!
В вышестоящие инстанции!

Шутка. :)

Fear Factory
10 Марта 2013
— 16:02
#

Отличная статья, спасибо за перевод и прекрасное оформление!

Нашел перевод последней главы
советы и рекомендации

Александр
11 Марта 2013
— 11:11
#

@Anonymous, спасибо за отзыв! Подписаться на новые записи можно через RSS, кнопки для подписки в правом верхнем углу на главной странице сайта.

Ant.Karlov
11 Марта 2013
— 15:43
#

@С4, да статья интересная. Правда она больше разбирает сетевой режим для конкретного типа игр. Но для общего развития и понимания сетевых игр тоже очень полезная :)

Ant.Karlov
11 Марта 2013
— 15:45
#

@Fear Factory, у меня сейчас не самые лучшие времена и блог, к сожалению, не получается своевременно обновлять и тем более работать над новыми уроками. Но я рад, что мне хотя бы удается его не забрасывать совсем ;)

Ant.Karlov
11 Марта 2013
— 15:47
#

@Александр, интересно. По всей видимости кто-то не дождался заключительной статьи :)

Ant.Karlov
11 Марта 2013
— 15:48
#

@An ППц это что! совсем совести нет!

Уязвимость типа XSS (погуглил) в основном для кражи cookies, видать что не сработала.

Pavel
19 Марта 2013
— 12:50
#

А xitri уже кто-то сломал...

No name
27 Марта 2013
— 09:48
#

дибильная статья. для плавного геймплея уже давно все используют двусторонняя асимиляция потока

Аноним
31 Июля 2013
— 23:35
#

К предыдущему Анониму.
А можно ссылку на статью о "двусторонней асимиляции потока", а то в гугле не нашел, а интересно...

Alex
2 Сентября 2013
— 05:38
#