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

  • Вид работы:
    Дипломная (ВКР)
  • Предмет:
    Информационное обеспечение, программирование
  • Язык:
    Русский
    ,
    Формат файла:
    MS Word
    1,71 Мб
  • Опубликовано:
    2017-07-10
Вы можете узнать стоимость помощи в написании студенческой работы.
Помощь в написании работы, которую точно примут!

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

ОГЛАВЛЕНИЕ

ВВЕДЕНИЕ

. ТЕХНИЧЕСКОЕ ПРЕДЛОЖЕНИЕ

. АНАЛИЗ ПРЕДМЕТНОЙ ОБЛАСТИ

.1 Обзор аналогов

.2 Выводы по предметной области

.3 Индивидуальность проекта

. ВЫБОР СРЕДЫ РАЗРАБОТКИ И СТОРОННИХ БИБЛИОТЕК

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

.2 Выбор фрэймворка

. РЕАЛИЗАЦИЯ ПРИЛОЖЕНИЯ

.1 Проектирование интерфейса

.2 Подготовка графических материалов

. ВЕКТОР РАЗВИТИЯ

ЗАКЛЮЧЕНИЕ

СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ

ПРИЛОЖЕНИЕ

ВВЕДЕНИЕ

В настоящее время в индустрии видеоигр направление мобильных платформ получило активное развитие. Наиболее популярные игры по аудитории значительно опережают игры с ПК и игровых консолей, а по данным компании SuperData [1] на рынке мобильных игр доход за 2016 год составил $40.6 млрд. при общих для индустрии 91$ млрд.

Разработка игровых приложений для мобильных платформ представляет собой наименее сложный, затратный и рискованный способ для разработчика получить опыт в разработке игр. Мобильные игры по структуре значительно проще аналогов с других платформ, а цена размещения готового продукта в таких системах цифрового распространения, как Google Play [2], чаще всего ограничивается разовым взносом регистрации разработчика.

Мобильные игры так же предоставляют разработчику множество способов развития проекта, в том числе распространение уже получившей некоторую известность игры на персональные компьютеры. Такое расширение можно увидеть на примерах игр Braveland [3] или Warhammer 40,000: Deathwatch [4], которые в настоящее время размещены в системе цифрового распространения Steam [5].

По всем вышеприведённым доводам мною было принято решение начать разработку мобильного игрового приложения. Система Android была выбрана по причине её максимальной среди мобильных платформ простоте и открытости, но это не ограничивает проект и в процессе дальнейшего развития также возможно распространение на iOS и Windows Phone.

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

Помимо жанра для игры необходимо определение образа внутреннего мира (сеттинга, от англ. setting) и модели монетизации.

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

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

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

1. ТЕХНИЧЕСКОЕ ПРЕДЛОЖЕНИЕ

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

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

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

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

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

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

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

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

Ввиду вышеуказанной информации, мною решено принять следующие параметры:

время отклика приложения - 0,5 секунды;

минимальная версия операционной системы - Android 7.0;

задержка хода искусственного интеллекта - 1 секунда.

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

2. АНАЛИЗ ПРЕДМЕТНОЙ ОБЛАСТИ

.1 Обзор аналогов

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

Braveland [3] - игра 2014 года. Один из наиболее близких аналогов, так как практически полностью совпадает по жанру и сеттингу, однако распространялась по платной модели. Помимо Android так же вышла на iOS, а позже версия для ПК была опубликована в Steam [5]. Получила известность среди любителей жанра и высокие оценки пользователей - средняя оценка в Google Play [2] составляет 4,4 балла (каждый пользователь выставляет оценку по пятибалльной шкале), а в настоящее время опубликовано два продолжения. Примечательна простотой игровых механик и дизайном - практически все элементы игрового процесса можно найти в более ранних представителях жанра, что не помешало хорошим продажам игры.

Battle for Wesnoth [6] - распространяемая по лицензии GNU General Public License [7] игра 2003 года выпуска от независимых разработчиков. К настоящему времени получила широкую известность, множество обновлений и пользовательских модификаций. Из достоинств игры самыми значительными являются глубокая проработка сюжета, новизна игровых механик, качественное музыкальное сопровождение и постоянные обновления. Является примером многолетней поддержки игрового проекта с очень простым двухмерным графическим исполнением.

King’s Bounty: Legions [8] - первая игра для мобильных платформ из известной серии King’s Bounty. Вышла в 2011 году на Android, iOS и Windows Phone, в 2012 году на iPad и в 2013 году опубликована в Steam [5]. Получила крайне широкую известность благодаря множеству уже существовавших на момент выхода игры фанатов серии, однако подверглась критики в связи с упрощением игрового процесса оригинальной серии и чрезмерным упрощением игры при вложении в неё денежных средств. Последнее является основным пунктом критики условно-бесплатной модели распространения - большинство пользователей считает, что вложение в игру денежных средств не должно затрагивать внутриигровой баланс. Несмотря на известность, получила средние оценки пользователей и осталась единственной игрой в серии на мобильных платформах.

