Разработка игрового приложения на Android

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

Рубрика Программирование, компьютеры и кибернетика
Вид дипломная работа
Язык русский
Дата добавления 24.06.2018
Размер файла 4,5 M

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.

3.3 Редактор трехмерной графики

Необходимость в редакторе трехмерной графики выражалась в следующем:

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

2. Трехмерные модели окружения, извлекаемые из файлов с такой же сложной структурой, как и в случае с автомобилями, несколько хаотичны. Проблема в том, что модели для отображения издали (так называемые LOD - Levels Of Detail, «уровни детализации») и их версии для отображения вблизи различаются по геометрии (очевидно, что у моделей для дальней отрисовки меньше детализация), но при этом находятся в пределах одного файла. Такие модели должны быть разделены вручную, а менее детализированная их версия должна быть удалена. Это связано с тем, что в собственном проекте было решено не использовать низкополигональные версии моделей, так как разница между оригинальными моделями высокой и низкой детализации не должна показаться существенной на данном этапе развития мобильных устройств.

3. Все модели оригинальной игры должны были быть преобразованы в формат, который принимается средой Unity.

Трехмерные редакторы принято делить на универсальные, узкоспециализированные, игровые движки и программы для создания цифровой скульптуры. Для решения таких задач, как полигональное моделирование (создание модели из составляющих ее трех- или четырехугольников), редактирование содержимого уже готовых моделей или наложение текстур, подойдут универсальные трехмерные редакторы. Самыми популярными из них на данный момент являются: Modo, Autodesk 3ds Max, Maya, Houdini и Blender.

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

Однако выбор автора пал на Autodesk 3ds Max. Этот продукт ведет свою историю с 1990 года[23] и, помимо того, что реализует все необходимые функции для удобного и быстрого моделирования, имеет крупнейшую базу справочных материалов и уроков.

Основным минусом Autodesk 3ds Max является его цена: на момент написания этой работы она составляет 6251 рубль в месяц или 49384 рубля в год, что, конечно, является неподъемной суммой для любого студента. Однако фирма-производитель Autodesk идет навстречу обучающимся, предлагая бесплатную подписку на продукт, если студент предоставляет информацию о своем учебном заведении. Автор воспользовался этим предложением.

Интерфейс программы представлен на рисунке 4.

Интерфейс отличается некоторой сложностью и большим количеством условных обозначений, в которых может быть сложно разобраться, однако при наличии некоторого опыта работа в этом редакторе не составляет труда. Интерфейс, в зависимости от выбранной конфигурации или собственной настройки, предлагает большое количество панелей инструментов для решения различных задач. Для разработки игрового приложения автору понадобились такие встроенные инструменты, как Edit Poly («Редактирование полигонов») и Unwrap UVW («Развертка координат текстур»).

Editable Poly («редактируемые полигоны») - это такой тип объекта, который предлагает работу с пятью видами подобъектов: вершина, ребро, грань, полигон или элемент. В отличие от прочих типов редактируемых объектов, при работе с editable poly под термином «полигон» понимается не треугольник, а многоугольник с любым количеством углов. Понятия «вершина» и «ребро» в контексте данного инструмента тождественны таким же понятиям в геометрии. Понятие «грань» обозначает последовательность рёбер, которые составляют собой выпуклую или вогнутую границу соединенных между собой без разрыва полигонов. Если же полигоны образуют замкнутую трехмерную фигуру (скажем, куб), то грань будет отсутствовать. Любая группа полигонов, замкнутая или нет, называется «элемент». Это по сути полноценный трехмерный объект, только не имеющий собственного отдельного имени и находящийся в составе другого объекта. Трансформировать такой подобъект возможно только в режиме редактирование Edit poly.

Рисунок 4. Интерфейс редактора трехмерной графики Autodesk 3ds Max

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

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

Инструмент Unwrap UVW позволяет работать с разверткой. Развёртка поверхности - это фигура, получающаяся в плоскости при таком совмещении точек данной поверхности с этой плоскостью, при котором длины линий остаются неизменными[25]. То есть инструмент Unwrap UVW используется для того, чтобы сопоставить координаты изображения, используемого в качестве текстуры, с координатами вершин объекта. Однако, в отличие от работы с развертками в геометрии, географии и на реальных объектах, ребра развертки редактируемого объекта в этом инструменте могут сколь угодно далеко растягиваться. Фрагмент изображения, накладываемый на полигон, которому принадлежит ребро, в таком случае также деформируется, чтобы координаты вершин на текстуре соответствовали заданным. Кроме того, инструмент позволяет использовать одну и ту же текстуру на нескольких полигонах объекта одновременно, или использовать несколько разных текстур для разных подобъектов.

