Запустить физическую симуляцию на клиенте и сервере?

13

Я реализую многопользовательский клон астероидов, чтобы узнать об архитектуре клиент-серверной сети в играх. Я потратил время на чтение публикаций GafferOnGames и Valve о технологиях клиент / сервер. У меня проблемы с двумя понятиями.

  1. В настоящее время у меня есть авторитетный игровой сервер, симулирующий физику с box2d и рассылающий информацию о состоянии мира клиентам примерно 20 раз в секунду. Каждый клиент отслеживает последние несколько снимков, которые он получил, и переключается между двумя состояниями, чтобы сгладить движение спрайтов. Однако это не так гладко. Это может быть некоторое время сглаживанием, затем немного подергиванием, затем возвращением к сглаживанию и т. Д. Я пробовал оба протокола TCP и UDP, оба они примерно одинаковы. Есть идеи, в чем может быть моя проблема? (Примечание: я реализовал это сначала для одиночной игры, и движение спрайтов было совершенно плавным при 60 кадрах в секунду при обновлении мира физики только 20 раз в секунду).

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

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

Благодарность!

Venesectrix
источник

Ответы:

10

Обязательно запустите симуляцию как на клиенте, так и на сервере. Все остальное имеет слишком большую задержку. Вы должны быть уверены, что симуляции совпадают, вставляя объекты в том же порядке, используя фиксированный временной шаг и избегая сравнения указателей. Я не пробовал это с Box2D, но обычно можно добиться одинакового поведения на всех машинах в симуляции физики. Вся математика обычно основана на бинарных выражениях IEEE 754, и их поведение строго определено для таких операций, как, например, +-*/несколько. Вы должны быть осторожны sin,cosи лайки жесткие, поскольку они могут различаться в зависимости от времени выполнения (это особенно важно при разработке для нескольких платформ). Также убедитесь, что вы используете строгую настройку для плавающих оптимизаций в вашем компиляторе. Вы по-прежнему можете синхронизировать объекты, периодически отправляя состояние объектов с сервера. Не обновляйте, если разница не превышает пороговое значение, чтобы избежать ненужного заикания.

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

Расмус
источник
Спасибо за ваш ответ. Я не думаю, что box2d гарантированно генерирует одинаковые результаты на разных процессорах, что будет для нас сценарием, так как мы пишем настольную игру. Я надеюсь, что различия будут незначительными и легко исправляемыми с помощью периодических обновлений с авторитетного сервера, но я никогда не пробовал.
Venesectrix
Эрин Катто считает, что попытка синхронизировать все состояния двух миров Box2D - это проигрышная битва ( box2d.org/forum/viewtopic.php?f=3&t=8462 )
Павел
Утверждение «IEEE 754 binary32 float [..] поведение строго определено для таких операций, как +-*/» полностью ложно. Все эти операции в IEEE-754 могут различаться в зависимости от реализации. Смотрите здесь и здесь для получения дополнительной информации.
BlueRaja - Дэнни Пфлюгофт
1
Нет, это полностью верно. Проблема, описанная в вашей ссылке, связана с различными режимами процессора x87 и реализациями трансцендентных. IEEE 754 binary32 является строго определенным для основных операций. Это зависит от вас, чтобы установить правильные режимы и использовать правильные инструкции, чтобы следовать стандарту. Очень помогает простое использование инструкций SSE, а не x87 fpu.
Расм
4

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

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

Мэтт Кемп
источник
Это может быть так. Я пытаюсь сделать задержку, пока не получу 3 снимка с сервера. В момент, когда я переворачиваю с броска 1 на выстрел 2. Затем с броска 2 на выстрел 3. Если в какой-то момент я пропускаю пакет, я могу перепрыгнуть от 1 до 3 вместо 1 до 2, если это имеет смысл. Я, возможно, еще не правильно это реализую. Спасибо за ссылку на статью!
Venesectrix
1

Я сделал что-то подобное сам и запускал Box2D только на клиентах. То, как я это сделал, состояло в том, чтобы позволить клиенту самостоятельно запускать собственное моделирование, отправляя текущую скорость (и вращение) каждого синхронизирующего пакета на сервер. Затем сервер отправляет эту информацию другим игрокам, которые устанавливают вновь полученные скорости для реплицируемых объектов. Это было очень гладко, без каких-либо заметных различий между клиентами.

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

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

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

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

Что касается вопроса 1, я говорю, что проблема заключается в колебаниях латентности, потому что нет абсолютной гарантии, что между каждым получением снимка будет абсолютно точный 20-секундный интервал. Позвольте мне проиллюстрировать (будучи "т" время, измеренное в миллисекундах):

1) В момент времени t = 20 с начала игры клиент получил снимок и успешно и беспроблемно выполнил интерполяцию.

2) В момент времени t = 40 между сервером и клиентом возникла задержка, и моментальный снимок фактически пришел только к моменту времени t = 41.

3) При t = 60 сервер отправил еще один снимок, но одна секунда моделирования была потрачена впустую на стороне клиента из-за задержки. Если моментальный снимок достигается при t = 60, клиент не будет выполнять интерполяцию 40 и 60 моментов, а фактически из моментов 41–60, генерируя другое поведение. Эта неточность может быть причиной возможной «вялости».

Что касается вопроса 2, ваша идея может сработать, если вы реализуете что-то, что будет эффективно отслеживать, действительно ли каждый объект синхронизирован клиент-сервер, без необходимости посылать пакеты каждый кадр, информирующий о положении объектов. Даже если вы делаете это с дискретными интервалами, вы не только столкнетесь с той же проблемой, что и в вопросе 1, но и получите слишком большое количество данных для передачи (что плохо).

UBSophung
источник
Я не уверен, что следую тому, что вы говорите в первом абзаце. Если симуляция выполняется только на сервере, а вы транслируете только изменения скорости / ускорения, то как клиент узнает, где должны быть нарисованы спрайты? Клиенты должны будут симулировать объекты на основе полученной скорости / ускорения, чтобы правильно их нарисовать. Думаю, вы правы в получении снимков с интервалами, отличными от того, что я ожидаю. Есть идеи, как с этим бороться?
Venesectrix
Клиенты знают начальные и текущие позиции, скорости и ускорения объектов и обновят позицию, в которой, по их мнению, находятся объекты (независимо от сервера) соответственно. Сервер в конечном итоге изменит такие свойства на клиентах с помощью сообщений, потому что это сервер, который выполняет физику и обнаружение столкновений (которые обязаны рано или поздно изменить скорость / ускорение и направление данного объекта)
UBSophung