Как синхронизировать часы по сети для разработки игр?


10

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

Итак, у меня два вопроса: 1) Как синхронизировать часы игр при старте, поскольку в сети есть задержка. 2) Можно ли НЕ синхронизировать их и просто предположить, что они одинаковы (мой код не зависит от часового пояса). Это не суперконкурентная игра, где люди меняют свои часы, чтобы обмануть, но все же.

Игра программируется на Java и Python (параллельная разработка как проект)



5
Я уверен, что этот вопрос уже рассмотрен на gamedev.stackexchange.com, или, по крайней мере, он там есть.
congusbongus

1
@CongXu: я не так уверен. Хотя эта задача обычно выполняется для игр, она не является специфической для разработки игр. Многие другие распределенные системы нуждаются в синхронизированных часах.
Ян Худек

2
Вы уже пытались использовать опцию TIMESTAMP для IPv4? Более подробная информация находится по адресу linux.die.net/man/7/socket оттуда до linux.die.net/man/3/cmsg, а затем небольшой пример программы на pdbuchan.com/rawsock/rawsock.html последней перед Раздел IPv6.
ott--

2
Игры (приложения) не должны касаться системных часов.
Восстановить Монику - М. Шредер

Ответы:


9

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

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

Основная идея может заключаться в том, что для каждого пакета, который вы отправили, вы отправили метку времени, порядковый номер и метку времени, когда вы получили последний пакет с другой стороны. Исходя из этого, вы вычисляете туда и обратно: например, если пакет Q говорит, что он был отправлен в 1000, а пакет P был получен в 500, чем, если вы отправили пакет P в 0 и получаете Q в 800, обратное путешествие равно (800 - 0 ) - (1000 - 500) = 300. Нет возможности узнать ассиметрию, поэтому вы просто предполагаете, что пакет занимает половину (150) тактов в любом направлении. И эта удаленная временная метка опережает локальную на 1000 - (800 - 150) = 350 тиков. В оба конца будет меняться. Если вы предполагаете, что часы достаточно точны, вы должны использовать долгосрочное среднее значение корреляции.

Обратите внимание, что вы не хотите использовать системные часы для часов. Они могут быть повторно синхронизированы на полпути, сбивая вас с пути. Вы должны использовать clock(CLOCK_MONOTONIC)в Unix или GetTickCountв Windows (не знаю, как эти API обернуты сейчас в Java или Python).


Примечание. Параметр SO_TIMESTAMPсокета (см. Socket (7), упомянутый ott-- в комментарии к вопросу) будет полезен для выделения эффекта задержки цикла обработки событий, который получает пакеты. Стоит ли это усилий, зависит от того, насколько хорошая точность вам нужна.


1

Как узнать, какие часы у игрока правильные? Вы не делаете, так что используйте опорные часы .

NTP здесь излишний - вам нужна точность всего ~ 1 секунды, поэтому используйте rdate или выберите один из многих алгоритмов синхронизации часов.

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


1

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

  • Сколько времени прошло с предыдущего кадра, чтобы вы могли продвигать любые вещи, основанные на времени. Это может отличаться на клиенте и сервере, если оба тикают с разной частотой (например, вы можете иногда видеть серверы, которые работают с фиксированной частотой 20 Гц (или что-то еще), но клиенты, которым разрешено работать так быстро, как они хотят).
  • Сколько времени прошло с момента запуска текущей карты. Это таймер, начинающийся с нуля (просто установите его равным 0 как на клиенте, так и на сервере, когда они запускаются), а время сервера считается «основным», поэтому сервер отправляет текущее представление этого времени клиенту для каждого кадра который работает на сервере. Это может быть получено либо путем взятия текущего времени сервера и вычитания времени, в которое сервер запущен, либо путем накопления времени на кадр выше. Указанное выше время на стороне клиента также может использоваться для генерации точек интерполяции между любыми двумя последовательными кадрами сервера.
  • Ссылка на «базовое время», с которого все остальное время увеличивается; это может быть (но не обязательно для всех типов игр) одинаковым на клиенте и сервере и инициализируется в начале игры (или текущей карты), но никогда не изменяется после (если не новая игра - или новая карта) - запущено).

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

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

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.