С помощью инструмента Unwrap UVW велось так называемое «текстурирование» автомобилей и моделей окружения для разрабатываемой игры.

Таким образом, разработку игрового проекта на Android решено вести в среде разработки игр Unity, написание и отладка программных модулей ведется в среде MonoDevelop-Unity с применением языка программирования C#, а создание и редактирование трехмерных моделей осуществляется в редакторе трехмерной графики Autodesk 3ds Max.

4. Проектная часть

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

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

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

4.1 Архитектура приложения

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

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

Графические движки принято делить на двумерные и трехмерные. Если для создания двумерной игры иногда достаточно стандартной графической библиотеки, встроенной в среду разработки ПО, то для трехмерных игр необходимы более сложные решения. Наиболее популярными и распространенными являются библиотеки Direct3D и OpenGL, при этом Direct3D лучше поддерживается ОС Windows, а OpenGL - всеми прочими операционными системами. Библиотеки возможно подключать к средам разработки приложений и работать напрямую с ними при разработке игры, однако Unity уже изначально отрисовывает трехмерную графику с помощью этих библиотек, при этом предлагая более удобный процесс работы и более высокий уровень программирования.

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

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

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

Готовые решения для всех этих составляющих игровой архитектуры уже предлагаются средой разработки игр Unity.

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

Такое решение для Unity также является стандартным.

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

1. Класс «Ручное управление автомобилем»:

1.1. Обработка нажатия кнопок;

1.2. Ускорение автомобиля игрока;

1.3. Торможение автомобиля игрока;

1.4. Переключение передней и задней передачи автомобиля игрока;

1.5. Поворот направо автомобиля игрока;

1.6. Поворот налево автомобиля игрока;

1.7. Направить руль автомобиля игрока прямо;

2. Класс «Управление автомобилем»:

2.1. Ускорение автомобиля;

2.2. Поворот руля на нужный угол;

2.3. Торможение;

2.4. Переключение передней и задней передачи;

2.5. Включение и выключение поворотников;

3. Класс «Автоматическое управление автомобилем»;

3.1. Свободное движение;

3.2. Движение по заданному пути;

4. Класс «Навигатор»:

4.1. Поиск кратчайшего пути;

4.2. Назначение кратчайшего пути автомобилю;

4.3. Сброс назначенного пути у автомобиля;

5. Класс «Диспетчер»:

5.1. Создание грузов и размещение их по складам городов;

5.2. Обработка прибытия пустого грузовика к складу за грузом;

5.3. Начало соперничества;

5.3.1. Выбор соперников и назначение пути;

5.4. Обработка прибытия грузовика с грузом к месту прибытия;

5.5. Конец соперничества;

5.5.1. Расчет и выдача денег;

6. Класс «Создание трафика на дорогах»:

6.1. Создание и размещение трафика в пределах зоны видимости;

6.2. Удаление трафика при выезде его из зоны видимости;

7. Класс «Сохранение и загрузка»:

7.1. Сохранение состояния игры;

7.2. Загрузка состояния игры;

8. Класс «Участник»:

8.1. Участие в соревновании;

8.1.1. Назначение груза;

8.2. Выход из соревнования;

8.2.1. Снятие груза;

8.3. Расчет повреждений при ударе;

8.4. Расчет оставшегося топлива;

9. Класс «Интерфейс»:

9.1. Обработка нажатия кнопок и клавиш;

9.2. Вывод меню и информационных сообщений;

10. Класс «Заправочная станция»:

10.1. Расчет цены и вывод информации;

10.2. Заправка топливом за деньги;

11. Класс «Станция тех. обслуживания»:

11.1. Расчет цены и вывод информации;

11.2. Ремонт за деньги.

12. Класс «Игрок»:

12.1. Изменение количества игровой валюты;

13. Класс «Пункт приема»:

13.1. Обработка прибытия грузовика;

14. Класс «Пункт выдачи»:

14.1. Обработка прибытия грузовика;

14.2. Обработка выбора груза для доставки.

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

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

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

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

4.2 Разработка структурно-функциональной схемы приложения

