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

Тип:
Добавлен:

Содержание

Введение

1. Аналитический обзор

1.1 Анализ предметной области

.2 Анализ требований.

.3 Выбор средств разработки

2. Проектирование

2.1 Общая архитектура приложения

.2 Проектирование клиентской части приложения

.3 Проектирование серверной части приложения

3. Реализация

3.1 Реализация пользовательского интерфейса

.2 Реализация серверной части

4. Тестирование

Заключение

Список используемых источников

Приложение

Введение

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

1. Аналитический обзор

.1 Анализ предметной области

На 2016 год, в одном из самых известных цифровых рынков в мире - Steame, было выпущено более 10000 игр. Среди них игры самых разных жанров, сложности, стоимости. [3]

Эти проекты разрабатываются группами энтузиастов, независимыми студиями, а также хорошо развитыми игровыми корпорациями. Последние для разработки игр используют собственные программные продукты (игровые движки), так как имеют время и деньги на их параллельную разработку. Небольшим же студиям приходится пользоваться уже готовыми решениями. Самые распространенные из них: Unity, Unreal Engine, Cry Engine, Game Maker, Construct 2. Каждый из представленных выше программных продуктов обладает своими достоинствами и недостатками. Например, два последних движка идеально подходят для разработки 2D игр, с наименьшими требованиями в знании программирования. Они подойдут для начинающих разработчиков или тех, кто вообще не знаком с программированием, а также для моментального создания игровых прототипов для тестирования самой идеи игры. Хоть там и разрешен скриптинг на их собственных языках, в большинстве случаев он не требуется. [4,5]

Рисунок 1.1 - Логотипы программ Game Maker Studio и Construct 2.

Unity является универсальным движком, позволяющим одинаково удобно создавать игровые проекты как в двумерном, так и в трехмерном пространстве. Он позволяет использовать готовые модули для быстрой сборки прототипов, а также поддерживает полноценное написание скриптов на языке С#. [6]

Рисунок 1.2 - Логотип программы Unity 3D

Unreal Engine и Cry Engine являются более «тяжелыми» движками, в основном предназначены для трехмерных шутеров, однако и другие игры на них тоже разрабатывают. Если вы хотите, чтобы ваша игра была самой реалистичной в плане графики, тогда эти продукты подойдут идеально. Они также позволяют писать скрипты на языке С++. [7,8]

Рисунок 1.3 - Логотипы программ Unreal Engine и Cry Engine.

В данной работе будет использоваться клиент-серверная архитектура приложения. Для разработки приложения с такой архитектурой существуют специализированные программные продукты: PlayerIO, SmartFox Server, Photon Network. Можно и самостоятельно писать программное обеспечение, но это требует больших временных затрат. Данные сервисы доступны для пользователей в нескольких тарифных планах, один из которых - бесплатный. Он позволяет протестировать как систему, так и свое приложение, но имеются определенные ограничения. Для добавления новых возможностей и снятия этих ограничений придется ежемесячно оплачивать подписку. В плане доступных возможностей на бесплатном тарифе, и последующей стоимости подписки самым выгодным является PlayerIO, он и будет использоваться при разработке приложения. [9]

Рисунок 1.4 - Логотип сервиса по хостингу серверов PlayerIO.

1.2Анализ требований

При разработке любого программного продукта первой стадией является составление документации. И сфера игровых разработок не исключение. Для определения цели, структуры игры, механики и сюжета, а также графического оформления создается специальный дизайн-документ. Ответственным за его написание назначается менеджер проекта, гейм-дизайнер или тимлид (лидер команды, от англ. - team leader). Документ может включать в себя бизнес-информацию, оценку продукта, временную карту разработки и тому подобное. Благодаря этому определяются требования к программному продукту. Приведем краткое описание требований к игровому приложению:

Жанр игры: одними из наиболее распространенных жанров на рынке в наши дни являются RPG и Action. Следовательно, для достижения наилучшего результата, нужно придерживаться общей игровой тенденции и в первую очередь разрабатывать игры таких жанров. Наша работа будет содержать в себе их смешение, что также является очень актуальным и распространенным на игровом рынке.[11]

