В настоящее время я работаю над довольно простым многопользовательским платформером. Я прочитал довольно много статей о методах, используемых для сокрытия задержки, но я все еще не могу разобраться в некоторых концепциях. Я нахожу эту тему очень интересной и люблю пробовать идеи самостоятельно, но я думаю, что вопрос gamedev stackexchange будет более эффективным для моего вопроса. Я постараюсь изо всех сил описать мою текущую ситуацию и вопрос, который возник по пути.
Сейчас я хочу синхронизировать только один плеер с сервером. Теоретически, я предположил, что игрок сам с предсказанием на стороне клиента не потребует серверных исправлений, поскольку нет никаких внешних факторов, которые влияют на его движение. Поэтому в моем прототипе в настоящее время только один игрок синхронизируется с сервером без отправки серверных исправлений.
Если вы знакомы с сетевыми играми, я думаю, что вы можете пропустить разделы контекста, хотя, возможно, я тоже что-то сделал по пути.
Цикл клиента (один раз на кадр, один раз каждые ~ 16,67 мс)
Упрощенный цикл клиента выглядит так:
Проверьте наличие локального ввода (WASD) и упакуйте их как действия (например
Type=MoveLeft, Time=132.0902, ID=15
). Мы сохраняем упакованные действия, чтобы в итоге отправить их позже. Также мы напрямую применяем желаемое действие к симуляции локальной физики игры. Например, если у нас естьMoveLeft
действие, мы применяем силу влево на скорости игрока.Проверьте, чтобы отправить действия. Чтобы предотвратить злоупотребление пропускной способностью клиента, отправляйте упакованные действия только через определенные интервалы (например, 30 мс).
Применить модификации сервера. В определенный момент это будет обрабатывать дельты и исправления, полученные сервером, и применять их к локальной симуляции игры. Для этого конкретного вопроса это не используется.
Обновите местную физику. Запустите цикл физики на главном игроке. По сути, это делает предсказание движения игрока на стороне клиента. Это добавляет гравитации к скорости игрока, применяет скорость игрока к его позиции, фиксирует столкновения на этом пути и т. Д. Я должен указать, что физическое моделирование всегда выполняется с фиксированными дельта-секундами (вызываемыми несколько раз в зависимости от реальных дельта-секунд) ,
Я пропускаю несколько конкретных деталей о физике и других разделах, потому что я чувствую, что они не нужны для вопроса, но не стесняйтесь сообщить мне, будут ли они иметь отношение к вопросу.
Цикл сервера (каждые 15 мс)
Упрощенный серверный цикл выглядит так:
Ручка действий. Проверьте полученные пакеты действий от клиентов и примените их к симуляции физики сервера. Например, мы могли бы получить 5
MoveLeft
действий, и мы применили бы силу к скорости 5 раз . Важно отметить, что весь пакет действий выполняется в одном «кадре» , в отличие от клиента, где он применяется, как только действие происходит.Обновите игровую логику. Мы обновляем физику игры, перемещаем игроков и исправляем столкновения и т. Д. Мы также упаковываем любые важные события, которые случайно отправлялись игрокам (например, здоровье игрока упало, игрок умер и т. Д.) Позже.
Отправить исправления. Мы регулярно (например, раз в 35 мс) отправляем дельты другим игрокам (например, позиции игроков, здоровье и т. Д.), Если они недавно изменились. Эта часть в настоящее время не реализована, так как я хочу, чтобы симуляция одного игрока давала одинаковые результаты на клиенте и сервере без исправлений, чтобы убедиться, что предсказание на стороне клиента работает хорошо.
Проблема
Текущая система отлично работает в простых обстоятельствах, и я был приятно удивлен, увидев, что она дала очень похожие результаты с простыми горизонтальными перемещениями (я думаю, что неточности связаны с ошибками точности с плавающей запятой):
Пожалуйста, игнорируйте прототип графики. Белый прямоугольник = игрок, красные прямоугольники = препятствия, синий = фон
Тем не менее, я получаю ошибки синхронизации после выполнения чувствительных ко времени движений, таких как прыжки и перемещение близко к изолированному препятствию:
Теоретически, я ожидал бы, что оба всегда будут иметь одинаковые результаты, поскольку у клиента нет внешних факторов, влияющих на его позицию. Однако на практике, я думаю, я понимаю проблему.
Поскольку прыжок вокруг препятствия, подобного этому, очень зависит от времени игрока, небольшие изменения в том, когда скорость применяется к позиции, будут иметь последствия для результата (например, клиент может отодвинуться как раз вовремя, чтобы избежать столкновения с препятствие, в то время как сервер будет делать это, поскольку он получит весь пакет действий позже и останется на препятствии в течение небольшого промежутка времени, изменяя конечный результат). Разница между тем, как клиент и сервер справляются с этим, заключается главным образом в том, что клиент выполняет все свои действия так, как они происходят, в то время как сервер выполняет их в массовом порядке при получении.
Вопрос
Этот длинный контекст, наконец, приводит к моему вопросу (спасибо, что прочитали это далеко): это нормально, требовать исправления сервера, даже когда только один игрок синхронизирован с сервером, или я должен использовать определенные методы, чтобы избежать рассинхронизации в ситуациях, чувствительных ко времени ?
Я думал о некоторых возможных решениях, некоторые из которых мне менее удобны:
Внедрить исправление сервера. Просто предположите, что это нормальное поведение и исправляйте ошибки по мере их возникновения. В любом случае я хотел реализовать это, но я просто хотел убедиться, что то, что я сделал до сих пор, приемлемо.
Используйте предоставленное клиентом время, чтобы применить желаемые действия. Я предполагаю, что это будет похоже на компенсацию задержки, требующую «вернуться назад во времени» и проверить движение. Вроде как применение серверных исправлений, вернуться назад во времени и повторно применить следующие действия после этого. Мне действительно не нравится идея. Он выглядит сложным, дорогим в ресурсах и требует доверия времени клиента (хотя я планирую действительно проверить, что время выглядит относительно законным).
Попросите GameDevelopment StackExchange за отличную новую идею, которая решит все мои проблемы.
Я только начинаю в мире игровых сетей, поэтому, пожалуйста, не стесняйтесь исправлять / критиковать / оскорблять любую из представленных выше концепций или давать идеи / ресурсы, которые могли бы помочь мне в моем путешествии в Чудесный мир сетевых технологий. Извините, если бы я мог найти свой ответ в другом месте, я потерпел неудачу в этом.
Большое спасибо за ваше драгоценное время.
источник
Ответы:
В таких случаях вам может быть лучше позволить клиенту быть немного авторитетным. Для таких точных элементов управления вы вряд ли получите хорошее поведение, даже с действительно продвинутой коррекцией и прогнозированием.
Клиенту необходимо перейти от простой отправки сообщений «Я прыгнул» к отправке сообщений «Я прыгнул с X, Y в момент времени T». Затем сервер проверяет, находится ли местоположение в непосредственной близости от того, что, по его мнению, было у игрока в момент времени T (который вы можете ограничить относительно небольшим временем в прошлом) для защиты от мошенничества, а затем моделирует переход с позиции клиента послал. Сервер исправляет клиента только тогда, когда он далеко не в порядке (обычно из-за задержки или тому подобного).
Этот вид техники используется в сочетании с коррекцией и интерполяцией, чтобы игра чувствовала отзывчивость на локальном клиенте и выглядела гладко для удаленных клиентов.
источник
~max(RTT)
серверных тиков в прошлом, но не знаю, нужна ли вам именно эта игра. Это может быть еще более удобно для игр в стиле шутера, где вы также хотите определить уровень удара / удара на клиенте, и вам нужно не только знать, где игрок находился 46 мс назад, но также и где его цель была 46 мс назад и где движущиеся окклюзионные платформы куда.