Warhammer 40,000: Deathwatch [4] - игра по известной научно-фантастической вселенной Warhammer 40,000. Вышла в 2015 голу для iOS и ПК. Несмотря на популярность, полученную в первую очередь благодаря фанатам вселенной, игра получила большое количество негативных отзывов - 37% рецензий в Steam [5] негативны. Основными проблемами игры являлась слабая оптимизация, а также множество ошибок, связанных с 3D графикой, большое количество платного контента и отсутствие обновление практически от момента выхода игры.

2.2 Выводы по предметной области

По вышеприведённым примерам можно заключить следующее:

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

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

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

.3 Индивидуальность проекта

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

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

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

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

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

игровой операционный android фреймворк

3. ВЫБОР СРЕДЫ РАЗРАБОТКИ И СТОРОННИХ БИБЛИОТЕК

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

Мною были рассмотрены среды разработки Eclipse [9], IntelliJ IDEA [10] и Android Studio [11]. Все они предоставляют полные возможности по разработке приложений на языке Java последней версии. Android Studio имеет встроенные средства по настройке комплекта средств разработки Android SDK и эмулятор устройств с операционной системой Android. В Eclipse и IntelliJ IDEA настройка Android SDK и эмуляция устройств на ОС Android осуществляется при помощи официальных плагинов. К моменту начала работы с проектом у меня уже был значительный опыт работы в Eclipse и Android Studioи меньший в IntelliJ IDEA.

Из этих трёх сред разработки Android Studio имеет следующие преимущества в контексте разработки для ОС Android:

изначальная ориентированность IDE для работки с ОС Android;

большее относительно других IDE количество обучающих материалов и документации по разработке для мобильных платформ;

простота настройки Android SDK и эмуляторов.

Из недостатков Android Studio можно отметить только высокое потребление системных ресурсов средой разработки.

По вышеуказанным причинам для разработки мною была выбрана среда разработки Android Studio.

.2 Выбор фреймворка

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

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

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

Мною был выбран фреймворк libGDX. Этот движок разрабатывается с 2014 года, в графической части основан на OpenGL и ориентирован на язык Java, поддерживая при этом C и C++. Ключевой особенностью языка является модульная система обеспечения кроссплатформенной разработки: основной код пишется в одном общем модуле, а специальные используются для сборки проекта на разных платформах.

Таким образом с введением минимального количества кода только в специальных модулях можно обеспечить запуск и корректную работу приложения на следующих системах: Windows, Android, Mac OS, iOS, Linux, и браузеры с поддержкой WebGL.

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

Многие разработчики популярнейших проектов на определённом этапе были вынуждены переписывать большую часть проекта на другом фреймворке или даже языке программирования для распространения игры на лишь одну новую платформу. Наиболее часто такими платформами совершаются между Android и iOS.

Так же среди преимуществ libGDX можно отметить следующие качества:

открытая лицензия Apache 2.0;

высокая производительность графики при относительно низкой сложности её разработки. Это особенно заметно в 2D, что идеально подходит для разрабатываемого проекта;

наличие большого объёма документации и обучающих материалов, в том числе русскоязычных.

Стоит также отметить, что libGDX редко используется в действительно крупных игровых проектах. Объясняется это в первую очередь его новизной, а так неполной реализацией некоторых сложных 3D-алгоритмов. Фреймворк больше ориентирован на независимые разработки независимых студий и разработчиков, создание первых проектов и введение в сферу разработки видеоигр.

4 .РЕАЛИЗАЦИЯ ПРИЛОЖЕНИЯ

4.1 Проектирование интерфейса

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

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

 

Рисунок 4.1 - Главное меню

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

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

На клетках располагаются персонажи двух команд (игрока и искусственного интеллекта) визуально различимые по цвету флага рядом с ними.

При выборе кликом определённого юнита на вторую область экрана выводится полная информация о его наименовании, его параметрах жизни, защиты и атаках. Этот экран показан на рисунке 4.2.

Рисунок 4.2 - экран игрового процесса

4.2 Подготовка графических материалов

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

Оптимальным решением в такой ситуации может быть использование художественных материалов, распространяемых по свободной лицензии Creative Commons License [12]. Эта лицензия позволяет использовать и даже адаптировать защищённые ей материалы, в том числе и в коммерческих продуктах. Единственным условием является упоминание автора исходных материалов. Было бы заблуждением считать, что игры с такими материалами не могут получить значительной аудитории. Достаточно часто такие игры можно находить в крупнейших системах цифрового распространения с преобладанием положительных отзывов и не рекордной, но значительной и стабильной аудиторией.

Хорошим примером игры от независимого разработчика, использующей свободные художественные материалы, будет Rogue’s Tale [13]. Игра вышла в 2014 году в системе Steam [5] и к настоящему времени получила множество положительных отзывов от пользователей.

Игра выполнена в простой двухмерной стилистике и принадлежит к не имеющему корректного перевода на русский язык жанру rouge-like, который в последние годы переживает первый со времён псевдографических игр подъём популярности. Пример графического исполнения Rouge’s Tale можно увидеть на рисунке 4.3.

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

Рисунок 4.3 - Rogue’s Tale

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

Примеры свободных материалов представлены на рисунках 4.4 и 4.5.

Рисунок 4.4 - Текстуры для игровых персонажей

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

Рисунок 4.5 - Текстуры для клеток игрового поля

4.3 Написание кода приложения