Для разработки структурно-функциональной схемы необходимо определить работающие модули и связи между ними. Основные модули были определены в предыдущем пункте (см. 4.1 Архитектура приложения). Для определения связей между модулями было решено составить описание возможных сценариев игрового процесса. Пример стандартного игрового сценария доставки груза с описанием связей между модулями:

1. «Пункт выдачи» сообщает «интерфейсу», что прибыл пустой грузовик;

2. «Интерфейс» выдает информацию об имеющемся грузе;

3. Пользователь выбирает доставить этот груз. «Интерфейс» сообщает «диспетчеру» о начале соревнования;

4. «Диспетчер» выбирает находящихся неподалеку «участников» и назначает им соревнование;

5. Каждый «участник» (кроме игрока) обращается к собственному «навигатору» для поиска пути;

6. Найдя путь, «навигатор» назначает его своему «автоматическому водителю»;

7. «Автоматический водитель» управляет «машиной»;

8. «Интерфейс» определяет нажатия кнопок игроком и направляет указания «машине», которая игроку принадлежит;

9. «Пункт приема» сообщает «диспетчеру, что прибыл грузовик (не грузовик игрока) с грузом;

10. «Диспетчер» снимает «участника» с соревнования;

11. «Участник» сообщает «навигатору» о снятии с пути;

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

13. «Пункт приема» сообщает «диспетчеру», что прибыл грузовик (грузовик игрока) с грузом;

14. «Диспетчер» сообщает всем «участникам» о том, что они сняты с соревнования;

15. Все «участники» сообщают своему «навигаторам» о снятии с пути;

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

17. «Диспетчер» сообщает «игроку», что выдает ему определенное количество денег;

18. «Диспетчер» сообщает «интерфейсу» о конце гонки и призе.

Пример описания сценария ремонта грузовика на станции технического обслуживания:

1. «Станция технического обслуживания» спрашивает у «игрока», сколько у него денег;

2. «Игрок» сообщает «станции технического обслуживания» сумму;

3. «Станция технического обслуживания» определяет, насколько может отремонтировать грузовик на эту сумму и сообщает об этом «интерфейсу»;

4. «Интерфейс» выдает информацию и обрабатывает выбор игрока;

5. При положительном выборе «интерфейс» сообщает «станции технического обслуживания», что заправка одобрена;

6. «Станция технического обслуживания» сообщает грузовику игрока («участник») о новом уровне состояния грузовика;

7. «Станция технического обслуживания» сообщает «игроку», что забрала у него определенное количество денег.

Похожая схема работы - у заправочной станции.

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

Рисунок 5. Пример диаграммы вариантов использования на этапе прототипирования

Рисунок 6. Пример диаграммы классов на этапе прототипирования

Рисунок 7. Диаграмма последовательности схемы выдачи груза на этапе прототипирования

Рисунок 8. Фрагмент диаграммы последовательности схемы заправки машины игрока топливом на этапе прототипирования

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

Рисунок 9. Структурно-функциональная схема приложения

4.3 Проектирование пользовательского интерфейса

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

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

а) кнопки были достаточно крупными и заметными;

б) кнопки, вызывающие взаимоисключающие действия («ускорение» и «торможение», «поворот налево» и «поворот направо»), располагались достаточно близко друг к другу, чтобы возможно было быстро переместить палец с одной на другую;

в) кнопки располагались в то же время достаточно далеко друг от друга, чтобы при нажатии на экран в нужном месте быть достаточно уверенным, что сработает нажатие именно на выбранную кнопку, а не на соседнюю;

г) все кнопки не загораживали происходящие на экране действия.

Временный интерфейс управления автомобилем выглядел подобным образом (рисунок 10).

Как видно из рисунка, в левом нижнем углу располагаются большие кнопки L и R, вызывающие поворот руля налево или направо. Если обе кнопки отпущены, руль восстанавливается в прямое положение. Кнопки в правом нижнем углу - B и F, вызывающие разгон и торможение автомобиля (B - от английского «break», F - от «forward»).

Рисунок 10. Интерфейс управления автомобилем на ранних этапах разработки

Собственный опыт управления игровым автомобилем с таким интерфейсом показал:

а) удобство разделения функций разгона / торможения и поворота налево / направо на правую и левую руки соответственно;

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

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

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

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

3. Результаты исследований и опыта работы профессионалов в индустрии мобильных игр и разработке интерфейсов.

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

Так, известный дизайнер Артемий Лебедев в веб-версии своей книги о дизайне «Ководство» приводит[26] следующее правило экранных интерфейсов:

