Как я могу эффективно отправлять объекты в моей игре с архитектурой клиент-сервер - PullRequest
0 голосов
/ 25 мая 2019

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

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

Спрайты хранятся в Dictionary<string, sprite>, который хранится на клиентских и серверных компьютерах.

Это реализовано так:

  1. Пользовательский ввод с клавиатуры и мыши отправляется на сервер каждый кадр (KeyboardState,MouseState).
  2. Сервер принимает данные и обновляет состояние игры.
  3. Сервер отправляет каждому клиенту свой видовой экран (прямоугольник), а также позицию (float, float), ключ спрайта(строка), вращение (float), цвет (int, int, int, int) всех спрайтов в области просмотра этого пользователя.
  4. Сервер хранит эту информацию как экземпляры класса, который содержит эти значения.
  5. Чтобы отправить его, сервер использует BinaryFormatter для сериализации класса и отправляет его, используя TcpClient и Sockets.
  6. Клиент десериализует входящие данные обратно в классы ирисует их на экране

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

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

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

Как бы яэффективно отправлять данные или реализовывать их иначе, чтобы они были эффективными?

1 Ответ

2 голосов
/ 28 мая 2019

Минимизируйте объем данных, проходящих через сеть. Отправляйте только необходимое количество данных и предоставьте свою собственную проверку с помощью отметок времени и проверки.

Каждый actionId и AnimationId в следующем должны демонстрировать минимальное (степень 2) количество байтов для уникального описания всех возможных значений.


Сервер -> Клиент:

На серверах известны положение клиента и ротация. Подтверждение последнего actionId. Список всех других позиций клиентов, ориентаций (поворотов), animationIds ... в поле зрения клиента + - maxRotationRate на расстоянии MaxViewDistance + - maxMovementRate.

Клиент должен усреднять свою текущую позицию с позицией серверов на каждом шаге.

Обрабатывать все входы локально (мышь и клавиатура) и отправлять только соответствующие данные на сервер:

При каждом обновлении клиент будет отправлять соответствующие данные и обновлять свое собственное внутреннее состояние, обрабатывать заданное состояние сервера и увеличивать значение int (назовите это меткой времени). Включите здесь паритет или CRC.


Клиент -> Сервер Текущая позиция, поворот, actionId, animationId и монотонно увеличивающееся значение int (назовите это меткой времени). Включите здесь паритет или CRC.

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

Данные о местоположении будут переданы (локальные обновления и настройки сервера).

Данные о местоположении и повороте и скорости (как линейные, так и вращательные) необходимо отправлять на сервер при каждом обновлении. При получении на сервере должен пройти процесс проверки, чтобы предотвратить мошенничество. В случае пропущенных, вышедших из строя или неправильно сформированных обновлений сервер примет последнюю позицию + скорость * (разница во времени с последней отметкой времени + текущее время сервера).


Вы должны использовать UDP для связи (обратите внимание, что вы используете свои собственные временные метки и CRC для проверки полученных данных, больше нет сбоев на недействительных данных).

Обрабатывать пакеты только в тех случаях, когда проверки четности / CRC проходят, и отклонять пакеты, которые получены слишком короткими или не прошли проверки. Эти проверки устранят сбой, связанный с ошибочными пакетами.

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

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

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

...