Я делаю простой маленький MOBA просто для удовольствия. Я делал все для одного игрока, потом понял: «О, черт, наверное, мне стоит добавить мультиплеер».
Раньше я ничего не делал с сетями, поэтому изучение того, как интегрировать Лидгрена в мою игру, было забавным и удивительным. Дело в том, что я в значительной степени знаю, что я делаю что-то неправильно, потому что оно недостаточно надежно для использования в обычных играх, насколько я знаю, но что с ним не так?
Что я делаю, так это то, что когда игрок выполняет какое-либо действие, он отправляет на сервер сообщение: «Эй, я только что сделал это». На сервере и клиенте выполняется одно и то же моделирование. Затем сервер отправляет сообщение всем другим клиентам, сообщая им, что этот парень сделал это.
По большей части, за исключением нескольких случаев, когда игрок делает что-то, клиент полагает, что это круто, и делает это самостоятельно. Поэтому, когда вы щелкаете правой кнопкой мыши где-нибудь, чтобы переместиться туда, клиент этого игрока просто начинает перемещать туда своего парня, а затем отправляет сообщение на сервер, сообщая об этом.
Итак, в основном:
- Игрок 1 разыгрывает заклинание, чтобы заставить его двигаться на 100% быстрее в течение шести секунд
- Локальный клиент Player 1 добавляет этот бафф к своему объекту Unit
- Клиент Игрока 1 отправляет на сервер сообщение «Эй, я только что произнес это заклинание»
- Сервер проверяет, действительно ли у него достаточно маны, чтобы разыграть это заклинание, и если да, добавляет этот бафф к копии сервера этого объекта Unit.
- Сервер отправляет сообщение всем другим клиентам, говоря: «Эй, этот парень только что произнес это заклинание»
- Каждый другой клиент получает сообщение и говорит: «А, ладно, круто», и добавляет этот бафф к своему локальному объекту Unit для этого игрока.
Я пробежался по вещам, чтобы увидеть, как большие игры делают мультиплеер, и это немного сбивает с толку тех, кто только начинает баловаться с этим, но похоже, что движок Source отправляет пакет, содержащий все изменения, ко всему в Мир каждый тик? Опять же, совершенно новичок в этом деле, но можете ли вы действительно загружать столько данных так часто?
Извините, если это немного бессмысленно, но в основном мне было интересно, почему моя более простая система не подходит, потому что если бы это было, другие игры использовали бы ее, верно?
источник
Ответы:
В дополнение к ответу Byte56, есть еще несколько вещей, которые следует учитывать:
Как вы собираетесь общаться между клиентами о движении игроков? В отличие от большинства других действий игрока, которые, как правило, являются изолированными событиями и, вероятно, несколько редкими, движение является непрерывным. Существует ограничение на скорость, с которой вы можете (и хотите, если хотите) отправлять и получать обновления. Предсказание на стороне клиента, о котором упоминал Байт56, обычно включает периодические обновления информации о положении и скорости клиента. Затем клиент локально интерполирует между ними, используя что-то вроде кубического сплайна .
Вторая проблема, которая связана с предыдущими, заключается в том, что UDP не имеет гарантированной доставки. Вы не можете быть уверены, что каждое отправленное вами сообщение приходит или даже приходит в правильном порядке. Вы можете отправлять пакеты 1, 2 и 3, и сервер получает 3, а затем 1, а не 2. Часто они будут в правильном порядке, и часто они будут приходить, но не всегда. Итак, вам нужна система, которая устойчива к потере пакетов. Достаточно простой системы подтверждения. Обычно используется битовое поле, сообщающее другому узлу, получил ли он последние 32 сообщения (для 32-разрядного типа int) и каким было последнее полученное сообщение. Таким образом, вы можете пометить сообщения как критические или нет, и повторно отправить, если они не получают критические. Здесь довольно приличное обсуждение .
При этом вам также следует помнить, что ваши клиенты будут не синхронизированы друг с другом. Каждый из них будет показывать другим игрокам интерполяцию между их предыдущими двумя сетевыми кадрами, пока вы работаете над следующим, в лучшем случае. Таким образом, вам нужна система, которая учитывает (справедливо), что то, что видел игрок, когда выполнял действие, не было фактическим состоянием игры, когда он делал это действие. Он реагировал на старое несинхронное игровое состояние.
Наконец, если эта игра призвана быть конкурентоспособной, вам также нужно беспокоиться об обмане. Таким образом, насколько это возможно (и разумно), вы должны не доверять клиентам и проверять их действия. «Нет, вы не можете пройти через эту стену. Нет, вы не можете идти быстрее, чем ваша скорость бега. Нет, вы не можете утверждать, что поразили эту цель». и т.п.
Для большего количества идей я рекомендую просмотреть другие статьи во второй ссылке.
Удачи!
источник
То, что вы описываете, по сути является предсказанием на стороне клиента , но вы не говорите, что происходит, когда сервер и клиент расходятся.
Он развивался со времен, когда клиент был просто тупым терминалом, отправляющим свои данные на сервер, и сервер сообщал клиенту результат. Однако, как только игры вышли за пределы локальной сети (и часто раньше), задержка стала заметной в этой ситуации. То, что вы описываете, было предложено на стороне клиента, чтобы исправить это. Теперь клиент также моделирует движение в ожидании ответа сервера. Затем они приходят к соглашению о результате. С сервером, являющимся авторитетом.
Следующие шаги - как вы реагируете на разногласия. Если у вас ничего нет для этого, вы получите клиентскую резинку или телепортирование, когда клиент и сервер не согласятся.
источник
Timing. В других ответах не упоминается время событий на сервере и разных клиентах. В зависимости от игры, это может быть чем-то, на что стоит обратить внимание. Задержка (или Lag) вводит переменную задержку между отправкой пакета и его получением. Время может быть непростым, но я постараюсь объяснить возможные проблемы как можно лучше. Есть некоторые игры, которые можно обойти, не беспокоясь об этом, но вот простой пример того, где это может вызвать проблемы.
Предположим, что все действуют на пакеты, как только они приходят.
Предположим, что время 0 (T0) и T1 близко друг к другу.
Что будет дальше, зависит от того, кто на это смотрит, и от того, в каком порядке пакеты поступают на сервер. Сервер всегда должен иметь последнее слово. Если сервер получает пакеты в указанном выше порядке, то сервер применит щит до того, как выстрел и игрок 1 (P1) выживет. С точки зрения P1, подняв щит сам, он увидит щит перед выстрелом и выживет. Но как насчет P2? Они увидят выстрел сразу же, потому что выстрелили, но увидят ли они сначала щит? Если
(T0 + latency between P1 and the server + the latency between the server and P2) > T1
после выстрела щит поднимется, и P2 будет думать, что их выстрел убил P1. Серверу придется как-то исправить эту ситуацию.Однако если сервер принимает пакеты в обратном порядке (что вполне возможно, даже если T0 <T1), то происходит обратное. P1 неправильный (и мертвый), в то время как P2 правильный (и победный).
Есть несколько способов справиться с подобными ситуациями, но проще всего позволить серверу делать все. Вы можете попытаться смоделировать это на клиенте, но не допускайте никаких постоянных действий, таких как смерть. Игрокам придется ждать важных подтверждений смены игры с сервера.
Отправка метки времени с действиями может быть полезной. Если вы в основном доверяете клиентам, вы можете использовать эти метки времени, чтобы определить, какое действие произошло первым, а не следовать нашему первому предположению. Это может быть сложно, потому что получение сообщений из прошлого обычно означает, что вы должны иметь возможность обратить время вспять.
Время это весело, а? Независимо от того, что вы в конечном итоге делаете, полезно знать об этих временных проблемах.
источник