Прогноз движения для не стрелков

35

Я работаю над изометрической 2D-игрой с умеренным мультиплеером, где примерно 20-30 игроков одновременно подключены к постоянному серверу. У меня были некоторые трудности с получением хорошей реализации предсказания движения.

Физика / движение

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

В основном игровом цикле «Обновление» вызывается перед «Розыгрышем». Логика обновления запускает «задачу обновления физики», которая отслеживает все объекты с ненулевой скоростью, использует базовую интеграцию для изменения положения объектов. Например: entity.Position + = entity.Velocity.Scale (ElapsedTime.Seconds) (где «Seconds» - это значение с плавающей запятой, но тот же подход будет работать для целочисленных значений в миллисекундах).

Ключевым моментом является то, что для движения не используется интерполяция - элементарный физический движок не имеет понятия «предыдущее состояние» или «текущее состояние», только положение и скорость.

Пакеты изменения состояния и обновления

Когда скорость сущности персонажа, которой управляет игрок, изменяется, на сервер отправляется пакет «перемещение аватара», содержащий тип действия сущности (стойка, ходьба, бег), направление (северо-восток) и текущую позицию. Это отличается от того, как работают 3D игры от первого лица. В 3D-игре скорость (направление) может меняться от кадра к кадру при движении игрока. Отправка каждого изменения состояния будет эффективно передавать пакет на кадр, что будет слишком дорого. Вместо этого 3D-игры, похоже, игнорируют изменения состояния и отправляют пакеты «обновления состояния» через фиксированный интервал - скажем, каждые 80–150 мс.

Так как обновления скорости и направления происходят в моей игре гораздо реже, я могу отправлять каждое изменение состояния. Хотя все физические симуляции происходят с одинаковой скоростью и являются детерминированными, задержка все еще остается проблемой. По этой причине я посылаю обычные пакеты обновления положения (аналогично 3D-игре), но гораздо реже - сейчас каждые 250 мс, но я подозреваю, что с хорошим прогнозом я могу легко увеличить его до 500 мс. Самая большая проблема состоит в том, что я теперь отклонился от нормы - вся другая документация, руководства и образцы онлайн отправляют рутинные обновления и интерполируют между двумя состояниями. Это кажется несовместимым с моей архитектурой, и мне нужно придумать лучший алгоритм предсказания движения, который ближе к (очень простой) архитектуре «сетевой физики».

Затем сервер получает пакет и определяет скорость игрока по типу движения на основе сценария (способен ли игрок бежать? Получить скорость бега игрока). Получив скорость, он комбинирует ее с направлением, чтобы получить вектор - скорость объекта. Происходит некоторое обнаружение читов и базовая проверка, а сущность на стороне сервера обновляется с учетом текущей скорости, направления и положения. Базовое регулирование также выполняется, чтобы не дать игрокам заполнить сервер запросами на перемещение.

После обновления своего собственного объекта сервер передает пакет «обновление позиции аватара» всем остальным игрокам в пределах диапазона. Пакет обновления положения используется, чтобы обновить физические симуляции на стороне клиента (мировое состояние) удаленных клиентов и выполнить прогнозирование и компенсацию запаздывания.

Предсказание и компенсация отставания

Как уже упоминалось выше, клиенты являются авторитетными для своей должности. За исключением случаев мошенничества или аномалий, аватар клиента никогда не будет перемещен сервером. Для аватара клиента не требуется экстраполяция («двигаться сейчас и исправить позже») - игрок видит следующее : правильно. Однако какая-то экстраполяция или интерполяция требуется для всех удаленных объектов, которые движутся. Некоторый вид предсказания и / или компенсации запаздывания явно требуется в локальном механическом / физическом движке клиента.

Проблемы

