Чтобы сэкономить пропускную способность в моей многопользовательской игре , я не обновляю каждый объект каждый тик сервера, вместо этого у каждого объекта есть updateRate, который сообщает игре, что этот объект будет обновляться после каждого тика X-сервера.
Когда я получаю сообщение об обновлении для объекта, я рассчитываю время, которое я ожидаю следующего обновления:
origin = serverCurrentPosition
diff = serverNextPosition - origin
arriveTime = now + timeBetweenTicks * updateRate
Когда я рисую объект, я вычисляю время, оставшееся до следующего обновления, и интерполирую позицию соответственно:
step = 100 / timeBetweenTicks * updateRate
delta = 1 - step * ((arriveTime - now) / 100)
position = origin + diff * delta
Это работает ... но на рисунке все еще есть немного дрожания, хотя в моей теории все должно работать хорошо, так как масштабирование должно заботиться о некоторой задержке, не так ли?
Таким образом, вопрос здесь заключается в том, это лучший подход? Должен ли я поставить фактическое отставание в вычислениях? Если так, как бы я это сделал? Я провел несколько экспериментов, но дрожание только ухудшалось.
источник
Ответы:
У вас есть дрожание, потому что ваше отставание постоянно меняется. Это означает, что, хотя сервер отправляет обновления ровно через каждые
timeBetweenTicks
тики, клиент получает их через некоторое переменное время. Это время, вероятно, близко кtimeBetweenTicks
хорошему соединению, но не совсем одинаковое (и, кроме того, у вас могут быть задержки сервера и разные тактовые частоты на сервере и клиенте).Таким образом, когда вы полагаетесь на получение обновления точно в указанное время, вы постоянно прибываете в пункт назначения до / после фактического обновления. Следовательно, дрожание.
Простой подход к уменьшению джиттера заключается в использовании «резиновых полос», что Мартин предлагает в другом ответе. По сути, когда вы получаете обновление, вы не сразу меняете положение объекта. Вместо этого, если позиция клиента и позиция сервера отличаются незначительно, вы начинаете интерполировать позицию клиента, чтобы через некоторое время (скажем, на полпути к следующему обновлению) позиции клиента и сервера сходились.
Еще одна идея уменьшить джиттер в вашей настройке: поскольку вы передаете как «текущие», так и «следующие» координаты, вы можете рассчитать скорость объекта. Затем, когда обновление запаздывает, вы не останавливаете объект в месте его назначения (то есть в «следующей» позиции), а продолжаете перемещать его с той же скоростью. Если ваши объекты не изменяют свои скорости резко, это действительно улучшит плавность движения на клиенте.
источник
Я решил эту проблему прежде с некоторым успехом с подходом, который я называю "тенями сети". Я не знаю, делают ли это другие люди, но это всегда работает для меня.
Каждый объект, который синхронизируется по сети, имеет невидимый сетевой теневой объект. Когда обновление приходит из сети, вы телепортируете тень непосредственно в положение, в котором, по словам сети, оно должно быть, а затем медленно интерполируете локальную видимую сущность в направлении тени с течением времени.
Я включил много деталей об этом подходе в свой предыдущий ответ здесь
источник
Я написал статью, в которой подробно описан несколько иной подход, который дает очень плавные результаты: http://www.gabrielgambetta.com/fpm3.html
источник