В связи с особенностями архитектуры фреймворка libGDX полное следование парадигме MVC (Model-View-Control, «Модель-Отображение-Управление») не представляется возможным, так как представление и управление взаимосвязаны, а их функции объявляются в общих интерфейсах и абстрактных классах.

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

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

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

Стоит отметить, что в таких целях часто используют стандартные форматы передачи данных, такие как JSON или XML.

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

На рисунке 4.6 в окне Android Studio показан участок конструктора класса Map.java, который отвечает за разбор одного из двух текстовых файлов и генерации на его основе игрового поля, полностью готового к дальнейшей обработке и отображению.

Рисунок 4.6 - Пример кода внутриигровой логики

Работа модуля отображения управляется объектом класс GameStateManager.java, который управляет стеком объектов класса State.java и его наследников. Последние реализуют состояния приложения, описанные в пункте 4.1.

Наследники класса State.java - MenuState.java и ScenarioState.java, они представляют состояния игрового меню и игрового процесса соответственно. Простая и эффективная реализация класса GameStateManager.java можно увидеть в окне IDE на рисунке 4.7.

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

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

Рисунок 4.7 - Пример кода модуля отображения

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

5. ВЕКТОР РАЗВИТИЯ

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

Но существуют и другие направления для развития. Наиболее удачными на мой взгляд являются следующие:

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

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

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

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

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

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

ЗАКЛЮЧЕНИЕ

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

Развитие проекта по указанным в пятой главе направлениям обеспечит игре стабильное приближению в таких системах, как Google Play [2] и Steam [5], что уже само по себе гарантирует первоначальную аудиторию. Система отзыва в этих средах так же позволит сделать выводы о состоянии проекта и скорректировать направления разработки.

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

СПИСОК ИСПОЛЬЗОВАННЫХ ИСТОЧНИКОВ

1.   SuperData Research [Электронный ресурс]: офиц. сайт. - Режим доступа: https://www.superdataresearch.com/.

2.      Google Play [Электронный ресурс]: офиц. сайт. - Режим доступа: https://play.google.com/store.

.        Приложение Braveland в Google Play [Эл. ресурс]. Реж. доступа: https://play.google.com/store/apps/details?id=com.tortugateam.braveland.v2&hl=ru.

4.      Warhammer 40,000: Deathwatch: Tyranid Invasion [Электронный ресурс]: офиц. сайт. - Режим доступа: http://rodeogames.co.uk/deathwatch.

5.      Steam [Электронный ресурс]: офиц. сайт. - Режим доступа: store.steampowered.com.

.        Приложение Battle for Wesnoth в Google Play [Эл. ресурс]. Режим доступа: https://play.google.com/store/apps/details?id=it.alessandropira.wesnoth112&hl=ru.

.        Стандартная общественная лицензия GNU (GPL) [Электронный ресурс]: офиц. сайт. - Режим доступа: https://www.gnu.org/licenses/gpl-3.0.ru.html.

.        Приложение King’s Bounty: Legions в Google Play [Электронный ресурс]. Режим доступа: https://play.google.com/store/apps/details?id=com.kranx.kbl.

9.      Eclipse [Эл. ресурс]: офиц. сайт. - Режим доступа: https://eclipse.org/.

10.    IntelliJ IDEA [Электронный ресурс]: офиц. сайт. - Режим доступа: https://www.jetbrains.com/idea/.

11.    Android Studio [Электронный ресурс]: офиц. сайт. - Режим доступа: https://developer.android.com/studio/index.html.

12.    Creative Commons License [Электронный ресурс]: офиц. сайт. - Режим доступа: https://creativecommons.org/licenses/by/3.0.

.        Приложение Rogue’s Tale в Steam [Электронный ресурс]. Режим доступа: http://store.steampowered.com/app/265990/Rogues_Tale/?l=russian.

ПРИЛОЖЕНИЕ 1

Коды классов приложения

Game1.java

package com.vlerof.game1;com.badlogic.gdx.ApplicationAdapter;com.badlogic.gdx.Gdx;com.badlogic.gdx.files.FileHandle;com.badlogic.gdx.graphics.Color;com.badlogic.gdx.graphics.GL20;com.badlogic.gdx.graphics.Pixmap;com.badlogic.gdx.graphics.Texture;com.badlogic.gdx.graphics.g2d.SpriteBatch;com.vlerof.game1.Scenario.Field;com.vlerof.game1.Scenario.Level;com.vlerof.game1.Scenario.Map;com.vlerof.game1.Scenario.Scenario;com.vlerof.game1.Scenario.Unit;com.vlerof.game1.States.GameStateManager;com.vlerof.game1.States.MenuState;class Game1 extends ApplicationAdapter {static final int WIDTH = 1080;static final int HEIGHT = 1920;static final int INTERFACE_HEIGHT = 160;static final int FIELD_HEIGHT = HEIGHT - INTERFACE_HEIGHT;static final int ATTACK_BORDER = WIDTH * 3 / 5;static final int SCALE = 32;static final String TITLE = "Game";static final Color COLOR_SIENNA = new Color(0.627f, 0.322f, 0.176f, 1f);static final Color COLOR_SADDLEBROWN = new Color(0.545f, 0.271f, 0.075f, 1f);static final Color COLOR_BLACK = new Color(0.0f, 0.0f, 0.0f, 1f);static Pixmap characterMap1;static Pixmap characterMap2;static Pixmap fieldMap;static Texture flagPlayer;static Texture flagEnemy;static Texture buttonStart;static Texture buttonExit;GameStateManager gsm;SpriteBatch batch;

@Overridevoid create () {= new SpriteBatch();= new GameStateManager();= new Pixmap(new FileHandle("Tiles/dg_classm32.png"));= new Pixmap(new FileHandle("Tiles/dg_uniques32.png"));= new Pixmap(new FileHandle("Tiles/dg_grounds32.png"));= new Texture(new FileHandle("flag1.png"));= new Texture(new FileHandle("flag2.png"));= new Texture(new FileHandle("start.png"));= new Texture(new FileHandle("exit.png"));.initLevels();.initTiles();.gl.glClearColor(0, 0, 0, 1);.push(new MenuState(gsm));

}

@Overridevoid render () {.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);.update(Gdx.graphics.getDeltaTime());.render(batch);

}

