Многопользовательская синхронизация движения на основе тайлов

8

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

Игра основана на плитке, вы можете двигаться только в 4 направлениях, и каждый ход перемещает спрайт на 32 пикселя (со временем, конечно). Теперь, если я просто отправлю это действие перемещения на сервер, который будет транслировать его всем игрокам, пока нажата клавиша ходьбы, для продолжения ходьбы я должен принять следующую команду, отправить ее на сервер, и для всех клиентов, со временем, иначе движение не будет более плавным. Я видел это в других играх, и это может быть довольно быстро, даже без задержки. Поэтому мне интересно, если это даже жизнеспособный вариант. Хотя это кажется очень хорошим методом для одиночной игры, поскольку он прост, понятен (достаточно просто выполнить следующее действие по перемещению во времени и добавить его в список), и вы можете легко добавить движение мыши (щелкнув мышью по некоторому элементу), чтобы добавить путь к очереди, которая шла.

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

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

Каков «стандартный» способ сделать это?

Марс
источник

Ответы:

4

Я предполагаю, что вы говорите о переезде в режиме реального времени. Попытка интерполировать позицию, вероятно, потерянная причина; из-за медленного соединения ваше игровое состояние может все больше отставать от реального игрового состояния. В отличие от другого комментария, я бы не советовал помещать большую игровую логику на стороне сервера. Когда я реализовал подобные решения, клиент постоянно подключал TCP-сокет к серверу. Когда состояние игры изменяется, он отправляет сообщение на сервер, например, «клиент в x = 10, y = 20». Сервер передает сообщение другим клиентам, которые пытаются обработать его на основе собственной внутренней логики. Использование TCP гарантирует, что ваши сообщения приходят в порядке.

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

Алан Гарднер
источник
1
+1 за 'даже игры AAA не могут справиться с экстремальным отставанием;' На самом деле никто не может отлично справиться даже с небольшими лагами. Хотя мы можем сделать так, как мы можем.
Вальмонд
3

По сути, это то, как вы можете сделать это простым и безопасным способом (предупреждение, экстремальный псевдокод):

A) Клиент (playerid = 5) просит сервер переместиться «вправо» (или лучше, на плитку 73,18)

Б) Сервер проверяет свою большую 2D-карту, которая содержит игроков (или ID игрока, например):

 if(map[73][18] == occupied)
     Send back ('Not OK') to client (the case is blocked by another player)
else
    Set the new position as blocked: map[73][18]=5
    Release the old position: map[72][18]=0;
    Send a 'new position: 5, 73,18' message to all players who are nearby (moving client included)

C) Клиенты получают сообщение «новая позиция» (ну, или игрок 5 получает сообщение «Не в порядке»)

D) клиенты медленно перемещают предмет с playerid = 5 к своей новой позиции (или создают его, если у него нет ни одного предмета с playerid = 5)

Valmond
источник
Что ж, спасибо, но моя проблема заключается в том, чтобы другие клиенты продолжали работать плавно, а не в движении мозаики вообще ^^
Mars
Правильно установите скорость и компенсируйте задержку, например, с помощью мертвого счета или просто «глупым» движением к цели с постоянной скоростью (или пропорциональной скоростью по определенному трезолду, если вы отправляете временные метки вдоль позиций), и все будет в порядке.
Вальмонд
1

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

Я не знаю ни одного стандарта, но первое, что пришло в голову, - это транслировать только «изменения входа», изменения входа игрока, от игрока к остальным. Например, вы можете транслировать только сообщения вдоль строк [нажатие клавиши, идентификатор клавиши, время] или [отпускание клавиши, идентификатор клавиши, время], и позволить игре игроков воздействовать на эти изменения ввода. Включение времени поможет с коррекцией пути (если игрок изменил направление в момент времени t, то «движение вперед» в момент времени t + 1 необходимо будет исправить).

Однако с этим решением вы можете столкнуться с проблемой потерянных сообщений; Предположим, что сообщение "ключ освобожден" не было отправлено? Что-то, что может помочь в этом, заключается в периодическом опросе игрового состояния игрока и возвращении текущей позиции игрока, а также любой нажатой клавиши или даже возвращении всего игрового состояния. В зависимости от количества игроков и команд, вы можете настроить это, чтобы сбалансировать передачу сообщений между клиентами / сервером для хорошего баланса.

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

Я надеюсь, что это помогло!

Джонатан Питр
источник
1
Проблема только с отправкой входных данных заключается в том, что если вы пропустите один или иногда просто интерпретируете их в неправильном порядке, то ваше состояние игры больше не будет в порядке, т.е. два клиента будут показывать разные «экраны».
Вальмонд
@ Вальмонд очень хорошая мысль ... на самом деле, я чувствую, что удаляю свой ответ, поскольку в этом свете он кажется неправильным.
Джонатан Питр
1
Вы можете отправлять входные данные на сервер (до тех пор, пока все в порядке), но сервер должен (IMO) отправлять точные данные или, по крайней мере, проверять данные или, возможно, отправлять целое состояние игры (это было сделано в реальных играх, например Blood Bowl). ), возможно, вы можете настроить свой ответ вместо того, чтобы удалить его :-)
Valmond