Графическая часть: одно из наиболее важных критериев, от которого зависит скорость и стоимость разработки. Для того, чтобы максимально избежать дополнительных затрат, как временных так и денежных, следует использовать векторную 2D графику. Хоть сейчас и присутствует тенденция выхода игр с пиксельной графикой, она является более сложной для отрисовки и требует от художника определенных навыков. Это в свою очередь повышает цену изображения. Также, суть использования именно двухмерного пространства заключается как в простоте создания визуального оформления, так и в облегченном программировании, с меньшим количеством вычислений в целом.

Рисунок 1.5 - Пример графического оформления игры.

Технические особенности: заключаются в архитектуре приложения, в использовании программных и аппаратных средств. Данная игра должна включать клиент-серверную модель приложения. Серверная часть может располагаться на нескольких физических серверах, но должна работать как единое целое. Все вычисления и проверки проходят на серверной стороне, клиентская часть лишь принимает входящие данные, отображает их пользователю на экран. Никаких игровых вычислений и обработки информации на клиентской стороне производиться не должно. [1]

Рисунок 1.6 - Клиент-серверная архитектура.

1.3Выбор средств разработки

Данный игровой проект будет разрабатываться на игровом движке Unity 3D. Это обеспечит наибольшую скорость разработки при помощи drag and drop интерфейса и использования одного из самых распространенных языков программирования - С#.

Рисунок 1.7 - Интерфейс Unity 3D.

В качестве среды программирования будет использована MS Visual Studio 2017. Преимущества этой среды перед MonoDeveloper, которая включена в Unity, заключаются в более удобном интерфейсе, возможности дебажить программу с показом используемых ресурсов в режиме реального времени.

Рисунок 1.8 - Интерфейс программы Visual Studio 2017.

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

Стоить отметить и сервисы, которые не будут иметь прямого отношения к самой игре, но внесут важную лепту в разработку программы. Это визуализированный трекер задач Trello. Главной целью данного сервиса является отслеживание задач, времени выполнения, распределения между исполнителями и контролем процесса работы. Он является бесплатным и очень удобным для пользования. [10]

Рисунок 1.9 - Интерфейс серверного приложения.

Рисунок 1.10 - Интерфейс визуальной доски задач.

2. Проектирование

.1 Общая архитектура приложения

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

Рисунок 2.1 - Общая архитектура многопользовательского игрового приложения.

На клиенте установлено игровое приложение, разработанное на движке Unity3D, внутри которого выполняются скрипты, написанные на языке программирования C#. По сути, игра является зацикленным realtime-приложением, многократно повторяющим свои действия. Внутри движка установлены сторонние библиотеки, называемые Api. Это программный код, отвечающий за взаимодействие разрабатываемой программы с внешним, независимым сервисом. При этом программист не знает внутреннего строения внешней системы, ему доступны только публичные функция для вызова в своем приложении. Запросы с клиента, передаются с помощью api в блок Multiplayer. Это также realtime-приложение, которое принимает и обрабатывает запросы в соответствии с кодом, хранящимся в Storage. Собственно Storage - это файловое хранилище сервера, в котором могут располагаться как программный код, так и текстуры, иные файлы. Блок Authentication отвечает за авторизацию пользователя на сервере. Он независим от Multiplayera, так как, только пройдя аутентификацию, клиент сможет отправлять игровые данные на сервер для последующей обработки. BigDB - это встроенная система управления базой данных, основанная на NoSQL базе. Для разрабатываемого приложения достаточно будет следующей структуры:

Рисунок 2.2 - Структура базы данных.

В таблице Users хранится информация о зарегистрированных пользователях, а именно - данные для авторизации. Поиск по таблице осуществляется по единственному индексу - email. В таблице RoomsId осуществляется учет созданных игровых комнат, к которым могут подключиться пользователи. Для ускорения поиска нужных комнат в индексы, вместе с id комнаты добавлена переменная isFull, которая показывает, достигло ли количество игроков максимальной вместимости одно игровой зоны. CountPlayers показывает текущее количество игроков.

2.2 Проектирование клиентской части приложения

Как было написано выше, клиентское приложение отвечает только за передачу информации на сервер, получении ответов с сервера и отображении информации на экране для пользователя. Все действия пользователя, любая игровая активность поступает на сервер, где полученная информация обрабатывается. Результаты обработки отправляются обратно клиенту. Затем данные поступают на экран компьютера. Это может быть какое-либо действие, анимация с персонажем и другими игровыми объектами, взаимодействие с окружающим миром. Пакеты данных отправляются по протоколам TCP/UDP, в зависимости от требуемой задачи. Например, при отправке запроса на авторизацию пакеты отправляются по протоколу TCP. Для постоянной синхронизации с сервером местоположения игрока, не обязательно после каждого пакета ожидать подтверждения доставки, поэтому можно использовать UDP.

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