@Overridevoid dispose () {.dispose();.dispose();.dispose();.dispose();.dispose();.dispose();.dispose();.dispose();

}static Scenario getDefaultScenario() {sc = new Scenario();.setMap(new Map("Maps/map1.txt"));.setSpawns("Maps/respawn1.txt");unit;

//TODO : moves, attacks, hp, defs= new Unit("John", 15, new Tile(characterMap1, 3, 0));.addEnemyUnit(unit);= new Unit("Karl", 15, new Tile(characterMap1, 3, 1));.addEnemyUnit(unit);= new Unit("Guss", 15, new Tile(characterMap1, 3, 2));.addEnemyUnit(unit);= new Unit("Bob", 15, new Tile(characterMap1, 3, 3));.addEnemyUnit(unit);= new Unit("Ivan", 15, new Tile(characterMap1, 3, 4));.addEnemyUnit(unit);= new Unit("Jack", 15, new Tile(characterMap1, 3, 5));.addEnemyUnit(unit);= new Unit("Tzeentch", 15, new Tile(characterMap1, 4, 6));.addPlayerUnit(unit);= new Unit("Nurgle", 15, new Tile(characterMap2, 9, 5));.addPlayerUnit(unit);= new Unit("Malal", 15, new Tile(characterMap2, 5, 2));.addPlayerUnit(unit);= new Unit("Slaanesh", 15, new Tile(characterMap2, 4, 0));.addPlayerUnit(unit);= new Unit("Khorn", 15, new Tile(characterMap2, 6, 0));.addPlayerUnit(unit);sc;

}static String formatString(String s) {int length = s.length();char[] chars = s.toCharArray();(int i = 0; i < length; i++) {(chars[i] == '\r' || chars[i] == '\n') {[i] = ' ';

}

}str = new String(chars);str.replaceAll(" ", " ");

}

}

Tile.java

package com.vlerof.game1;com.badlogic.gdx.graphics.Pixmap;com.badlogic.gdx.graphics.Texture;class Tile {

public Pixmap pixmap;

public int xOffset;

public int yOffset;

public Tile(Pixmap _source, int _xOffset, int _yOffset) {

pixmap = _source;

xOffset = _xOffset;

yOffset = _yOffset;

}

public Texture getTexture() {

Pixmap pxmp = new Pixmap(Game1.SCALE, Game1.SCALE, Pixmap.Format.RGBA8888);

pxmp.drawPixmap(pixmap, 0, 0, xOffset * Game1.SCALE, yOffset * Game1.SCALE, Game1.SCALE, Game1.SCALE);

return new Texture(pxmp);

}

public Pixmap getPixmap() {

Pixmap pxmp = new Pixmap(Game1.SCALE, Game1.SCALE, Pixmap.Format.RGBA8888);

pxmp.drawPixmap(pixmap, 0, 0, xOffset * Game1.SCALE, yOffset * Game1.SCALE, Game1.SCALE, Game1.SCALE);

return pxmp;

}

}

Map.java

