Advertisement
  1. Game Development
  2. Multiplayer
Gamedevelopment

Создание одноранговой многопользовательской сетевой игры

by
Difficulty:IntermediateLength:LongLanguages:

Russian (Pусский) translation by Liliya (you can also view the original English article)

Играть в многопользовательскую игру всегда весело. Вместо того, чтобы избивать оппонентов, контролируемых AI, игрок должен столкнуться с стратегиями, созданными другим человеком. В этом учебном пособии представлена ​​реализация многопользовательской игры, проводимой по сети, с использованием ненасильственного подхода однорангового (P2P).

Примечание: Хотя этот урок написан с использованием AS3 и Flash, вы должны использовать одни и те же методы и концепции практически в любой игровой среде разработки. У вас должно быть общее понимание сетевого общения.

Вы можете загрузить или разблокировать конечный код из репозитория GitHub или файлов с zip-файлами.


Предварительный просмотр результатов

Сетевая демонстрация. Элементы управления: arrows или WASD для перемещения, Space для стрельбы, B для развертывания бомбы.

Искусство из Remastered Tyrian Graphics, Iron Plague и Hard Vacuum Дэниела Кука (Lost Garden).


Вступление

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

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

Авторитарная реализация с использованием архитектуры клиент-сервер.

Если клиент выполняет действие, например, перемещение из одной точки в другую, эта информация отправляется на сервер. Сервер проверяет правильность информации, затем обновляет состояние игры. После этого он распространяет информацию всем клиентам, поэтому они могут соответствующим образом обновить свое игровое состояние.

В неавторитетной группе нет центрального объекта, и каждый игрок (игра) контролирует свое игровое состояние. В одноранговом (P2P) подходе одноранговый узел отправляет данные всем другим одноранговым узлам и получает от них данные, считая, что информация является надежной и правильной (без обмана):

Неавторитетная реализация с использованием архитектуры P2P.

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

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

Подсказка: авторитетный подход более защищен от обмана, поскольку сервер полностью контролирует состояние игры и может игнорировать любое подозрительное сообщение, например, объект, заявил, что он перемещался 200 пикселей, когда он может  перемещаться только на 10.

Определение неавторитарной игры

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

Корабль игрока контролируется локально. Модели противников моделируются на основе интернет сети.

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

Эти сообщения занимают время, чтобы путешествовать по сети с одного компьютера на другой, поэтому, когда игрок получает информацию о том, что корабль противника находится на (x, y), его, вероятно, больше нет - вот почему это симуляция:

Задержка связи, вызванная сетью.

Чтобы точность моделирования была достоверной, каждый участник несет ответственность за распространение только информации о своем корабле, а не других. Это означает, что если в игре есть четыре игрока - A, B, C и D говорят, что игрок A является единственным, кто может сообщить, где находится корабль A, если он ударился, если он выстрелил пулю или сбросил бомбу, и как скоро. Все остальные игроки получат сообщения от А, информирующие о своих действиях, и они будут реагировать соответственно, поэтому, если пуля А получит корабль С, тогда С будет транслировать сообщение, сообщающее, что оно было уничтожено.

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

Однако при увеличении латентности имитация становится неточной. Например, игрок A стреляет и локально видит, как пуля попадает в корабль B, но ничего не происходит; это потому, что взгляд A на B задерживается из-за сетевого отставания. Когда B фактически получил сообщение о пуле A, B находился в другом положении, поэтому никакой удар не распространялся.


Сопоставление релевантных действий

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

В нашей игре важными действиями являются:

  • shoot(корабль игрока выпустил пулю или бомбу)
  • move (перемещение игрока)
  • die (корабль игрока был уничтожен)

Действия игрока во время игры.

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

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


Выполнение действий самостоятельно

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

Используя пример съемки нашей игры в качестве примера, если она глубоко взаимосвязана с логикой ввода, невозможно повторно использовать тот же самый код съемки в разных ситуациях:

Выполнение действий самостоятельно.

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

Класс Ship в нашей игре, например, не содержит многопользовательского кода; он полностью развязан. Он описывает корабль, будь то местный или нет. Класс, однако, имеет несколько методов управления судном, например rotate() и setter для изменения своего положения. Как следствие, многопользовательский код может вращать корабль так же, как и код ввода пользователя - разница в том, что он основан на локальном входе, а другой - на сетевые сообщения.