«В экранных интерфейсах любые элементы управления не должны быть по площади меньше квадрата размером 16Ч16 пикселей (в который умещается курсор)».

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

Компания-разработчик мобильных устройств и приложений Apple в своем руководстве по созданию интерфейсов для iPhone «iPhone Human Interface Guidelines» рекомендует[27] принять размер 44 на 44 пикселя в качестве минимального. Журнал по дизайну Smashing Magazine, ссылаясь на исследование MIT Touch Lab «Human Fingertips to investigate the Mechanics of Tactile Sense» [28], в своей достаточно подробной статье по разработке интерфейсов для мобильных приложений приводит[29] более разнообразные и несколько отличающиеся от совета Apple данные:

1. Средняя ширина указательного пальца - от 16 до 20 мм, что, учитывая разрешение экрана в 1280 на 720 пикселей, составляет диапазон от 45 до 57 пикселей.

2. Средняя ширина большого пальца - около 25 мм, что при таком же разрешении означает 72 пикселя.

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

Кроме этого, была принята во внимание статья, описывающая[30] выступление разработчика мобильных игр Ольги Лысенко из компании «My.com» на конференции «White Nights St. Petersburg 2016», которая рекомендует следующее:

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

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

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

4. Для привлечения внимания пользователя следует использовать размер и анимацию элементов.

5. Не стоит занимать мелкими элементами весь экран.

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

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

После проведенного анализа началась работа над полноценным интерфейсом приложения. Итоговым вариантом основного интерфейса стал следующий:

Рисунок 11. Итоговый вариант основного интерфейса

Как видно, осталось разделение на левую и правую руки. Кнопки на левой стороне экрана отвечают за поворот руля, кнопки на правой - за движение. При этом функционал обозначается максимально простыми формами: стрелки влево и вправо обозначают поворот, стрелки вверх и вниз - переключение передней и задней передачи. Черный квадрат означает торможение, а его расположение под кнопкой «ГАЗ» дает интуитивно понять его функцию.

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

Рисунок 12. Камера переключена на вид снаружи, карта выключена

Рисунок 13. Карта в полномасштабном режиме

При нажатии кнопки принимают «вдавленный» вид.

Значения «fps» и «av» в правом верхнем углу означают моментальное и среднее за игру количество кадров в секунду и нужны для подведения статистики.

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

Рисунок 14. Пиктограммы на карте

а) машина игрока с указанием направления;

б) грузовик;

в) соперничающий грузовик;

г) станция технического обслуживания;

д) заправочная станция;

е) город.

Иконки также копируют внешний вид оригинальных иконок из «Дальнобойщиков-2» и уже знакомы для тех, кто играл в эту игру.

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

«1 из 4»: положение игрока в текущем соревновании. На данный момент с игроком соревнуются три грузовика, при этом игрок ближе всех к пункту назначения.

«Груз: 84%»: целостность груза. Груз может повреждаться при столкновениях, на данный момент его целостность - 84 процента.

«0 км/ч»: скорость. На данный момент машина игрока стоит.

«$85»: количество денег у игрока. На данный момент - 85 условных единиц. При очень больших суммах число сокращается до количества тысяч с обозначением - буквой «к». Пример: «5402к» означает от 5402000 до 5402999 условных единиц.

Значок заправки и «69%»: количество топлива в баке. Значок заправки дает интуитивно понять, что речь идет именно о топливе.

Значок грузовика и «59%»: целостность грузовика. При малых значениях грузовик значительно замедляет свою скорость или не едет вообще.

Кроме того, под информационной полосой еще предусмотрено появление дополнительной строки для вывода мгновенных сообщений (рисунок 15, сообщение «Игра загружена»). Это могут быть сообщения о загрузке или сохранении игры, о заработанных или снятых деньгах.

Рисунок 15. Пример моментального сообщения

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

«911»: при наличии денег восстанавливает машину игрока на ближайшей автотрассе, а также добавляет некоторое количество здоровья и топлива.

«Отмена»: возврат к игре.

«Начать сначала»: возвращает машину игрока к складу города «Южный», а игровые значения - к значениям по умолчанию.

«Сохранить принудительно»: сохранить текущее состояние игры. При этом стирается предыдущее сохранение. Кроме этого, игра автоматически сохраняет свое состояние каждый раз, как груз доставлен до места назначения.

«Загрузить последнее сохранение»: пользователь может продолжить игру с последнего сохранения.

«Выход из игры»: перед выходом пользователю будет предложено сохранить текущее состояние игры.

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