package com.vlerof.game1.Scenario;com.badlogic.gdx.Gdx;com.badlogic.gdx.files.FileHandle;com.badlogic.gdx.graphics.Pixmap;com.badlogic.gdx.graphics.Texture;com.vlerof.game1.Game1;java.awt.Point;java.io.BufferedReader;java.io.File;java.io.FileInputStream;java.io.IOException;java.io.InputStreamReader;class Map {

public final int WIDTH;

public final int HEIGHT;

private Field map[][];

public Map(String _filename) {

FileHandle file = Gdx.files.internal(_filename);

String str = Game1.formatString(file.readString());

int spacePos = str.indexOf(" ");

WIDTH = Integer.parseInt(str.substring(0, spacePos));

str = str.substring(spacePos + 1);

spacePos = str.indexOf(" ");

HEIGHT = Integer.parseInt(str.substring(0, spacePos));

str = str.substring(spacePos + 1);

map = new Field[WIDTH][HEIGHT];

String fieldCode;

for (int y = 0; y < HEIGHT; y++) {

for (int x = 0; x < WIDTH - 1; x++) {

spacePos = str.indexOf(" ");

fieldCode = str.substring(0, spacePos);

str = str.substring(spacePos + 1);

map[x][y] = parseField(fieldCode);

}

if (y == HEIGHT - 1) {

fieldCode = str.substring(0);

} else {

spacePos = str.indexOf(" ");

fieldCode = str.substring(0, spacePos);

str = str.substring(spacePos + 1);

}

map[WIDTH - 1][y] = parseField(fieldCode);

}

}

public Field getField(int _x, int _y) {

return map[_x][_y];

}

public Field getField(Point _point) {

return map[_point.x][_point.y];

}

private Field parseField(String _code) throws StringIndexOutOfBoundsException {

FieldType type;

char typeStr = _code.charAt(0);

switch(typeStr) {

case 'p' : {

type = FieldType.PLAIN;

break;

}

case 'f' : {

type = FieldType.FOREST;

break;

}

case 'm' : {

type = FieldType.MOUNTAIN;

break;

}

case 'w' : {

type = FieldType.WATER;

break;

}

case 'b' : {

type = FieldType.BLOCKED;

break;

}

case 's' : {

type = FieldType.SNOW;

break;

}

default : {

type = FieldType.BLOCKED;

}

}

int number = Integer.parseInt(_code.substring(1));

return new Field(type, number);

}

public Pixmap getPixmap() {

Pixmap pxmp = new Pixmap(Game1.SCALE * WIDTH, Game1.SCALE * HEIGHT, Pixmap.Format.RGBA8888);

for(int y = 0; y < HEIGHT; y++) {

for(int x = 0; x < WIDTH; x++) {

pxmp.drawPixmap(map[x][y].getTile().getPixmap(), x * Game1.SCALE, y * Game1.SCALE, 0, 0, Game1.SCALE, Game1.SCALE);

}

}

pxmp.setColor(0.3f, 0.3f, 0.3f, 0.5f);

for(int x = 1; x < WIDTH; x++) {

pxmp.drawRectangle(x * Game1.SCALE, 0, 2, HEIGHT * Game1.SCALE);

}

for(int y = 1; y < HEIGHT; y++) {

pxmp.drawRectangle(0, y * Game1.SCALE, WIDTH * Game1.SCALE, 2);

}

return pxmp;

}

}

Scenario.java

package com.vlerof.game1.Scenario;com.badlogic.gdx.Gdx;com.badlogic.gdx.files.FileHandle;com.badlogic.gdx.graphics.Pixmap;com.badlogic.gdx.graphics.g2d.SpriteBatch;com.vlerof.game1.Game1;java.awt.Point;java.util.ArrayList;class Scenario {

public Map map;

public ArrayList<Point> playerSpawn;

public ArrayList<Point> enemySpawn;

public ArrayList<Unit> playerTeam;

public ArrayList<Unit> enemyTeam;

public Scenario() {

playerSpawn = new ArrayList<Point>();

enemySpawn = new ArrayList<Point>();

playerTeam = new ArrayList<Unit>();

enemyTeam = new ArrayList<Unit>();

}

public Scenario(String _fileMap, String _fileSpawn, String _filePlayer, String _fileEnemy) {

//TODO : scenario init

}

public void setMap(String _filename) {

map = new Map(_filename);

}

public void setMap(Map _map) {

map = _map;

}

public void setSpawns(String _filename) {

playerSpawn = new ArrayList<Point>();

enemySpawn = new ArrayList<Point>();

parseSpawns(_filename);

}

public void addPlayerSpawn(Point _point) {

playerSpawn.add(_point);

}

public void addEnemySpawn(Point _point) {

enemySpawn.add(_point);

}

public void setPlayerTeam(String _filename) {

playerTeam = new ArrayList<Unit>();

parsePlayerTeam(_filename);

}

public void setEnemyTeam(String _filename) {

enemyTeam = new ArrayList<Unit>();

parseEnemyTeam(_filename);

}

public void addPlayerUnit(Unit _unit) {

playerTeam.add(_unit);

_unit.setFlag(Game1.flagPlayer);

}

public void addEnemyUnit(Unit _unit) {

enemyTeam.add(_unit);

_unit.setFlag(Game1.flagEnemy);

}

private void parseSpawns(String _filename) {

FileHandle file = Gdx.files.internal(_filename);

String str = Game1.formatString(file.readString());

int spacePos;

for(int y = 0; y < map.HEIGHT; y++) {

for (int x = 0; x < map.WIDTH - 1; x++) {

spacePos = str.indexOf(" ");

parseSpawnCode(Integer.parseInt(str.substring(0, spacePos)), x, y);

str = str.substring(spacePos + 1);

}

if (y == map.HEIGHT - 1) {

parseSpawnCode(Integer.parseInt(str.substring(0)), map.WIDTH - 1, y);

} else {

spacePos = str.indexOf(" ");

parseSpawnCode(Integer.parseInt(str.substring(0, spacePos)), map.WIDTH - 1, y);

str = str.substring(spacePos + 1);

}

}

}

private void parsePlayerTeam(String _filename) {

}

private void parseEnemyTeam(String _filename) {

//TODO : parse

}

private void parseSpawnCode(int _code, int _x, int _y) {

switch(_code) {

case 1: {

addPlayerSpawn(new Point(_x, _y));

break;

}

case 2: {

addEnemySpawn(new Point(_x, _y));

break;

}

}

}

public void placeUnits() {

Point p;

for(Unit unit : playerTeam) {

if(!playerSpawn.isEmpty()) {

p = playerSpawn.remove(0);

map.getField(p).setUnit(unit);

unit.setLocate(p);

}

}

for(Unit unit : enemyTeam) {

if(!enemySpawn.isEmpty()) {

p = enemySpawn.remove(0);

map.getField(p).setUnit(unit);

unit.setLocate(p);

}

}

}

public void drawUnits(Pixmap _pxmp) {

for(Unit unit : playerTeam) {

_pxmp.drawPixmap(unit.getPixmap(), unit.getLocate().x * Game1.SCALE, unit.getLocate().y * Game1.SCALE, 0, 0, Game1.SCALE, Game1.SCALE);

}

for(Unit unit : enemyTeam) {

_pxmp.drawPixmap(unit.getPixmap(), unit.getLocate().x * Game1.SCALE, unit.getLocate().y * Game1.SCALE, 0, 0, Game1.SCALE, Game1.SCALE);

}

}

public void drawUnits(SpriteBatch _sb) {

for(Unit unit : playerTeam) {

unit.setSpritePosition(Gdx.graphics.getWidth() * unit.getLocate().x / map.WIDTH,

((Gdx.graphics.getHeight() - Game1.INTERFACE_HEIGHT) * unit.getLocate().y / map.HEIGHT) + Game1.INTERFACE_HEIGHT);

unit.getSprite().draw(_sb);

unit.getFlag().draw(_sb);

}

for(Unit unit : enemyTeam) {

unit.setSpritePosition(Gdx.graphics.getWidth() * unit.getLocate().x / map.WIDTH,

((Gdx.graphics.getHeight() - Game1.INTERFACE_HEIGHT) * unit.getLocate().y / map.HEIGHT) + Game1.INTERFACE_HEIGHT);

unit.getSprite().draw(_sb);

unit.getFlag().draw(_sb);

}

}

}