Обмен данными на основе действий

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

Сообщения, обмениваемые в игре, будут описаны как объекты, все из которых содержат обязательное свойство op (код операции). op используется для определения типа сообщения и указания свойств, которые имеет объект сообщения. Это структура всех сообщений:

структура сетевых сообщений.
  • Сообщение OP_DIE сообщает, что судно было уничтожено. Его свойства x и y содержат местоположение судна, когда оно было уничтожено.
  • Сообщение OP_POSITION содержит текущее местоположение судна-партнера. Его свойства x и y содержат координаты корабля на экране, а угол - текущий угол поворота судна.
  • В сообщении OP_SHOT говорится, что корабль выстрелил что-то (пулю или бомбу). Свойства x и y содержат местоположение судна при его запуске; свойства dx и dy указывают направление судна, которое гарантирует, что пуля будет реплицироваться во всех одноранговых точках, используя тот же угол, на котором используется стреляющее судно, когда оно было нацелено; и свойство b определяет тип снаряда (пуля или бомба).

Multiplayer класс

Чтобы организовать многопользовательский код, мы создаем Multiplayer класс. Он отвечает за отправку и получение сообщений, а также за обновление местных судов в соответствии с полученными сообщениями, чтобы отразить текущее состояние имитации игры.

Его первоначальная структура, содержащая только код сообщения, такова:


Отправка сообщений о действиях

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

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

Действие OP_POSITION следует отправлять каждый раз, когда игрок меняет свое текущее положение. Многопользовательский код вводится в код игры для распространения этой информации:

Наконец, действие OP_SHOT должно отправляться каждый раз, когда игрок стреляет. Отправленное сообщение содержит тип пули, который был запущен, так что каждый сверстник увидит правильный снаряд:


Синхронизация на основе полученных данных

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

В игре корабли организованы в боевом порядке. До сих пор у этого строя был только один корабль (игрок). Чтобы создать симуляцию для всех других игроков, класс Multiplayer будет изменен, чтобы добавить новый корабль в этот строй всякий раз, когда новый игрок присоединяется к игре:

Обменный код сообщения автоматически предоставляет уникальный идентификатор для каждого игрока (user.id в коде выше). Эта идентификация используется многопользовательским кодом для создания нового корабля, когда игрок присоединяется к арене; таким образом, каждое судно имеет уникальный идентификатор. Используя идентификатор автора каждого полученного сообщения, можно найти этот корабль в строе кораблей.

Наконец, пришло время добавить handleGetObject() в класс Multiplayer. Этот метод вызывается каждый раз, когда приходит новое сообщение:

Когда приходит новое сообщение, метод handleGetObject() вызывается с двумя параметрами: идентификатором автора (уникальный идентификатор) и данными сообщения. Анализируя данные сообщения, извлекается код операции и на основе этого извлекаются все остальные свойства.

Используя извлеченные данные, многопользовательский код воспроизводит все действия, которые были получены по сети. Принимая сообщение OP_SHOT в качестве примера, это шаги, выполненные для обновления текущего состояния игры:

  1. Посмотрите на местный корабль, userId.
  2. Обновить положение и угол Ship's в соответствии с полученными данными.
  3. Обновить направление Ship's в соответствии с полученными данными.
  4. Вызовите игровой метод, отвечающий за стрельбу снарядов, стрельбу пулей или бомбой.

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


Смягчение проблем задержки

Если игра исключительно перемещает объекты на основе сетевых обновлений, любое потерянное или задержанное сообщение приведет к тому, что объект «телепортируется» из одной точки в другую. Это можно смягчить с помощью местных вычислений.

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

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

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


Заключение

Создание многопользовательской игры в сети - сложная и захватывающая задача. Это требует другого способа увидеть вещи, поскольку все соответствующие действия должны быть отправлены и воспроизведены всеми игроками. Как следствие, все игроки видят симуляцию происходящего, за исключением локального корабля, у которого нет задержек в сети.

В этом учебном пособии описана реализация многопользовательской игры с использованием не авторитетного подхода P2P. Все представленные концепции могут быть расширены для реализации различных многопользовательских механизмов. Начнем создавать многопользовательскую игру!

Advertisement
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.