При отсутствии сохранений на текущий момент, кнопка «загрузить текущее сохранение» выключена и показана серым цветом.

Примеры разделов меню:

Рисунок 16. Меню паузы

Рисунок 17. Меню с негативным сообщением, сохранений сделано еще не было

Кроме основных разделов меню, в игре присутствуют боковые меню. Они появляются при выборе груза (рисунок 19) и при заезде на станцию технического обслуживания (рисунок 18). Боковые меню не перекрывают полностью обзор и появляются за кнопками управления, позволяя пользователю проехать дальше или остановить автомобиль.

Боковое меню станции технического обслуживания имеет два пункта: ремонт и модернизация. При наличии денег пользователю предлагается отремонтировать грузовик или усилить двигатель. В противном случае выводится сообщение о недостатке денег. На рисунке 18 приведен пример случая, когда имеющихся 500 условных единиц хватает на ремонт до 91%, но не хватает на хоть какое-то улучшение работы двигателя.

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

Рисунок 18. Боковое меню станции технического обслуживания

Рисунок 19. Боковое меню пункта загрузки

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

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

5. Программная реализация

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

5.1 Компоненты Unity, используемые для разработки приложения

Как уже было сказано ранее, среда Unity оперирует понятием «игровой объект». Игровые объекты имеют имя и место в иерархии других игровых объектов. К каждому игровому объекту применяются различные компоненты. Про единственный обязательный компонент «Transform» уже было написано ранее (см. 3.2 Среда разработки). Прочие компоненты расширяют функции игровых объектов. Вот основные из используемых в приложении:

1. «Mesh Filter»: этот компонент загружает определенную импортированную трехмерную модель из менеджера ресурсов и ассоциирует ее с объектом. Без прочих компонентов трехмерная модель не отображается и никак себя не проявляет.

2. «Mesh Renderer»: этот компонент отрисовывает трехмерную модель, если она ранее ассоциирована с объектом. У компонента существуют настройки, позволяющие включить или отключить отбрасывание моделью теней, реагирование на освещение сцены, настройки отражений и прочее. Кроме того, компонент подгружает из менеджера ресурсов материалы и применяет их к модели.

3. «Light»: компонент превращает игровой объект в источник света. Доступны 4 типа источника света: spot (направленный свет из точки), directional (направленный свет с параллельными лучами), point (всенаправленный свет из точки) и area (источник света - прямоугольник). Настройки изменяются в зависимости от выбранного типа источника, и в общем виде предлагают изменение интенсивности и цвета.

4. «Sphere Collider»: это так называемый «коллайдер», создающий в начале координат объекта невидимую сферу, размеры которой можно изменять. Форма этой сферы будет учитываться физическим движком при столкновениях и любых контактах со всеми прочими коллайдерами, присутствующими в сцене.

5. «Mesh Collider»: этот коллайдер загружает в начало координат выбранную трехмерную модель, размеры и форма которой будет учитываться физическим движком. В отличие от «mesh renderer», используется не трехмерная модель, ассоциированная с объектом, а любая трехмерная модель, которую можно загрузить из менеджера ресурсов.

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

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

8. «Rigid Body»: настройки физического тела для физического движка. Помимо коллайдеров, для взаимодействия с другими объектами физический движок будет учитывать параметры этого компонента: масса, трение, влияет ли на объект сила гравитации, является ли объект динамически меняющим свою форму, нужно ли блокировать перемещение или вращение объекта по какой-либо из его осей, и прочее.

9. «Camera»: этот компонент превращает игровой объект в виртуальную камеру. Некоторые настройки: угол обзора, нужно ли при отрисовке изображения с камеры стирать предыдущее изображение, координаты области для отрисовки на игровом экране, расстояние, объекты ближе которого не нужно отрисовывать, и некоторые другие.

10. «Canvas»: это компонент, используемый для отрисовки пользовательского интерфейса. Создает так называемый «холст», который игнорирует трехмерное пространство игры и позволяет работать с текстурами и текстом, находящимися ниже в иерархии, как с двумерными объектами.

11. «Canvas Scaler»: компонент, который автоматически подстраивает размер холста под размер экрана устройства.

12. «Text»: компонент, выводящий текст на холст, либо проявляющий его в трехмерном пространстве. Доступны стандартные настройки текста: шрифт, размер и т.п.

13. «Image»: компонент, выводящий изображение на холст.