Unit.java

package com.vlerof.game1.Scenario;com.badlogic.gdx.graphics.Pixmap;com.badlogic.gdx.graphics.Texture;com.badlogic.gdx.graphics.g2d.Sprite;com.vlerof.game1.Tile;java.awt.Point;java.util.ArrayList;class Unit {

private Texture texture;

private Sprite sprite;

private Sprite flag;

private Pixmap pixmap;

private String name;

private Point locate;

private Level level;

private ArrayList<Point> moves;

private ArrayList<FieldType> moveTypes;

private ArrayList<Attack> attacks;

private boolean alive;

private int healthCurrent;

private int healthMax;

private int healthPerLvl;

private int defenseMelee;

private int defenseRange;

private int defenseFire;

public Unit(String _name, int _maxLevel, Tile _tile) {

name = _name;

level = new Level(0, _maxLevel);

attacks = new ArrayList<Attack>();

texture = _tile.getTexture();

sprite = new Sprite(texture);

pixmap = _tile.getPixmap();

}

public Unit setLocate(Point _locate) {

locate = _locate;

return this;

}

public Point getLocate() {

return locate;

}

public void setSpritePosition(float _x, float _y) {

sprite.setPosition(_x, _y);

flag.setPosition(_x + 32, _y);

}

public void addExp(int _amount) {

int lvlUps = level.addExp(_amount);

if(lvlUps > 0) {

healthMax += lvlUps * healthPerLvl;

healthCurrent = healthMax;

}

}

public int getLevel() {

return level.getLevel();

}

public void setHealth(int _hpMax, int _hpPerLvl){

healthCurrent = healthMax = _hpMax;

healthPerLvl = _hpPerLvl;

alive = true;

}

public void setDefenses(int _defMelee, int _defRange, int _defFire) {

defenseMelee = _defMelee;

defenseRange = _defRange;

defenseFire = _defFire;

}

public void addMove(Point _point) {

moves.add(_point);

}

public void addMoveType(FieldType _type) {

moveTypes.add(_type);

}

public void addAttack(Attack _attack) {

attacks.add(_attack);

}

public ArrayList<Point> getMoves(){

return moves;

}

public ArrayList<FieldType> getMoveTypes(){

return moveTypes;

}

public ArrayList<Attack> getAttacks(){

return attacks;

}

public Texture getTexture() {

return texture;

}

public Sprite getSprite() {

return sprite;

}

public Pixmap getPixmap() {

return pixmap;

}

public void setFlag(Texture _texture) {

flag = new Sprite(_texture);

}

public Sprite getFlag() {

return flag;

}

public boolean isAlive() {

return alive;

}

}

Level.java