После построения приложения формируется набор файлов, представляющих файловую структуру готового приложения.

Рисунок 2.3 - Файловая структура приложения.

В основной папке располагается исполняемый файл формата .exe и папка с требуемыми данными. Эта папка включает в себя игровые ресурсы, используемые библиотеки, локальные настройки. В папке Managed сохранены библиотеки .dll, которые нужны для работы написанных скриптов. В папке Mono хранится конфигурация проекта. Resources включает в себя настройки включения и конфигурации графический ресурсов приложения. А сами текстуры располагаются в корне каталога в файлах формата .resS и .resource. Для каждого уровня создается файл данного формата, который содержит в себе все изображения в бинарном формате. Информация о проекте хранится в файле app.info, а файлах level0-level5 - информация об уровнях. Globalgamemanagers собирает все включенные ресурсы и библиотеки в себя, для загрузки после старта приложения. Ну и последний файл output_log.txt хранит отладочную информацию о ходе работы приложения.

2.3 Проектирование серверной части приложения

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

Выделим основные модули, которые должны присутствовать на сервере: модуль идентификации, с его помощью пользователи смогут заходить в свои аккаунты и сохранять игровую статистику; модуль работы с базой данных - отвечает за соединение с базой и таблицей, отправку запросов, принятие ответов; модуль балансировки нагрузки - принимает входящие на сервер пакеты данных и отправляет соответствующим модулям с наименьшей загруженностью; модуль обработки игрового мира - это главный модуль, внутри которого проходят все игровые события, создается карта, персонажи и т.д. Также присутствуют дополнительные модули, которые лишь дополняют игровую механику, но все же достаточно важны. К ним относятся модули чата, шифрования, внутреннего взаимодействия модулей и тому подобное. У каждого модуля есть свой «адрес» в системе, благодаря которым отправляемые пакеты данных достигают свой цели. Например, клиентское приложение отправляет какой-либо запрос на сервер, указывая адрес балансировщика. Тот в свою очередь определяет, что это за данные, для чего они предназначены и передает его уже на обработку конечному модулю по заранее известному адресу. При включении нового модуля, например при повышенных нагрузках, для него определяется адрес и сохраняется на сервере. При уменьшении количества передаваемых данных, неиспользуемый модуль закрывается, адрес удаляется. При этом запись адреса должна включать в себя физическое местоположения модуля, так как из-за распределенности системы один сервер может находиться сразу на нескольких физических машинах.

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

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

Рисунок 2.4 - Блок-схема алгоритма.

3. Реализация

.1 Реализация пользовательского интерфейса

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

Рисунок 3.1 - Интерфейс меню.

При совпадении значений авторизация считается успешной, и игрок попадает в лобби. Лобби - это игровая комната, в которой отображается вся информация об игровом персонаже, все настройки, и также кнопки для запуска поиска комнаты-арены.

Рисунок 3.3 - Внутриигровой интерфейс.

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

.2 Реализация серверной части

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

Рисунок 3.4 - Интерфейс сервиса PlayerIO.

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

Рисунок 3.5 - Пример хранения информации о пользователе.

Вторая таблица RoomsId в базе данных отвечает за хранение информации о доступных комнатах для подключения игроков. Она содержит три поля: id, countPlayer, isFull. Первое поле связывает игрока, создавшего комнату с хранимым объектом в таблице. То есть, чтобы присоединиться к этому игроку, и попасть в одну игровую комнату не требуется знать ее автоматически создаваемого названия, можно просто найти по имени пользователя. Второе поле показывает, сколько игроков уже находится в комнате. При превышении максимального порога, а именно 16 игроков, комната считается полной и в ход вступает третье поле. Оно является ключевым при поиске свободных игровых комнат для пользователя.

Рисунок 3.6 - Пример объекта в таблице RoomsId.