14. «Raw Image»: компонент, выводящий на холст изображение, которое не было загружено в менеджер ресурсов, а создавалось прямо в ходе работы приложения. Такое изображение, к примеру, может отрисовываться со второй камеры и проецироваться как текстура зеркала заднего вида.

15. «Canvas Renderer»: компонент без настроек, необходимый для отрисовки изображений или текста на холсте.

16. «Event Trigger»: компонент позволяет обрабатывать простейшие взаимодействия пользователя с объектом (нажатие на объект, наведение курсора и т.д.), вызывая выбранные методы. В настройке предлагается выбрать тип действия, выбрать скрипт, метод из которого будет выполняться, и сам метод. Компонент помогает при прототипировании или в случаях, когда не нужно сложной обработки взаимодействия игрока с объектом.

17. Компонент-скрипт.

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

Для определения поведения игровых объектов в качестве нового компонента добавляется компонент-скрипт. Имя основного класса скрипта берется в качестве имени класса компонента. Для этого основной класс должен быть наследником класса MonoBehaviour, определенного заранее средой Unity. Если это условие выполнено, то в настройках компонента отображаются public-переменные, объявленные в классе, а также переменные с видимостью private, если при этом они снабжены атрибутом [SerializeField].

В качестве примера приведен фрагмент класса optimizeAway (рисунок 20) и отображение соответствующего компонента в окне Inspector (рисунок 21):

public class optimizeAway: MonoBehaviour {

public float cleanRadius;

public Color color;

private GameObject environmentObject;

private GameObject participantsObject;

private GameObject[] allExistingWorldParts;

private GameObject[] allExistingParticipants;

private main main;

Рисунок 20. Фрагмент исходного кода класса optimizeAway

Рисунок 21. Итоговый компонент Optimize Away

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

5.2 Основные процедуры, функции и алгоритмы работы приложения

Помимо функции Start(), которая по умолчанию запускается при создании нового экземпляра данного игрового объекта, и функции Update(), которая по умолчанию вызывается с каждым тактом, также использовались добавленные мною функции lateStart() и slowUpdate().

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

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

Выполнение этих двух функций обеспечивается строчками, приведенными на рисунке 22. Они добавляются в конец функции Start().

Invoke («lateStart», 0.3f);

InvokeRepeating («slowUpdate», 1f, 1f);

Рисунок 22. Вызов функций lateStart() и slowUpdate()

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

В этом разделе приведены блок-схемы функций и сами функции Start(), Update() модуля автоматического управления автомобилем AIDrive и алгоритм поиска кратчайшего пути модуля Navigator.

Рисунок 21. Блок-схема процедуры Start() модуля AIDrive

Рисунок 23. Блок-схема процедуры Update() модуля AIDrive

void Start () {

 // 1. Setting variables

carScript = this. GetComponent<carScript> ();

carTransform = carScript.carTransform;

main = GameObject. Find («GAME»).GetComponent<main> ();

allExistingPaths = main.pathsObject. GetComponentsInChildren<path> ();

maxFromCarTorqueRemembered = maxFromCarTorque;

onSensorMultiplierRemembered = onSensorMultiplier;

slowBeforeTurnsRemembered = slowBeforeTurns;

sideSensorsAngleRemembered = sideSensorsAngle;

leftSideSensorRemembered = leftSideSensor;

rightSideSensorRemembered = rightSideSensor;

 // 2. Overriding carscript checks

if (switchCarScriptChecks) {

carScript.overrideSteering = true;

carScript.brakesOnWeakTorquing = true;

carScript.spinVWArtificially = true;

}

 // 3. Trying to get me as a participant

try {

thisPart=this. GetComponent<participant>();

} catch {

thisPart = null;

}

 // 4. Calling latestart

Invoke («lateStart», 0.3f);

InvokeRepeating («slowUpdate», 1f, 1f);

}

Рисунок 24. Исходный код процедуры Start() модуля AIDrive

void Update () {

if (overtaker) // 3. Checking if we change node because of overtaking

ifMoveNodeWhileOvertaking ();

 // 4. Movement

if (! virtualMovement) { // 4.1 Real movement with collisions and so on:

Steer(); // 4.1.1. Steering

 // // 4.1.2. Checking if we have an obstacle ahead:

RaycastHit closestHit;

Vector3 closestSensorStartPos;

if (checkAnObstacle (out closestSensorStartPos, out closestHit)) {

if (OUT) Debug. Log (closestHit.collider.gameObject.tag + Vector3

Рисунок 25. Исходный код процедуры Update() модуля AIDrive (начало)

Distance (closestSensorStartPos, carTransform.position).ToString());

onFacingObstacle (closestSensorStartPos, closestHit); //React to the obstacle

}

else {

goOn (); //Speed car

if (overtaker)

CancelInvoke («startOvertaking»); //If it is free ahead, no need to overtake

}

} else { // 4.2. Virtual movement to free some resources:

moveVirtually(); // 4.2.1. Move and orient virtually:

checkVirtualArrived(); // 4.2.2. Cheking if we reach zeroPorch of the cargo destination:

}

 // 5. Checking if we reach the point:

checkIfWeReachTheNode();

 // 6. Drawing line to the next node in the viewport

Debug. DrawLine (carTransform.position, nodePosition, new Color (1, 1, 1, 0.2f));

if (OUT) {

Debug. Log («nodeindex:» + nodeIndex);

}

}

Рисунок 26. Исходный код процедуры Update() модуля AIDrive (конец)

Для поиска кратчайшего маршрута по графу в приложении используется публичная функция findRouteTo, вызывающая приватную рекурсивную функцию findWay. Для начала стоит уточнить, что в системе путей в приложении не используется понятие «вершины», а только понятие «пути», тождественное понятию «ребра» у графа. Последовательность путей составляет «маршрут», по которому ориентируется грузовик с автоматическим управлением.

Ниже приведены обе функции, публичная и приватная, с переведенными на русский язык комментариями:

// Внешняя функция для поиска кратчайшей последовательности путей:

public path[] findRouteTo (path start, path target) {

bool found = false;

 // Сначала мы пробуем быстрый способ:

bool temp = excludeOtherLanes;

excludeOtherLanes = true;

Route route = findWay (start, target, new List<path> (), out found);

 // Если путь не найден, мы можем попробовать полный анализ, если это позволено:

if (route.length == 0 && temp == false) {

if (OUT)

Debug. Log («No route like this. Trying full analysis»);

excludeOtherLanes = false;

route = findWay (start, target, new List<path> (), out found);

}

 // Возвращаем настройки

excludeOtherLanes = temp;

if (route.length!= 0) {

if (OUT) {

Debug. Log («Route length:» + route.length);

Debug. Log («Route is:»);

for (int i = 0; i < route.points. Length; i++)

Debug. Log (» *» + route.points [i]);

}

path[] ret = new path [route.points. Length - 1];

for (int i = 1; i < route.points. Length; i++)

ret [i - 1] = route.points [i];

return route.points;

} else {

if (OUT)

Debug. Log («No route like this»);

return new path[0];

}

}