package com.vlerof.game1.Scenario;java.util.ArrayList;class Level {

private int level;

private final int max;

private int experience;

private static final ArrayList<Integer> sumToUp = new ArrayList<Integer>();

public Level(int _experience, int _max) {

if(_experience > 0 && _experience < 1000000) {

experience = _experience;

} else {

experience = 0;

}

if(_max > 0 && _max < 100) {

max = _max;

} else {

max = 10;

}

}

public int getLevel() {

return level;

}

public int addExp(int _amount) {

int levelUps = 0;

experience += _amount;

int sumToNext = sumToUp.get(level);

while(experience > sumToNext && level < max) {

experience -= sumToNext;

level++;

levelUps++;

sumToNext = sumToUp.get(level);

}

return levelUps;

}

public static void initLevels() {

sumToUp.add(15);

for(int i = 1; i < 100; i++) {

sumToUp.add((i + 3) * 5 + sumToUp.get(i - 1));

}

}

}

FieldType.java

package com.vlerof.game1.Scenario;enum FieldType {

PLAIN,

FOREST,

MOUNTAIN,

WATER,

BLOCKED,

SNOW

}

Field.java

package com.vlerof.game1.Scenario;com.vlerof.game1.Game1;com.vlerof.game1.Tile;java.util.ArrayList;java.util.HashMap;class Field {

private static HashMap<FieldType, ArrayList<Tile>> tilesMap = new HashMap<FieldType, ArrayList<Tile>>();

private FieldType fieldType;

private Unit unit;

private int tileNumber;

public Field(FieldType _type, int _tileNumber) {

fieldType = _type;

unit = null;

if(_tileNumber < tilesMap.get(_type).size()) {

tileNumber = _tileNumber;

} else {

tileNumber = 0;

}

}

public Tile getTile() {

return tilesMap.get(fieldType).get(tileNumber);

}

public FieldType getType() {

return fieldType;

}

private Unit getUnit(){

return unit;

}

public void setUnit(Unit _unit) {

unit = _unit;

}

public int getTilesCount() {

return tilesMap.get(fieldType).size();

}

public static int getTypeTilesCount(FieldType _type) {

return tilesMap.get(_type).size();

}

public static void initTiles() {

tilesMap.put(FieldType.PLAIN, new ArrayList<Tile>());

tilesMap.put(FieldType.FOREST, new ArrayList<Tile>());

tilesMap.put(FieldType.MOUNTAIN, new ArrayList<Tile>());

tilesMap.put(FieldType.WATER, new ArrayList<Tile>());

tilesMap.put(FieldType.BLOCKED, new ArrayList<Tile>());

tilesMap.put(FieldType.SNOW, new ArrayList<Tile>());

//Plains

ArrayList<Tile> tileList = tilesMap.get(FieldType.PLAIN);

for(int i = 0; i < 15; i++) {

tileList.add(new Tile(Game1.fieldMap, i % 9, i / 9));

}

for(int i = 0; i < 6; i++) {

tileList.add(new Tile(Game1.fieldMap, i, 3));

}

for(int i = 0; i < 3; i++) {

tileList.add(new Tile(Game1.fieldMap, i + 3, 4));

}

///////////////////////////////////////////////////////

//Forests

tileList = tilesMap.get(FieldType.FOREST);

for(int i = 0; i < 9; i++) {

tileList.add(new Tile(Game1.fieldMap, i, 6));

}

for(int i = 0; i < 3; i++) {

tileList.add(new Tile(Game1.fieldMap, i + 6, 7));

}

///////////////////////////////////////////////////////

//Mountains

tileList = tilesMap.get(FieldType.MOUNTAIN);

for(int i = 0; i < 3; i++) {

tileList.add(new Tile(Game1.fieldMap, i, 9));

}

for(int i = 0; i < 3; i++) {

tileList.add(new Tile(Game1.fieldMap, i + 6, 9));

}

for(int i = 0; i < 9; i++) {

tileList.add(new Tile(Game1.fieldMap, i, 13));

}

//Water

tileList = tilesMap.get(FieldType.WATER);

for(int i = 0; i < 3; i++) {

tileList.add(new Tile(Game1.fieldMap, i + 6, 1));

}

for(int i = 0; i < 3; i++) {

tileList.add(new Tile(Game1.fieldMap, i, 2));

}

//Blocked

tileList = tilesMap.get(FieldType.BLOCKED);

for(int i = 0; i < 3; i++) {

tileList.add(new Tile(Game1.fieldMap, i, 3));

}

for(int i = 0; i < 3; i++) {

tileList.add(new Tile(Game1.fieldMap, i + 6, 4));

}

for(int i = 0; i < 3; i++) {

tileList.add(new Tile(Game1.fieldMap, i + 6, 8));

}

///////////////////////////////////////////////////////

//Snow

tileList = tilesMap.get(FieldType.SNOW);

for(int i = 0; i < 3; i++) {

tileList.add(new Tile(Game1.fieldMap, i + 3, 9));

}

for(int i = 0; i < 3; i++) {

tileList.add(new Tile(Game1.fieldMap, i + 6, 10));

}

for(int i = 0; i < 3; i++) {

tileList.add(new Tile(Game1.fieldMap, i + 6, 11));

}

///////////////////////////////////////////////////////

}

}

GameStateManager.java

package com.vlerof.game1.States;com.badlogic.gdx.graphics.g2d.SpriteBatch;java.util.Stack;class GameStateManager {

private Stack<State> states;

public GameStateManager() {

states = new Stack<State>();

}

public void push(State _state) {

states.push(_state);

}

public void pop() {

states.pop().dispose();

}

public void set(State _state) {

states.pop().dispose();

states.push(_state);

}

public void update(float _dt) {

states.peek().update(_dt);

}

public void render(SpriteBatch _sb) {

states.peek().render(_sb);

}

}

