Как я могу остановить дрейф игрока из-за локального предсказания входа, когда он остановится?

14

Я работаю над многопользовательским игровым движком 2D-сервер-клиент (который вы можете попробовать здесь ). Он использует WebRTC DataChannels. (Соединения одноранговые, но хост-узел по-прежнему действует как сервер.)

Самая большая проблема (кроме возможности подключения) - это локальный входной прогноз. Мы делаем обычное: при нажатии клавиш игроки мгновенно двигаются, сообщают хосту, какие клавиши нажаты, получают данные обратно с хоста и сравнивают их с исторической позицией. Положение корректируется с течением времени, если есть разница. Это хорошо работает с низкой потерей пакетов или PDV , даже если пинг высокий.

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

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

Я не заметил этого в других играх. Как это можно смягчить?

AshleysBrain
источник
3
P2P-игра с сервером? Здесь что-то не так.
API-Beast
К сожалению, под «сервером» я подразумеваю «узел хоста».
AshleysBrain
2
Ну, это тоже не похоже на одноранговую модель, просто потому, что один из игроков изображает из себя, что сервер не делает его равноправным. Техника, которую вы используете, определенно является техникой клиент-сервер. В P2P вы либо полностью доверяете всем клиентам (например, каждый пэр спрашивает друг друга о том, где находится их игрок), либо вы не доверяете ни одному (например, вы задерживаете ввод до тех пор, пока все одноранговые узлы не получат его).
API-Beast
Ах ... на самом деле это хороший момент ... Я запутался: соединения одноранговые (что и делает WebRTC), но сам движок - сервер-клиент (один из пиров - просто сервер ). Хорошая точка зрения.
AshleysBrain
2
То , что это заставляет меня думать о нашем собственном Эндрю Рассел «s Стик Ninjas Dev журналы на YouTube , в частности , это один на исправление ошибок прогнозирования . Дрейф, который вы описываете, звучит очень похоже на то, что происходит в этом видео, и Эндрю рассказывает подробности. Связаны ли они, или, возможно, даже та же самая проблема?
Анко

Ответы:

8

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

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

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

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

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

Сервер должен проверить входные часы и убедиться, что они не слишком сильно отклоняются от ожиданий, чтобы предотвратить мошенничество. Входные часы не должны быть значительно больше, чем время обхода, которое вы должны рассчитывать. Зафиксируйте любой, который находится в разумных пределах ( [Now-2*RTT,Now]например).

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

Шон Миддледич
источник
1

Я использовал надежные UDP-сообщения для индикации изменений состояния кнопки и ненадежные UDP-сообщения для коррекции положения. В основном мне очень помогли следующие статьи: https://developer.valvesoftware.com/wiki/Source_Multiplayer_Networking

В нем говорится о прогнозировании движения путем сохранения состояний игрока в постоянных временных интервалах в соответствии с поступлением сообщений коррекции положения для примерно 20 или 30 сохранений состояний. Таким образом, похоже, что ваши удаленные игроки будут жить в не очень «прошлом», постоянно применяя технику предсказания :) На основе задержки в сетевом сообщении вы можете получить положение вашего объекта примерно во времени, когда сообщение было только что отправлено с хоста.

Текущее «экранное» положение может быть затем плавно переведено в прогнозируемое положение с использованием математики Lerp (линейная интерполяция). Идея состоит в том, чтобы интерполировать значения в промежутках времени между пакетами коррекций. Таким образом, похоже, что отображаемый объект всегда движется к некоторой предсказанной позиции. Для значения интерполяции я беру 1, деленную на «среднюю задержку сообщения», деленную на «среднее время рендеринга кадра», поэтому движение выглядит плавным.

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

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

Я описал всю схему, которую использовал в своем проекте, поэтому надеюсь, что вы найдете ответ на свой вопрос.

Александр Смирнов
источник