Пример серверного кода, в котором показана структура объекта игрока и методы передачи сообщений приведен в приложении 1. Сам сервер имеет два типа комнат: лобби и арена. Благодаря такому разделению возможно выделить независимые друг от друга запросы, распределяя нагруженность системы в целом. В лобби осуществляется обработка персональной информации игрока. На арене же постоянно обрабатываются игровые события, которые абсолютно не задействуются в лобби-комнате.

Алгоритм работы авторизации:

1)С клиента отправляется запрос на авторизацию. В запросе передаются введенные пользователем электронная почта и пароль. Пароль передается в зашифрованном виде.

2)Сервер принимает сообщение с типом Login и локально сохраняет имя пользователя и пароль.

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

)При совпадении паролей клиенту отправляется ответ об успешной аутентификации. Иначе, отправляется сообщение о неправильно введенном пароле или о не существующем имени игрока.

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

Во время игры между пользователями постоянно передаются сообщения. Можно посчитать примерное максимальное значение передаваемых пакетов в пределах одной комнаты одному игроку. Для этого возьмем максимально допустимое количество игроков - 16, вычтем самого пользователя и умножим на количество отправляемых пакетов в секунду от одного игрока. Оно приблизительно равно 30. В итоге получаем 450 пакетов в секунду передается одному пользователю. Всего в комнате пересылается 7200 пакетов в секунду. При большом объеме информации и количестве комнат это может вызвать достаточно большую нагрузку на сервер. Поэтому следует передавать только необходимую информацию, которая поможет рассчитать и собрать на клиенте полный набор данных.

Каждый пакет данных имеет свой тип, по которому определяются дальнейшие действия над полученной информацией. Приведем примеры с пояснениями некоторых из них:

)Create. Данный тип пакета используется при вхождении игроком в комнату-арену. Он передает логическую информацию на сервер о том, что пользователь готов начать игру. На сервере создается объект игрока, задаются начальные параметры. Затем с сервера отсылается ответ такого же типа, с требуемыми параметрами. При получении, на клиенте создается объект игрового персонажа, и сохраняются переданные параметры.

2)Move. Тип данных, используемый для передачи текущих координат после совершения передвижения. С клиента отправляется пакет с координатами, и сервер рассылает эти данные всем игрокам внутри комнаты.

)Attack. При совершении выстрела игроком, на сервер отправляется информация с данным типом. Затем она рассылается другим пользователям и уже на клиенте происходит исполнение данного события.

static string GetMd5Hash(string input)

{(MD5 md5Hash = MD5.Create())

{[] data = md5Hash.ComputeHash(Encoding.UTF8.GetBytes(input));sBuilder = new StringBuilder();(int i = 0; i < data.Length; i++)

{.Append(data[i].ToString("x2"));

}sBuilder.ToString();

}

}

Листинг 3.7 - Функция формирования хещ-суммы по алгоритму md5.

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

Полученный хеш передается на сервер, где он и сравнивается со значением из базы данных.

игровой алгоритм сервер интерфейс

4. Тестирование

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

Рисунок 4.1 - Консоль серверного приложения.

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

Рисунок 4.2 - Консоль игрового приложения.

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

Рисунок 4.3 - Проверка правильности ввода данных работает.

Собственно запуск самой игры. Загрузка уровня произошла успешно, вся информация отображается корректно.

Рисунок 4.4 - Игровой уровень.

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

Рисунок 4.5 - Запуск в системе Windows 10.

Как видим, приложение успешно запустилось в данной операционной системе. Отметим, что для успешной работы приложения на компьютере пользователя должны быть установлены библиотеки .NET от Microsoft. Так как приложение поддерживает сборку и для 32-битных систем, оно успешно запустится и на более старых системах, таких как windows 7, XP.

Теперь проверим запуск игры в unix-подобной системе, а именно в Ubuntu 16.04.

Рисунок 4.6 - Запуск в системе Ubuntu 16.04.

Для этого в Unity3D был выбран режим построения для Linux, 64-битная сборка. Приложение сразу начало свою работу без требования установки дополнительного программного обеспечения. Можно предположить, что и в аналогичных unix-подобных системах приложение сможет запуститься без каких-либо серьезных проблем.

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