 // Внутренняя рекурсивная функция поиска кратчайшей последовательности путей:

private Route findWay (path iStart, path iTarget, List<path> iUsedPaths, out bool found, int iter=0) {

if (OUT)

Debug. Log («Analyzing» + iStart);

if (OUT) Debug. Log («iUsedPaths [» + iUsedPaths. Count +»]»);

if (iter >= maxDepth && maxDepth!=0) {

if (OUT) Debug. Log («BREAKING AT» + iter);

found = false;

return new Route ();

}

Рисунок 27. Фрагмент исходного кода модуля Navigator (начало)

 // Если маршрута не существует, возвращаем пустой:

if (iStart == null || iTarget == null) {

if (OUT) Debug. Log (iStart + «is empty»);

found = false;

return new Route ();

}

 // Если на этом пути поиск уже осуществлялся, возвращаем пустой маршрут:

if (iUsedPaths. Contains (iStart)) {

if (OUT) Debug. Log (iStart + «is already used»);

found = false;

return new Route ();

}

 // Добавляем этот путь и все его полосы как уже посещенные:

iUsedPaths. Add (iStart);

if (iStart.otherLanes. Length > 0 && excludeOtherLanes)

foreach (path lane in iStart.otherLanes)

if (lane!= null)

iUsedPaths. Add (lane);

 // Если дорога в ремонте, возвращаем пустой маршрут:

if (iStart.broken) {

if (OUT) Debug. Log (iStart + «is broken»);

found = false;

return new Route ();

}

 // Если этот путь - цель, возвращаем его и его длину:

if (iStart == iTarget) {

if (OUT) {

Debug. Log (iStart + «is the target»);

}

found = true;

path[] temp = {iStart};

return new Route (temp, (iStart.getLength()));

}

 // Если поворот налево с этого пути - цель, возвращаем этот путь и поворот, а также их общую длину:

if (iStart.nextPathOnLeft == iTarget) {

if (OUT) Debug. Log (iStart + «has target on the left»);

found = true;

path[] temp = {iStart, iStart.nextPathOnLeft};

float tlen = iStart.getLength () +

iStart.nextPathOnLeft.getLength ();

if (OUT) Debug. Log («returning path[] with» +iStart + iStart.nextPathOnLeft +» and length of» + tlen);

return new Route (temp, tlen);

}

Рисунок 28. Фрагмент исходного кода модуля Navigator (продолжение)

 // Если поворот направо с этого пути - цель, возвращаем этот путь и поворот, а также их общую длину:

if (iStart.nextPathOnRight == iTarget) {

if (OUT) Debug. Log (iStart + «has target on the right»);

found = true;

path[] temp = {iStart, iStart.nextPathOnRight};

float tlen = iStart.getLength () +

iStart.nextPathOnRight.getLength ();

if (OUT) Debug. Log («returning path[] with» +iStart +»; «+ iStart.nextPathOnRight +» and length of» + tlen);

return new Route (temp, tlen);

}

 // Иначе идем вглубь:

Route left = new Route();

Route right = new Route();

bool leftFound = false;

bool rightFound = false;

List<path> leftPaths = new List<path> (iUsedPaths);

List<path> rightPaths = new List<path> (iUsedPaths);

 // Рекурсивный вызов:

if (iStart.nextPathOnLeft!= null)

left = findWay (iStart.nextPathOnLeft, iTarget, leftPaths, out leftFound, iter + 1);

if (iStart.nextPathOnLeft!= iStart.nextPathOnRight)

if (iStart.nextPathOnRight!= null)

right = findWay (iStart.nextPathOnRight, iTarget, rightPaths, out rightFound, iter + 1);

 // Если найдены маршруты при повороте и налево и направо, выбираем кратчайший:

if (leftFound && rightFound) {

if (right.length > left.length) {

found = leftFound;

path[] temp = concatArrays (iStart, left.points);

float tlen = iStart.getLength () + left.length;

return new Route (temp, tlen);

} else {

found = rightFound;


Подобные документы

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

    дипломная работа [791,8 K], добавлен 10.07.2017

  • Общее описание разрабатываемого приложения, его актуальность и сферы практического применения. Выбор среды разработки и языка программирования, 3D-движка. Архитектура приложения, интерфейса и его главных элементов, взаимодействие с пользователем.

    дипломная работа [317,5 K], добавлен 10.07.2017

  • Создание, изучение и разработка приложение на Android. Среда разработки приложения DelphiXE5. Установка и настройка среды программирования. Этапы разработки приложения. Инструменты для упрощения конструирования графического интерфейса пользователя.

    курсовая работа [1,6 M], добавлен 19.04.2017

  • Характеристика работы операционной системы Android, используемой для мобильных телефонов. Создание Android проекта в среда разработки Eclipse. Общая структура и функции файла манифест. Компоненты Android приложения. Способы осуществления разметки.

    курсовая работа [1,0 M], добавлен 15.11.2012

  • Архитектура и история создания операционной системы Android. Язык программирования Java. Выбор средства для реализации Android приложения. Программная реализация Android приложения. Проведение тестирования разработанного программного обеспечения.

    курсовая работа [167,8 K], добавлен 18.01.2017

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

    дипломная работа [3,4 M], добавлен 12.08.2017

  • Преимущества операционной системы Android. Проектирование интерфейса приложений. Визуальные редакторы и средства кроссплатформенной разработки. Оптимизация игрового процесса, выбор фреймворка и библиотек. Классификация и характеристика игр по жанрам.

    дипломная работа [2,6 M], добавлен 10.07.2017

  • Проектирование удобного приложения для комфортной навигации по файлам облачного хранилища в одном файловом менеджере. Выбор интегрированной среды разработки. Выбор инструментов для визуализации приложения. Выбор средств отслеживания HTTPзапросов.

    курсовая работа [3,6 M], добавлен 16.07.2016

  • Общая характеристика интерфейса языка программирования Delphi. Рассмотрение окна редактора кода, конструктора формы, инспектора объектов и расширения файлов. Ознакомление с основными этапами создания и сохранения простого приложения; проверка его работы.

    презентация [184,3 K], добавлен 18.03.2014

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

    дипломная работа [1,2 M], добавлен 04.02.2016

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.