Я боролся с различными алгоритмами, и у меня есть ряд вопросов и проблем:

  1. Должен ли я быть экстраполирующим, интерполирующим или и тем, и другим? Мое "внутреннее чувство" состоит в том, что я должен использовать чистую экстраполяцию, основанную на скорости. Клиент получает изменение состояния, клиент вычисляет «предсказанную» скорость, которая компенсирует задержку, а обычная физическая система делает все остальное. Тем не менее, он чувствует разногласия со всем другим примером кода и статей - кажется, что все они хранят несколько состояний и выполняют интерполяцию без физического движка.

  2. Когда пакет приходит, я попытался интерполировать положение пакета со скоростью пакета в течение фиксированного периода времени (скажем, 200 мс). Затем я беру разницу между интерполированной позицией и текущей позицией «ошибки», чтобы вычислить новый вектор и поместить его на объект вместо скорости, которая была отправлена. Тем не менее, предполагается, что другой пакет прибудет в этот интервал времени, и невероятно трудно «угадать», когда следующий пакет прибудет - тем более, что они не все приходят через фиксированные интервалы (то есть / также изменяется состояние). Является ли концепция в корне ошибочной или она правильная, но нуждается в некоторых исправлениях / корректировках?

  3. Что происходит, когда удаленный плеер останавливается? Я могу немедленно остановить сущность, но она будет расположена в «неправильном» месте, пока она не начнет двигаться снова. Если я оцениваю вектор или пытаюсь интерполировать, у меня возникает проблема, потому что я не сохраняю предыдущее состояние - физический движок не может сказать «вам нужно остановиться после достижения позиции X». Он просто понимает скорость, ничего более сложного. Я неохотно добавляю информацию о «состоянии перемещения пакетов» к сущностям или физическому движку, поскольку это нарушает базовые принципы проектирования и отбирает сетевой код на остальной части игрового движка.

  4. Что должно произойти, когда объекты сталкиваются? Существует три сценария: контролирующий игрок сталкивается локально, два объекта сталкиваются на сервере во время обновления позиции или обновление удаленного объекта сталкивается на локальном клиенте. Во всех случаях я не уверен, как справиться со столкновением - кроме обмана, оба состояния являются «правильными», но в разные периоды времени. В случае удаленного объекта не имеет смысла рисовать его, проходя сквозь стену, поэтому я выполняю обнаружение столкновений на локальном клиенте и заставляю его «останавливаться». Основываясь на пункте № 2 выше, я мог бы вычислить «исправленный вектор», который постоянно пытается переместить сущность «через стену», которая никогда не будет успешной - удаленный аватар застревает там до тех пор, пока ошибка не станет слишком высокой и не «защелкнется» в позиция. Как игры работают вокруг этого?

ShadowChaser
источник
1
Какое отношение имеет игра 3D или 2D к какому серверу вы используете? и почему не работает сервер-аттестат для вашей игры?
AttackingHobo
1
@ Рой Т. Компромиссы пропускной способности. Пропускная способность является наиболее ценным ресурсом в современных компьютерных системах.
FxIII
1
Это просто неправда, в онлайн-играх преобладает время отклика, например, на линии 10 Мбит (1,25 МБ / с) задержка между сервером и клиентом составляет 20 мс, отправка пакета размером 1,25 КБ займет 20 мс + 1 мс. Отправка пакета размером 12,5 КБ займет 30 мс. На линии с удвоенной скоростью пакет 1,25 КБ будет по-прежнему занимать 20 мс + 0,5 мс и 20 мс + 5 мс для пакета 12 Кбайт. Задержка является ограничивающим фактором, не пропускной способностью. В любом случае, я не знаю, сколько там данных, но отправка 50 vector3 (25x позиция + 25x поворот) занимает всего 600 байтов, отправка каждые 20 мс будет стоить 30 Кб / с. (+ накладные расходы пакета).
Рой Т.
2
Движок Quake имеет прогноз с первой версии. Прогноз землетрясения описан там и в некоторых других местах. Проверьте это.
user712092
1
Делаете ли вы эту позицию + = скорость * deltatime для каждой сущности параллельно (обязательно: в коде у вас есть 2 массива физических параметров сущностей, один кадр в отдельности; вы обновляете более старую версию, чтобы она была более новой, и меняли их местами)? Есть некоторые проблемы с итерациями Шона Баррета, который создал базу движка Thief 1 .
user712092

Ответы:

3

Единственное, что нужно сказать, это то, что 2D, изометрия, 3D, они одинаковы, когда дело доходит до этой проблемы. То, что вы видите много примеров 3D, и вы используете только двумерную систему ввода с ограничением по октанту и мгновенной скоростью, не означает, что вы можете отказаться от сетевых принципов, которые развивались за последние 20 с лишним лет.

Будь прокляты принципы дизайна, когда игра подвергается риску!

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

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

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

Вы когда-нибудь описывали физический движок, такой как Havok или Bullet? Они действительно довольно оптимизированы и очень, очень быстрые. Возможно, вы попали в ловушку, предполагая, что работа ABC будет медленной и оптимизирует то, что не нужно.

Патрик Хьюз
источник
Определенный мудрец-совет здесь! Легко потерять из виду большую картину. Я использую TCP в этом случае. Проблема «8 направлений» - не столько проблема с точки зрения входных данных, сколько проблема с интерполяцией и экстраполяцией. Графика ограничена этими углами и использует анимированные спрайты - игровой процесс «выглядит странно», если игрок движется под другим углом или со скоростью, которая слишком далека от нормы.
ShadowChaser
1

Таким образом, ваш сервер по сути является "рефери"? В этом случае я считаю, что все в вашем клиенте должно быть детерминированным; вам нужно убедиться, что все на каждом клиенте всегда будут давать одинаковый результат.

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

Когда вы получаете обновление «реальной позиции» каждого игрока (что, возможно, вы можете попробовать пошатнуться на сервере), да, вам нужно будет интерполировать позицию и направление игрока. Если «угаданная» позиция очень неправильная (то есть игрок полностью изменил направление сразу после того, как был послан последний пакет направления), у вас будет огромный разрыв. Это означает, что либо игрок прыгает с позиции, либо вы можете интерполировать до следующей предполагаемой позиции. Это обеспечит более плавную интерполяцию с течением времени.

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

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