При тестировании производительности приложения будем опираться на одну характеристику, очень важную для всех любителей активных игр - это fps (кадров в секунду, с англ. - frame per second). На рисунке 4.7 можно увидеть игровую сцену, на которой находится одновременно максимальное количество игроков для одной комнаты, а именно 16. В правом верхнем углу отображается вся статистика по процессорной загрузке, видео, а также количество отображаемых элементов в данный момент. Напротив строки Graphics: можно увидеть число, которое и показывает количество кадров в секунду в момент времени. Минимальное число кадров, которое удалось достигнуть - ~480fps. Это очень высокое значение, которое означает, что за одну секунду картинка на экране сменится примерно 480 раз. Это обеспечит наибольшую сглаженность и плавность действий. Заметим, что стандартом в игровой сфере является 60 кадров в секунду. Именно такое количество непрерывно сменяющихся картинок может быть замечено человеческим глазом. Если fps продолжать увеличивать, то визуально никакой разницы в плавности картины замечено не будет. Минимальной границей частоты кадров, при которой сохраняется плавность показа фоторяда, считается 30 fps. Если бы количество кадров в игре было бы меньше данного минимума, тогда игру пришлось бы оптимизировать.

Рисунок 4.7 - Тестирование производительности.

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

Заключение

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

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

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

Список используемых источников

1. Mail.Ru Group. Архитектура сервера онлайн-игры на примере Skyforge

. Документация .NET Framework 4.5 and 4.6

. Valve рассказала, сколько всего игр в Steam

. Construct 2 - конструктор для создания 2D игр без программирования и скриптов

5. GameMaker Studio 2 Manual

. Unity - Руководство: Руководство Unity

. Unreal Engine 4 Documentation | Unreal Engine

. Home - CRYENGINE Home - Documentation

. Documentation - PlayerIO

. About Trello - Trello Help

11. Исследование игровых сеттингов / Блог компании Mail.Ru Group / Хабрахабр

Приложение 1

Листинг основных программных блоков серверной части

public class Player : BasePlayer

{= bornPositionX[this.command];= bornPositionY[this.command];= 100f;= true;

}bool isDeath()

{(healht < 0)

{= false;true;

}

{false;

}

}

// Gettersint GetCommand()

{this.command;

}float GetPosX()

{this.posx;

}float GetPosY()

{this.posy;

}float GetRotate()

{this.rotate;

}string GetRoomId()

{this.room;

}

// Settersvoid SetCommand(int id)

{.command = id;

}void SetPosX(float x)

{.posx = x;

}void SetPosY(float y)

{.posy = y;

}void SetRotate(float rotate)

{.rotate = rotate;

}void SetRoomId(string id)

{.room = id;

}

}

[RoomType("GameRoom")]class GameCode : Game<Player>

{List<Player> players = new List<Player>();string typeGame;int counterCommand = 0;override void GameStarted()

{.WriteLine("Game is started: " + RoomId);

}override void GameClosed()

{.WriteLine("RoomId: " + RoomId);

}override void UserJoined(Player player)

{++;(counterCommand > 4)

{= 1;

}.SetCommand(counterCommand);.Add(player);.WriteLine("User Jointed " + player.ConnectUserId);(Player pl in players)

{(pl.ConnectUserId != player.ConnectUserId)

{.Send("PlayerJoined", player.ConnectUserId, player.GetPosX(), player.GetPosY(), player.GetRotate());.Send("PlayerJoined", pl.ConnectUserId, pl.GetPosX(), pl.GetPosY(), pl.GetRotate());

}

}

}override void UserLeft(Player player)

{.Remove(player);("PlayerLeft", player.ConnectUserId);

}override void GotMessage(Player player, Message message)

{(message.Type)

{"Create":.WriteLine("Send " + player.ConnectUserId);.Reborn();.Send("Create", player.ConnectUserId, player.GetPosX(), player.GetPosY(), player.GetRotate());;"Move":.SetPosX(message.GetFloat(1));.SetPosY(message.GetFloat(2));.SetRotate(message.GetFloat(3));(Player pl in players)

{(pl.ConnectUserId != player.ConnectUserId)

{.Send("Move", player.ConnectUserId, player.GetPosX(), player.GetPosY(), player.GetRotate());

}

};"Chat":(Player pl in players)

{(pl.ConnectUserId != player.ConnectUserId)

{.Send("Chat", player.ConnectUserId, message.GetString(0));

}

};"Attack":(Player pl in players)

{(pl.ConnectUserId != player.ConnectUserId)

{.Send("Attack", player.ConnectUserId, message.GetFloat(1), message.GetFloat(2));

}

}

break;

}

}

}