State.java

package com.vlerof.game1.States;com.badlogic.gdx.graphics.OrthographicCamera;com.badlogic.gdx.graphics.g2d.SpriteBatch;com.badlogic.gdx.math.Vector3;abstract class State {

protected OrthographicCamera camera;

protected Vector3 mouse;

protected GameStateManager gsm;

public State(GameStateManager _gsm) {

gsm = _gsm;

camera = new OrthographicCamera();

mouse = new Vector3();

}

protected abstract void handleInput();

public abstract void update(float dt);

public abstract void render(SpriteBatch sb);

public abstract void dispose();

}

MenuState.java

package com.vlerof.game1.States;com.badlogic.gdx.Gdx;com.badlogic.gdx.graphics.Texture;com.badlogic.gdx.graphics.g2d.SpriteBatch;com.vlerof.game1.Game1;class MenuState extends State {

private Texture background;

public MenuState(GameStateManager _gsm) {

super(_gsm);

background = new Texture("Map.jpg");

@Override

protected void handleInput() {

if(Gdx.input.justTouched()) {

int x = Gdx.input.getX();

int y = Gdx.input.getY();

if(x > Gdx.graphics.getWidth() / 2 - Game1.buttonStart.getWidth() / 2 &&

x < Gdx.graphics.getWidth() / 2 + Game1.buttonStart.getWidth() / 2 &&

y < Gdx.graphics.getHeight() / 3 &&

y > Gdx.graphics.getHeight() / 3 - Game1.buttonStart.getHeight()) {

gsm.set(new ScenarioState(gsm, Game1.getDefaultScenario()));

} else if (x > Gdx.graphics.getWidth() / 2 - Game1.buttonExit.getWidth() / 2 &&

x < Gdx.graphics.getWidth() / 2 + Game1.buttonExit.getWidth() / 2 &&

y < Gdx.graphics.getHeight() * 2 / 3 &&

y > Gdx.graphics.getHeight() * 2 / 3 - Game1.buttonExit.getHeight()) {

Gdx.app.exit();

}

}

}

@Override

public void update(float dt) {

handleInput();

}

@Override

public void render(SpriteBatch sb) {

sb.begin();

sb.draw(background, 0, 0, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());

sb.draw(Game1.buttonStart, Gdx.graphics.getWidth() / 2 - Game1.buttonStart.getWidth() / 2,

Gdx.graphics.getHeight() * 2 / 3);

sb.draw(Game1.buttonExit, Gdx.graphics.getWidth() / 2 - Game1.buttonExit.getWidth() / 2,

Gdx.graphics.getHeight() / 3);

//TODO : Buttons

sb.end();

}

@Override

public void dispose() {

background.dispose();

}

}

ScenarioState.java

package com.vlerof.game1.States;com.badlogic.gdx.Gdx;com.badlogic.gdx.graphics.GL20;com.badlogic.gdx.graphics.Pixmap;com.badlogic.gdx.graphics.Texture;com.badlogic.gdx.graphics.g2d.SpriteBatch;com.vlerof.game1.Game1;com.vlerof.game1.Scenario.Scenario;class ScenarioState extends State {

private Scenario scenario;

private Pixmap mapPixmap;

private Texture mapTexture;

private Texture interfaceTexture;

public ScenarioState(GameStateManager gsm, Scenario _scenario) {

super(gsm);

scenario = _scenario;

scenario.placeUnits();

mapPixmap = _scenario.map.getPixmap();

mapTexture = new Texture(mapPixmap);

Pixmap pxmp = new Pixmap(Game1.WIDTH, Game1.INTERFACE_HEIGHT, Pixmap.Format.RGBA8888);

pxmp.setColor(Game1.COLOR_SIENNA);

pxmp.fillRectangle(0, 0, Game1.WIDTH, Game1.INTERFACE_HEIGHT);

pxmp.setColor(Game1.COLOR_SADDLEBROWN);

pxmp.fillRectangle(Game1.ATTACK_BORDER, 0, 2, Game1.INTERFACE_HEIGHT);

pxmp.setColor(Game1.COLOR_SADDLEBROWN);

pxmp.fillRectangle(0, 0, Game1.WIDTH, 5);

interfaceTexture = new Texture(pxmp);

}

@Override

protected void handleInput() {

}

@Override

public void update(float dt) {

}

@Override

public void render(SpriteBatch sb) {

Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

sb.begin();

sb.draw(mapTexture, 0, Game1.INTERFACE_HEIGHT, Gdx.graphics.getWidth(), Gdx.graphics.getHeight() - Game1.INTERFACE_HEIGHT);

sb.draw(interfaceTexture, 0, 0, Game1.WIDTH, Game1.INTERFACE_HEIGHT);

scenario.drawUnits(sb);

sb.end();

}

@Override

public void dispose() {

mapPixmap.dispose();

interfaceTexture.dispose();

}

}

Похожие работы на - Разработка игрового приложения для операционной системы Android

 

Не нашли материал для своей работы?
Поможем написать уникальную работу
Без плагиата!