Джонатан Коннелл
источник
Спасибо - это звучит довольно близко к тому, что мне нужно, особенно на стороне сервера. Интересным моментом является то, что, хотя игроки заблокированы в 8 направлениях, внутреннее движение является трехмерным вектором. Я думал об этом немного больше в прошедший день, и мне кажется, что я борюсь с тем, что у меня вообще не реализована интерполяция - я просто использую очень простую интеграцию, устанавливая скорость и обновляя позицию на основе вектор каждого обновления.
ShadowChaser
Я не уверен, как совместить это с интерполяцией или предсказанием. Я попытался взять обновленную позицию, отправленную в пакете, интегрировать ее за фиксированный период времени (скажем, 200 мс), а затем определить вектор (скорость), необходимый для достижения этой точки за 200 мс. Другими словами, независимо от текущей неправильной позиции игрока на стороне клиента, они все равно должны достичь той же «оценочной правильной позиции» за 200 мс. В итоге мой персонаж отправился в сумасшедших направлениях - я полагаю, потому что 200 мс действительно должны быть временем для следующего пакета, что я не могу оценить.
ShadowChaser
Удалось ли вам сначала интегрировать правильную позицию от t до t + 1, прежде чем интегрировать неправильную позицию с предполагаемой правильной позицией в t + 1?
Джонатан Коннелл
Да - я дважды проверил, что я использовал правильную позицию для первоначальной интеграции. Первоначально это была ошибка, но ее исправление, казалось, не принесло заметного улучшения. Мое подозрение - «+1» - оно должно сильно зависеть от времени между пакетами. Есть две проблемы: отправлять изменения состояния в дополнение к регулярным (250 мс) обновлениям, и я не могу предсказать, когда они произойдут. Кроме того, я не хочу блокироваться через определенный интервал, поскольку имеет смысл для сервера отправлять меньше обновлений для объектов, которые находятся дальше от игрока. Время между пакетами может измениться.
ShadowChaser
1
Да, включение фиксированного временного шага, вероятно, не очень хорошая идея. Я обеспокоен тем, что ошибочность движения в 8 направлениях будет очень трудно (если не невозможно?) Предсказать. Тем не менее, вы можете попытаться использовать среднее время ожидания клиента для прогнозирования t + 1 и иметь порог, выше которого вы всегда «телепортируете» других игроков на их новые позиции.
Джонатан Коннелл
0

Разве вы не можете включить скорость в свои сообщения об изменении состояния и использовать ее для прогнозирования движения? Например, предположим, что скорость не меняется, пока вы не получите сообщение о том, что она изменилась? Я думаю, что вы уже отправляете позиции, поэтому, если что-то «переходит» из-за этого, у вас все равно будет правильная позиция из следующего обновления. Затем вы можете шагать по позициям во время обновлений, как вы уже делаете, используя скорость из последнего сообщения и перезаписывая позицию при получении сообщения новой позицией. Это также означает, что если позиция не меняется, но скорость нужна вам, чтобы отправить сообщение (если это даже допустимый случай в вашей игре), но это не сильно повлияет на использование вами пропускной способности, если вообще.

Здесь интерполяция не должна иметь значения, например, когда вы знаете, где что-то будет в будущем, есть ли у вас это, какой метод вы используете и т. Д. Возможно, вас путают с экстраполяцией? (для которого я описываю один простой подход)

jheriko
источник
-1

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

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

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

Что должно произойти, когда игрок останавливается? Я не могу интерполировать в правильную позицию, поскольку им, возможно, придется идти назад или в другом странном направлении, если их позиция слишком далеко впереди.

Зачем вам нужно интерполировать? Авторитетный сервер должен отменять любые ошибочные движения.

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

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

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

Гьян ака Гари Буйн
источник
Несколько ответов: * Если у сервера есть полномочия, он будет отвечать за отслеживание всех движущихся объектов и регулярное обновление их позиций. Другими словами, для этого нужно запустить физический движок, который может дорого обойтись. Масштабируемость - главная цель моего дизайна. * Мне нужно интерполировать на стороне клиента, в противном случае каждое обновление сервера, отправленное клиентам, будет вызывать скачки сущностей. Прямо сейчас моя интерполяция выполняется в физическом движке - он просто устанавливает скорость. Там нет государств или дельты.
ShadowChaser
Я прочитал все статьи Гленна, но в комментариях он заявляет, что они предназначены только для стрелков (т.е. / высокие частоты обновления). В нескольких его статьях рассказывается об авторитетных клиентах, к которым я стремлюсь. Я не хочу делать какую-либо интерполяцию / физику на сервере, но я хочу передумать, если это действительно единственный путь :)
ShadowChaser
1
-1. То, что вы написали, лишь смутно затрагивает тему; чувствует себя неоднозначным. Ответы кажутся не соответствующими требованиям, когда они, по сути, «читают эту длинную статью», но не содержат полезной информации из данной статьи.
AttackingHobo
1
@ AttackingHobo Я бы с тобой согласился. Я упоминал, что спешил, но это не оправдание. Если бы у меня не было времени, было бы лучше оставить это в покое. Урок выучен.
Гьян ака Гари Буйн