Приложение 2

Листинг программного кода скрипта взаимодействия с сервером

public class Clientside : MonoBehaviour {string name = "Test";GameObject[] playerPrefab = new GameObject[10];GameObject[] bullet = new GameObject[10];GameObject weapon;Canvas menu;float rot = 0f;Texture2D[] numeral = new Texture2D[10];GameObject player;Client client;Connection connection;List<PlayerIOClient.Message> msgList = new List<PlayerIOClient.Message>();Dictionary<string,string> options = new Dictionary<string, string> ();int teamId = 0;int ammo = 30;bool isReload = false;Start () {.Add ("maxplayers", "16");userId = Settings.email;.PlayerIO.Authenticate(

"shooter-gpmw9uiee0uxk34a7hzp7w",

"public",Dictionary<string, string>{{"userId", userId}},,(Client client) {.Log ("Authenticate");.client = client;.Multiplayer.DevelopmentServer = new ServerEndpoint("localhost",8184);.Multiplayer.CreateJoinRoom(.roomId,

},(PlayerIOError error) {.Log("Error Joining Room: " + error.ToString());

}

);

}

);

}void SendAttack(){(ammo > 1)

{(!isReload)

{-;.Send("Attack", player.name, player.transform.position.x, player.transform.position.y);

}

}

{.Reload();

}

}void Reload()

{= !isReload;

}handlemessage(object sender, PlayerIOClient.Message m) {.Add(m);

}FixedUpdate() {(player != null) {.Send("Move", player.name, player.transform.position.x, player.transform.position.y, player.transform.rotation.z);

}(PlayerIOClient.Message m in msgList) {(m.Type) {"PlayerJoined":.Log("It's not me");otherPlayer = GameObject.Instantiate(playerPrefab[teamId]) as GameObject;.transform.position = new Vector3(m.GetFloat(1), m.GetFloat(2), 0);.name = m.GetString(0);.GetComponent<Control>().enabled = false;.Log(otherPlayer.name);;"Create":(player == null) { .Log("It's me");= (GameObject)Instantiate(playerPrefab[teamId]);.transform.position = new Vector3(m.GetFloat(1), m.GetFloat(2), 0);.name = m.GetString(0);= m.GetInt(3);.GetComponent<Control>().enabled = true;.GetComponent<Control>().player = player;.Log(player.name);

};"Move":upplayer = GameObject.Find (m.GetString (0));.transform.position = new Vector3(m.GetFloat(1), m.GetFloat(2), 0);.transform.eulerAngles = new Vector3(0,0,m.GetFloat(3));;"Attack":othplayer = GameObject.Find (m.GetString (0));posX = othplayer.transform.position.x + (Mathf.Cos((othplayer.transform.localEulerAngles.z - 90) * Mathf.Deg2Rad)) * -player.GetComponent<Control>().shooting_speed;posY = othplayer.transform.position.y + (Mathf.Sin((othplayer.transform.localEulerAngles.z - 90) * Mathf.Deg2Rad)) * -player.GetComponent<Control>().shooting_speed;game_bullet = Instantiate(bullet[teamId], othplayer.transform.position, othplayer.transform.rotation) as GameObject;_bullet.GetComponent<Bullet>().master = othplayer;_bullet.GetComponent<Rigidbody2D>().AddForce(new Vector2(posX, posY));;"PlayerLeft":playerd = GameObject.Find(m.GetString(0));(playerd);;

}

}.Clear();(isReload) {(ammo < 30)++;(ammo == 30) {.Reload();

}

}

}void OnGUI()

{mouse = Input.mousePosition;(ammo > 9)

{x = ammo % 10;y = (int)ammo / 10;.DrawTexture(new Rect(mouse.x + 18, -mouse.y + Screen.height - 8, 16, 16), numeral[y]);.DrawTexture(new Rect(mouse.x + 35, -mouse.y + Screen.height - 8, 16, 16), numeral[x]);

}{.DrawTexture(new Rect(mouse.x + 18, -mouse.y + Screen.height - 8, 16, 16), numeral[0]);.DrawTexture(new Rect(mouse.x + 35,-mouse.y + Screen.height - 8,16,16), numeral[ammo]);

}

}

}

Copyright © 2018 WorldReferat.ru All rights reserved.