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

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

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

Методы создания

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

Для рядовых или начинающих разработчиков существует три типа инструментов для создания игры на Андроиде:

  1. Онлайн сервисы позволяют заниматься разработкой прямо в браузере. Предлагают пользователям готовые и рабочие шаблоны для работы с разнообразными игровыми жанрами. Требуют минимального количества навыков в программировании.
  2. Программы обладают более подробным функционалам. Аналогично с онлайн сервисами предлагают набор готовых шаблонов и скриптов. Требуют определенных знаний в программировании, поскольку понадобится писать код для каждого действия.
  3. Среда разработки – сложный инструмент, требующий навыков в программировании. Здесь необходимо знать конкурентный язык программирования, на котором будет писаться игра. Без специальных курсов и знаний написать игры, например, на языке Java невозможно. Для самоучек придуманы специализированные форумы. Наиболее популярный – GeekBrains .

Идея и сценарий

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

Чтобы сделать игру на Андроид необходимо, чтобы игровой процесс отвечал на вопросы:

  1. Стороны конфликта : пример Angry Birds – птицы и свиньи.
  2. Как решается этот конфликт – птицы летят в свиней на рогатке.
  3. Где разворачиваются основные события ?

Пример сценария для ранера на Android: главный герой – белка, которая готовится к зимней спячке. Ее задача , насобирать, как можно больше припасов на зиму. В качестве преград выступают деревья и другие лесные жители. Разумеется, чем сложнее игра, тем больше вопросов задается для ее создания. Но вопросы «зачем», «почему» и «как» применяются для любого проекта.

Объектная модель и спецификации

Увлекательный геймплей и яркая графика – это не единственные факторы успешного приложения. Немаловажными являются такие пункты, как объектная модель и спецификации. Представленные параметры выполняют две важнейшие функции:

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

Пример объектной модели игровой сущности:

  • Основной раздел – предметы:
    • Специальная классификация – оружие:
      • Вид № 1 – меч ;
      • Вид № 2 – лук .

Контент и интерфейс

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

  1. Использовать интуитивно понятные значки (меню настроек – шестеренки).
  2. Применять минималистские объекты , которые не будут отвлекать от игры.
  3. Структурировать информацию.

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

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

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

Выбор движка

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

Каждый движок способен выполнять те или иные задачи и применяется для различных жанров. Рассмотрим на примерах различных движков:


Исключением из правил являются фирменные движки разработчиков. Например, компания Rockstar (создатели серии GTA Red Dead Redemption) используют собственный движок, находящийся в закрытом доступе.

Процесс создания игры

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

В качестве конструктора используем Game Maker – это один из лучших инструментов для новичков. В первом примере рассмотрим разработку простой аркады:

  1. Создаем основной фон – локацию, где будут протекать основные события.
  2. Делаем главного персонажа : рисуем самостоятельно или загружаем готовый шаблон.
  3. Проектируем предметы для взаимодействия: монетки, ловушки, враги и т.п.
  4. Программируем событие , которое случится при взаимодействии с предметом: наступил на ловушку – игра окончена, подобрал монетку – путь продолжается.

Для того чтобы показать различие между игровыми жанрами рассмотрим более сложный пример. Теперь используем конструктор Unity 3D, а игровой жанр меняем на ККИ:

  1. Первый пункт остается неизменным – создание фона для будущего проекта.
  2. Место главного персонажа занимают карты , их намного больше, поэтому работа более время затратная.
  3. Проектируем логические взаимодействия между картами (самый сложный этап).
  4. Определяем количество игроков .
  5. Конвертируем игровое меню из трехмерного измерения в двухмерное пространство.
  6. Определяем условия , при которых матч будет считаться завершенным.

Лучшие конструкторы

Construct 2 и 3

– инструмент, позволяющий делать видеоигры на телефоны без знаний программирования. С его помощью можно создать видеоигру не написав не единой строчки кода. Если думаете, что работать с таким инструментом проигрышный вариант, то посмотрите на приложение Floppy Bird , которое написано на Construct 2.

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

Construct 3 – улучшенный движок, который планомерно вытесняет Construct 2. Расширение привычных опций и предоставление новых функции – преимущества обновленной версии. Однако в этой ревизии отсутствует бесплатная подписка . Зато имеется обратная совместимость с предыдущей версией утилиты.

– распространяется в трех вариантах: «бесплатная версия», «обычная вариация», и «профессиональная ревизия». Разумеется, что чем разнообразнее функционал версии, тем выше ее цена.

Clickteam Fusion – это мультиплатформенный движок, позволяющий создавать игры для различных платформ, а также заниматься их портированием. Основная специализация – 2D. Однако существует возможность писать и в 3D. Именно на этом движке был написан Five nights at Freddy’s (Пять ночей с Фредди).

Движок – это еще один представитель конструкторов, предъявляющие минимальные требования к знаниям программирования. Презентованный движок – мультиплатформенный инструмент, позволяющий писать игры, как на мобильные, так и на старшие платформы. Обладает интерфейсом Drag & Drop.

Интерфейс приложения – его главная фишка, поскольку меню управления имитирует панель Photoshop , что оказывается довольно удобным для геймдизайнинга. На этом движке пишутся приложения таких студий как: ArmorGames, Kongregate, Newground и прочих более мелких кампаний.

GameMaker – движок, специализирующийся на создании двухмерных проектов, которые являются популярными на мобильных платформах. Движок ориентирован на начинающих разработчиков , обладающих базовым набором знаний. Посредством GameMaker разрабатывался Hotline Miami и прочие 2D шедевры. Из очевидных плюсов движка выделяют:


Unity – наиболее популярный движок среди разработчиков. Представленный движок – самая гибкая система в сегодняшнем списке. Здесь удобно работать с 2D и 3D проектами. На этой платформе разрабатывались видеоигры для различных систем:

  • PS 3 – Cuphead, Escape from Tarkov, Life Is Strange: Before the Storm.
  • Android и IOs – Angry Birds 2, Hitman Go, Heartstone.
  • PC – Pillars of Eternity, Ori and the Blind Forest.

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

Теперь наглядно сравним вышеперечисленные конструкторы.

Конструктор Цена Преимущества
Construct 2 и 3 Бесплатная/199 $ Мультиплатформа, оперативность обработки данных, простой внутренний язык.
Clickteam Fusio 148 $ Создание прототипов, минимальные требования к программированию, создание полноценного коммерческого продукта.
Бесплатно/99 $/199 $ Интерфейс Drag & Drop, ориентированность на 2D игры, имитация панели управления Photoshop.
Game Make Бесплатно Мультиплатформа, регулярные обновления, активное пользовательское сообщество, простая панель управления.
Бесплатная Мультиплатформа, вариативность игровых настроек, готовые шаблоны для создания игр, популярность среди разработчиков, открытая система

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

  • наличие мультиплеера ;
  • собственные познания в программировании ;
  • сложность проекта: двухмерная или трехмерная игры;
  • степень совместимости с другими игровыми платформами;
  • финансовые возможности (стоимость платных инструментов).

Онлайн сервис AppsGeyser

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

Разберем создание игры в качестве примера:


Обратите внимание, что загружать и сохранять проекты можно только после прохождения регистрации в AppsGeyser. Пройдя регистрацию, разработчики смогут публиковать результаты работ в Google Play Market. Однако эта процедура будет стоить 25 долларов за публикацию.

Лучшие приложения

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

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


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

Apper

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

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


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

Пример создания игры

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

Геймплей

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

Начало разработки

«Гоночный тетрис» состоит из двух простых сцен: главное меню и окно геймплея . Первым делом займемся меню. Для него необходимо использовать элемент управления GUI – стандартный инструмент платформы.

Для фона используем спрайт под названием «background ». В примере применяется серый цвет. При желании цветовая палитра изменяется.

Второй шаг – создание скрипта «menu.cs ». Путь команды: Правой кнопкой мыши на строке скрипта – «Create» – «C# Script ». Не забудьте повесить его на «background». Содержимое скрипта выглядит следующим образом:

Using UnityEngine; using System.Collections; using System.Collections.Generic; using System.Runtime.Serialization.Formatters.Binary; using System.IO; public class menu: MonoBehaviour { public GUIStyle mystyle; //объявляется для того чтобы изменять начертание GUI компонентов(шрифт, размер и.т.п.) string score; //переменная для хранения пройденной дистанции void Start () { StreamReader scoredata = new StreamReader (Application.persistentDataPath + "/score.gd"); //создание файловой переменной score = scoredata.ReadLine (); //чтение строки scoredata.Close (); //закрытие файловой переменной } void Update () { } void OnGUI(){ GUI.Box (new Rect (Screen.width*0.15f, Screen.height*0.8f, Screen.width*0.7f, Screen.height*0.1f), "MAX DISTANCE:"+score,mystyle); //создаем небольшое окошко для показа пройденного расстояния if (GUI.Button (new Rect (Screen.width*0.15f, Screen.height*0.25f, Screen.width*0.7f, Screen.height*0.1f), "Start game",mystyle)) //создаем кнопку для запуска игровой сцены { Application.LoadLevel(1);//Загрузка игровой сцены } if (GUI.Button (new Rect (Screen.width*0.15f, Screen.height*0.4f, Screen.width*0.7f, Screen.height*0.1f), "Exit",mystyle)) //создаем кнопку для выхода из игры { Application.Quit();//Выход из игры } } }

В конечном итоге на экране должно получить примерное такое окно:

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

Игровое окно

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

В их число входят:

  • автомобиль;
  • бензобак;
  • дорога.

Рассмотрим создание каждого элемента в отдельности.

Дорога

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

Приступим:

  1. Загружаем на сцену с гейплеем, подгоняя ее по размерам камеры.
  2. Далее добавляем в качестве дочерних объекта внутри дороги четыре блока с преградами и иконку бензобака.
  3. Не забудьте прибавить к ним Box Collider 2D. Дополнительно требуется отметить иконку Is Triger , чтобы объекты пересекались с машиной.
  4. Создайте скрипт под названием «moveroad.cs » и повесьте его на трассу. Далее прописываем код: using UnityEngine; using System.Collections; using System.Collections.Generic; using System.Runtime.Serialization.Formatters.Binary; using System.IO; public class moveroad: MonoBehaviour { public GUIStyle mystyle;//создание стиля int f,fuelst; float score=0,speed=-0.2f,data,fuelpos;// переменные для хранения расстояния, скорости и рекорда public GameObject block;// игровой объект для размещения блока public GameObject block1; public GameObject block2; public GameObject block3; public GameObject fuel; bool turbotriger=false; void Start () { StreamReader scoredata = new StreamReader (Application.persistentDataPath + "/score.gd"); data = float.Parse(scoredata.ReadLine ());//чтение с файла информации о рекорде scoredata.Close (); } void Update () { transform.Translate (new Vector3 (0f,speed,0f));//движение дороги с заданной выше скоростью score = score + (speed*-10);// подсчет расстояния if (transform.position.y < -19f) // если дорога уходит за пределы камеры то она "теле портируется" вверх { transform.position=new Vector3(0f,33.4f,0f);//новая позиция дороги block.transform.position=new Vector3(10.15f,block.transform.position.y,block.transform.position.z); block1.transform.position=new Vector3(8.42f,block1.transform.position.y,block1.transform.position.z); block2.transform.position=new Vector3(6.62f,block2.transform.position.y,block2.transform.position.z); block3.transform.position=new Vector3(4.95f,block3.transform.position.y,block3.transform.position.z); fuel.transform.position=new Vector3(11.86f,fuel.transform.position.y,fuel.transform.position.z); //скрытие за пределы камеры всех препятствий(блоков) f = Random.Range (0, 5);//случайное появление на дороге 1-го из 4-х блоков или канистры с бензином switch (f) { case 0:block.transform.position=new Vector3(2.40f,block.transform.position.y,block.transform.position.z); break; case 1:block1.transform.position=new Vector3(0.90f,block1.transform.position.y,block1.transform.position.z); break; case 2:block2.transform.position=new Vector3(-0.80f,block2.transform.position.y,block2.transform.position.z); break; case 3:block3.transform.position=new Vector3(-2.35f,block3.transform.position.y,block3.transform.position.z); break; case 4: fuelst=Random.Range(0,4); if(fuelst==0){fuelpos=2.40f;} if(fuelst==1){fuelpos=0.90f;} if(fuelst==2){fuelpos=-0.80f;} if(fuelst==3){fuelpos=-2.35f;} fuel.transform.position=new Vector3(fuelpos,fuel.transform.position.y,fuel.transform.position.z); break; } if (score>data)// если текущее пройденное расстояние превышает то что записано в файле рекорда то идет обновление данных { StreamWriter scoredata=new StreamWriter(Application.persistentDataPath + "/score.gd");//создаем файловую переменную для хранения пройденного расстояния scoredata.WriteLine(score);//записываем новое значение в файл scoredata.Close();//закрываем файловую переменную } } } void OnGUI(){ GUI.Box (new Rect (0, 0, Screen.width, Screen.height*0.05f), "Distance(m): " + score,mystyle);//создаем окно для подсчета расстояния } }

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

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

Автомобиль

Киньте спрайт машины на сцену.

Установите авто в любое место на трассе. Создайте скрипт carcontroller.cs и повести его на машину. Ниже находится содержимое скрипта:

Using UnityEngine; using System.Collections; using UnityStandardAssets.CrossPlatformInput; public class carconroller: MonoBehaviour { void Start () { } public void Update () { if (transform.rotation.z !=0) //проверка столкновения коллайдера автомобиля и препятствия, при столкновении происходит загрузка меню { Application.LoadLevel (0); } } } public void OnGUI() { if (GUI.RepeatButton (new Rect (Screen.width*0.1f, Screen.height*0.9f, Screen.width*0.2f, Screen.height*0.08f), "L")) //создаем кнопку для движения влево { if (transform.position.x > -2.4f) { transform.Translate (new Vector3 (-0.05f, 0f, 0f)); } } if (GUI.RepeatButton (new Rect (Screen.width*0.7f, Screen.height*0.9f, Screen.width*0.2f, Screen.height*0.08f), "R")) //создаем кнопку для движения вправо { if (transform.position.x < 2.4f) { transform.Translate (new Vector3 (0.05f, 0f, 0f)); } } } }

Посредством скрипта автомобиль получит возможность перемещаться .

Бензобак

Для создания показателя наполненности бензобака необходимо использовать одинаковые спрайты разных цветов .

Сделайте зеленый спрайт дочерним. Следующий аналогичен с предыдущими пунктами: создать скрипт (fuelscript.cs) и повесить его на бензобак (fuel) с таким содержанием:

Using UnityEngine; using System.Collections; public class fuelscript: MonoBehaviour { public GameObject fuelall; float mytimer=100f;// задание плавающего числа // Use this for initialization void Start () { } void Update () { mytimer = 100f; mytimer -= Time.deltaTime;//изменения числа с течением времени if (mytimer/mytimer==1f) //проверка на период времени в 1 секунду { fuelall.transform.position=new Vector3(fuelall.transform.position.x-0.0011f,fuelall.transform.position.y,fuelall.transform.position.z); fuelall.transform.localScale = new Vector3(fuelall.transform.localScale.x-0.001f, 1, 1); //выше идет сдвижение влево и уменьшение по ширине зеленой полосы для имитации шкалы } if (fuelall.transform.localScale.x < 0) //если шкала исчезла то загрузка идет загрузка главного меню { Application.LoadLevel(0); } } }

Трасса в нашем меню называется road183 , а ее копия – road183(1) . В дочерний объект fueltrack добавьте скрипт, отвечающий за восполнение бензобака при его контакте с автомобилем. Следующим шагом будет создание скрипта triger.cs. Повесьте его на fueltrack в каждой трассе. И отметьте объект, как Is Triger с таким кодом:

Using UnityEngine; using System.Collections; public class triger: MonoBehaviour { public GameObject fuel;//добавляем сюда greenfuel // Use this for initialization void Start () { } // Update is called once per frame void Update () { } void OnTriggerEnter2D(Collider2D col) { if (col.gameObject.name == "playercar") //проверка пересечения автомобиля и объекта fuel { fuel.transform.position=new Vector3(0,fuel.transform.position.y,fuel.transform.position.z); fuel.transform.localScale = new Vector3(1, 1, 1); //восстановление у объекта fuel стандартных значений } } }

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

Этот туториал предназначен в первую очередь для новичков в разработке под андроид, но может быть будет полезен и более опытным разработчикам. Тут рассказано как создать простейшую 2D игру на анроиде без использования каких-либо игровых движков. Для этого я использовал Android Studio, но можно использовать любую другую соответствующее настроенную среду разработки.

Шаг 1. Придумываем идею игры
Для примера возьмём довольно простую идею:

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


Шаг 2. Создаём проект
В Android Studio в верхнем меню выбираем File → New → New Project.

Тут вводим название приложения, домен и путь. Нажимаем Next.

Тут можно ввести версию андроид. Также можно выбрать андроид часы и телевизор. Но я не уверен что наше приложение на всём этом будет работать. Так что лучше введите всё как на скриншоте. Нажимаем Next.

Тут обязательно выбираем Empty Activity. И жмём Next.

Тут оставляем всё как есть и жмём Finish. Итак проект создан. Переходим ко третьему шагу.

Шаг 3. Добавляем картинки

Шаг 5. Редактируем MainActivity класс

В первую очередь в определение класса добавляем implements View.OnTouchListener. Определение класса теперь будет таким:

Public class MainActivity extends AppCompatActivity implements View.OnTouchListener {
Добавим в класс нужные нам статические переменные (переменные класса):

Public static boolean isLeftPressed = false; // нажата левая кнопка public static boolean isRightPressed = false; // нажата правая кнопка
В процедуру protected void onCreate(Bundle savedInstanceState) {
добавляем строки:

GameView gameView = new GameView(this); // создаём gameView LinearLayout gameLayout = (LinearLayout) findViewById(R.id.gameLayout); // находим gameLayout gameLayout.addView(gameView); // и добавляем в него gameView Button leftButton = (Button) findViewById(R.id.leftButton); // находим кнопки Button rightButton = (Button) findViewById(R.id.rightButton); leftButton.setOnTouchListener(this); // и добавляем этот класс как слушателя (при нажатии сработает onTouch) rightButton.setOnTouchListener(this);
Классы LinearLayout, Button и т.д. подсвечены красным потому что ещё не добавлены в Import.
Чтобы добавить в Import и убрать красную подсветку нужно для каждого нажать Alt+Enter.
GameView будет подсвечено красным потому-что этого класса ещё нет. Мы создадим его позже.

Теперь добавляем процедуру:

Public boolean onTouch(View button, MotionEvent motion) { switch(button.getId()) { // определяем какая кнопка case R.id.leftButton: switch (motion.getAction()) { // определяем нажата или отпущена case MotionEvent.ACTION_DOWN: isLeftPressed = true; break; case MotionEvent.ACTION_UP: isLeftPressed = false; break; } break; case R.id.rightButton: switch (motion.getAction()) { // определяем нажата или отпущена case MotionEvent.ACTION_DOWN: isRightPressed = true; break; case MotionEvent.ACTION_UP: isRightPressed = false; break; } break; } return true; }
Если кто-то запутался ― вот так в результате должен выглядеть MainActivity класс:

Package com.spaceavoider.spaceavoider; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.MotionEvent; import android.view.View; import android.widget.Button; import android.widget.LinearLayout; public class MainActivity extends AppCompatActivity implements View.OnTouchListener { public static boolean isLeftPressed = false; // нажата левая кнопка public static boolean isRightPressed = false; // нажата правая кнопка @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); GameView gameView = new GameView(this); // создаём gameView LinearLayout gameLayout = (LinearLayout) findViewById(R.id.gameLayout); // находим gameLayout gameLayout.addView(gameView); // и добавляем в него gameView Button leftButton = (Button) findViewById(R.id.leftButton); // находим кнопки Button rightButton = (Button) findViewById(R.id.rightButton); leftButton.setOnTouchListener(this); // и добавляем этот класс как слушателя (при нажатии сработает onTouch) rightButton.setOnTouchListener(this); } public boolean onTouch(View button, MotionEvent motion) { switch(button.getId()) { // определяем какая кнопка case R.id.leftButton: switch (motion.getAction()) { // определяем нажата или отпущена case MotionEvent.ACTION_DOWN: isLeftPressed = true; break; case MotionEvent.ACTION_UP: isLeftPressed = false; break; } break; case R.id.rightButton: switch (motion.getAction()) { // определяем нажата или отпущена case MotionEvent.ACTION_DOWN: isRightPressed = true; break; case MotionEvent.ACTION_UP: isRightPressed = false; break; } break; } return true; } }
Итак, класс MainActivity готов! В нём инициирован ещё не созданный класс GameView. И когда нажата левая кнопка - статическая переменная isLeftPressed = true, а когда правая - isRightPressed = true. Это в общем то и всё что он делает.

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

Шаг 6. Создаём класс GameView

Теперь наконец-то создадим тот самый недостающий класс GameView. Итак приступим. В определение класса добавим extends SurfaceView implements Runnable. Мобильные устройства имею разные разрешения экрана. Это может быть старенький маленький телефон с разрешением 480x800, или большой планшет 1800x2560. Для того чтобы игра выглядела на всех устройствах одинаково я поделил экран на 20 частей по горизонтали и 28 по вертикали. Полученную единицу измерения я назвал юнит. Можно выбрать и другие числа. Главное чтобы отношение между ними примерно сохранялось, иначе изображение будет вытянутым или сжатым.

Public static int maxX = 20; // размер по горизонтали public static int maxY = 28; // размер по вертикали public static float unitW = 0; // пикселей в юните по горизонтали public static float unitH = 0; // пикселей в юните по вертикали
unitW и unitW мы вычислим позже. Также нам понадобятся и другие переменные:

Private boolean firstTime = true; private boolean gameRunning = true; private Ship ship; private Thread gameThread = null; private Paint paint; private Canvas canvas; private SurfaceHolder surfaceHolder;
Конструктор будет таким:

Public GameView(Context context) { super(context); //инициализируем обьекты для рисования surfaceHolder = getHolder(); paint = new Paint(); // инициализируем поток gameThread = new Thread(this); gameThread.start(); }
Метод run() будет содержать бесконечный цикл. В начале цикла выполняется метод update()
который будет вычислять новые координаты корабля. Потом метод draw() рисует корабль на экране. И в конце метод control() сделает паузу на 17 миллисекунд. Через 17 миллисекунд run() запустится снова. И так до пока переменная gameRunning == true. Вот эти методы:

@Override public void run() { while (gameRunning) { update(); draw(); control(); } } private void update() { if(!firstTime) { ship.update(); } } private void draw() { if (surfaceHolder.getSurface().isValid()) { //проверяем валидный ли surface if(firstTime){ // инициализация при первом запуске firstTime = false; unitW = surfaceHolder.getSurfaceFrame().width()/maxX; // вычисляем число пикселей в юните unitH = surfaceHolder.getSurfaceFrame().height()/maxY; ship = new Ship(getContext()); // добавляем корабль } canvas = surfaceHolder.lockCanvas(); // закрываем canvas canvas.drawColor(Color.BLACK); // заполняем фон чёрным ship.drow(paint, canvas); // рисуем корабль surfaceHolder.unlockCanvasAndPost(canvas); // открываем canvas } } private void control() { // пауза на 17 миллисекунд try { gameThread.sleep(17); } catch (InterruptedException e) { e.printStackTrace(); } }
Обратите внимание на инициализацию при первом запуске. Там мы вычисляем количество пикселей в юните и добавляем корабль. Корабль мы ещё не создали. Но прежде мы создадим его родительский класс.

Шаг 7. Создаём класс SpaceBody

Он будет родительским для класса Ship (космический корабль) и Asteroid (астероид). В нём будут содержаться все переменные и методы общие для этих двух классов. Добавляем переменные:

Protected float x; // координаты protected float y; protected float size; // размер protected float speed; // скорость protected int bitmapId; // id картинки protected Bitmap bitmap; // картинка
и методы

Void init(Context context) { // сжимаем картинку до нужных размеров Bitmap cBitmap = BitmapFactory.decodeResource(context.getResources(), bitmapId); bitmap = Bitmap.createScaledBitmap(cBitmap, (int)(size * GameView.unitW), (int)(size * GameView.unitH), false); cBitmap.recycle(); } void update(){ // тут будут вычисляться новые координаты } void drow(Paint paint, Canvas canvas){ // рисуем картинку canvas.drawBitmap(bitmap, x*GameView.unitW, y*GameView.unitH, paint); }
Шаг 8. Создаём класс Ship

Теперь создадим класс Ship (космический корабль). Он наследует класс SpaceBody поэтому в определение класа добавим extends SpaceBody.

Напишем конструктор:

Public Ship(Context context) { bitmapId = R.drawable.ship; // определяем начальные параметры size = 5; x=7; y=GameView.maxY - size - 1; speed = (float) 0.2; init(context); // инициализируем корабль }
и переопределим метод update()

@Override public void update() { // перемещаем корабль в зависимости от нажатой кнопки if(MainActivity.isLeftPressed && x >= 0){ x -= speed; } if(MainActivity.isRightPressed && x <= GameView.maxX - 5){ x += speed; } }
На этом космический корабль готов! Всё компилируем и запускаем. На экране должен появиться космический корабль. При нажатии на кнопки он должен двигаться вправо и влево. Теперь добавляем сыплющиеся сверху астероиды. При столкновении с кораблём игра заканчивается.

Шаг 9. Создаём класс Asteroid

Добавим класс Asteroid (астероид). Он тоже наследует класс SpaceBody поэтому в определение класса добавим extends SpaceBody.

Добавим нужные нам переменные:

Private int radius = 2; // радиус private float minSpeed = (float) 0.1; // минимальная скорость private float maxSpeed = (float) 0.5; // максимальная скорость
Астероид должен появляться в случайной точке вверху экрана и лететь вниз с случайной скоростью. Для этого x и speed задаются при помощи генератора случайных чисел в его конструкторе.

Public Asteroid(Context context) { Random random = new Random(); bitmapId = R.drawable.asteroid; y=0; x = random.nextInt(GameView.maxX) - radius; size = radius*2; speed = minSpeed + (maxSpeed - minSpeed) * random.nextFloat(); init(context); }
Астероид должен двигаться с определённой скорость вертикально вниз. Поэтому в методе update() прибавляем к координате x скорость.

@Override public void update() { y += speed; }
Так же нам нужен будет метод определяющий столкнулся ли астероид с кораблём.

Public boolean isCollision(float shipX, float shipY, float shipSize) { return !(((x+size) < shipX)||(x > (shipX+shipSize))||((y+size) < shipY)||(y > (shipY+shipSize))); }
Рассмотрим его поподробнее. Для простоты считаем корабль и астероид квадратами. Тут я пошёл от противного. То есть определяю когда квадраты НЕ пересекаются.

((x+size) < shipX) - корабль слева от астероида.
(x > (shipX+shipSize)) - корабль справа от астероида.
((y+size) < shipY) - корабль сверху астероида.
(y > (shipY+shipSize)) - корабль снизу астероида.

Между этими четырьмя выражениями стоит || (или). То есть если хоть одно выражение правдиво (а это значит что квадраты НЕ пересекаются) - результирующие тоже правдиво.

Всё это выражение я инвертирую знаком!. В результате метод возвращает true когда квадраты пересекаются. Что нам и надо.

Про определение пересечения более сложных фигур можно почитать .

Шаг 10. Добавляем астероиды в GameView

В GameView добавляем переменные:

Private ArrayList asteroids = new ArrayList<>(); // тут будут харанится астероиды private final int ASTEROID_INTERVAL = 50; // время через которое появляются астероиды (в итерациях) private int currentTime = 0;
также добавляем 2 метода:

Private void checkCollision(){ // перебираем все астероиды и проверяем не касается ли один из них корабля for (Asteroid asteroid: asteroids) { if(asteroid.isCollision(ship.x, ship.y, ship.size)){ // игрок проиграл gameRunning = false; // останавливаем игру // TODO добавить анимацию взрыва } } } private void checkIfNewAsteroid(){ // каждые 50 итераций добавляем новый астероид if(currentTime >= ASTEROID_INTERVAL){ Asteroid asteroid = new Asteroid(getContext()); asteroids.add(asteroid); currentTime = 0; }else{ currentTime ++; } }
И в методе run() добавляем вызовы этих методов перед вызовоом control().

@Override public void run() { while (gameRunning) { update(); draw(); checkCollision(); checkIfNewAsteroid(); control(); } }
Далее в методе update() добавляем цикл который перебирает все астероиды и вызывает у них метод update().

Private void update() { if(!firstTime) { ship.update(); for (Asteroid asteroid: asteroids) { asteroid.update(); } } }
Такой же цикл добавляем и в метод draw().

Private void draw() { if (surfaceHolder.getSurface().isValid()) { //проверяем валидный ли surface if(firstTime){ // инициализация при первом запуске firstTime = false; unitW = surfaceHolder.getSurfaceFrame().width()/maxX; // вычисляем число пикселей в юните unitH = surfaceHolder.getSurfaceFrame().height()/maxY; ship = new Ship(getContext()); // добавляем корабль } canvas = surfaceHolder.lockCanvas(); // закрываем canvas canvas.drawColor(Color.BLACK); // заполняем фон чёрным ship.drow(paint, canvas); // рисуем корабль for(Asteroid asteroid: asteroids){ // рисуем астероиды asteroid.drow(paint, canvas); } surfaceHolder.unlockCanvasAndPost(canvas); // открываем canvas } }
Вот и всё! Простейшая 2D игра готова. Компилируем, запускаем и смотрим что получилось!
Если кто-то запутался или что-то не работает можно скачать исходник .

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

На этом всё. Пишите отзывы, вопросы, интересующие вас темы для продолжения.

Теги:

Добавить метки

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

Идея

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

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

Список особенностей

Так как создавать игры на "Андроид" невозможно без их детальной проработки, на данном этапе придется продолжить работу в и описать особенности, которые будут в игре. Приведем пример: серия God of War - это слэшер. Оружие главного героя - кнут. Во время боя можно делать длинные красивые комбо-атаки. Каждый уровень завершается схваткой с боссом.

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

Диздок

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

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

Объектная модель

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

Под функциональностью следует понимать:

  • Можно ли надеть\снять\купить\продать\улучшить.
  • Останется ли в инвентаре после смерти.
  • Потеряет ли прочность с течением времени либо при каком-нибудь действии.
  • Повышает ли характеристики персонажа или группы.
  • Имеет ли набор особых свойств.

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

Функциональные спецификации

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

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

Контент

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

Интерфейс

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

Выбор движка или конструктора

Еще один шаг, который придется выполнить до того, как создавать игры на "Андроид", - выбрать Давно прошли те времена, когда всё необходимо было делать с нуля. Сегодня, взяв готовый конструктор, можно выполнить все работы, написав минимум кода.

Выбор движка стоит делать, основываясь на некоторых его особенностях:

  • Условия использования.
  • Возможности.
  • Цена.
  • Поддержка разработчиками.
  • Задокументированность.
  • Размер комьюнити.
  • Простота.
  • Расширяемость.

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

Возможности : они должны полностью перекрывать потребности разработчика. Если же продукт предлагает больше, чем нужно, игру можно будет легко расширить, задействовать новые функции диздока. Но задумайтесь и о балансе! Использовать Unreal Engine для тетриса - глупо.

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

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

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

UDK

Unreal Development Kit - не самый простой в освоении игровой движок, но зато один из самых мощных. Его используют не только начинающие разработчики, но и крупные корпорации. Если вы ищете ответ на вопрос: "Как создать 3Д-игру и какой движок для этого выбрать?" - вам стоит изучить возможности UDK.

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

Torque 2D/3D

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

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

Для написания скриптов в Torque встроен язык Torque Script. Свойства каждого объекта могут быть определены заранее. Также в конструктор встроен набор Box2D, который занимается физическими расчетами.

Если вы пытаетесь найти ответ на вопрос: "Как создать и какой движок для этого выбрать?" - можно смело заявить, что Torque позволит сделать мультиплеерный проект в сжатые сроки. Весь необходимый функционал встроен заранее, а примеры, находящиеся на официальном сайте, покажут, как его использовать наиболее рационально.

Изучение

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

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

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

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

Статьи и Лайфхаки

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

Делаем игру на телефон: задумка и обучение

Итак, ответ на вопрос является утвердительным. Изначально будущему разработчику следует определиться с операционной системой мобильного телефона, на которую будет рассчитана его игра. На сегодняшний день не существует такой мобильной платформы, которой бы пользователи отдавали наибольшее предпочтение – как это происходит, к примеру, в мире персональных компьютеров, где «пальма первенства» принадлежит Windows. Каждый из производителей готов предложить нечто эксклюзивное, и в итоге рынок заполнен десятками операционных систем. Наиболее популярными можно назвать Windows Phone 7, Android, iOs и Symbian OS. Для начала придётся заняться разработкой игры для конкретной платформы, а уж потом можно попытаться подстроить приложение и под другие системы. Вопрос о том, как сделать игру на телефон, требует самого смелого и творческого подхода, поскольку иногда различие между ОС оказывается очень существенным.

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

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

Делаем игру на телефон: разработка и тестирование

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

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

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

Этот урок начинает серию статей, посвященных написанию аркадных игр для Android. За основу был взят цикл, который написал и опубликовалв своем блоге Tamas Jano . Материал ориентирован, прежде всего, на начинающих программистов, которые хотят попробовать свои силы в создании игр для Android. Я ставлю перед собой цель создать у нас на сайте максимально понятный и доступный учебник для молодой русскоязычной аудитории, поэтому очень надеюсь на вашу критику, вопросы и комментарии. Опубликованный в этом цикле материал будет постоянно перерабатываться с учетом ваших вопросов, пожеланий и замечаний. Надеюсь, что вместе мы сможем успешно осуществить этот небольшой эксперимент.

Александр Ледков

Идея и архитектура

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

Смоделируем игровую ситуацию. Наш персонаж находится в центре экрана. Роботы каждую 1/10 секунды приближаются к нему. каждую десятую секунду мы проверяем также не произошло ли касание экрана. Если произошло - двигаем наш персонаж в необходимом направлении или делаем выстрел. если выстрел сделан, каждый тик (1/10 секунды) мы проверяем столкновение пули с врагами. Если пуля попала в робота - то и робот и пуля взрываются, если нет - роботы и пуля перемещаются на новые позиции (робот перемещается на 5 пикселей за тик, а пуля - на 50 пикселей). Мы также проверяем не поймал ли робот нашего героя. Если поймал - игра заканчивается.

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

  1. Модуль управления . Здесь считываются координаты касания экрана.
  2. Игровой движок . Здесь мы должны обновить состояние игровых объектов, то есть вычислить их новые координаты, проверить здоровье, столкновения и тому подобное.
  3. Аудио модуль .
  4. Графический модуль . Здесь на основании текущего состояния формируется и выводится на экран новый кадр.

Давайте более детально рассмотрим наши модули.

Модуль управления

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

Игровой движок

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

Давайте рассмотрим взаимодействие модуля управления и игрового движка. На представленном выше рисунке показан круг-контроллер. Светлое зеленое пятно символизирует область касания. Модуль управления сообщает игровому движку координаты касания (dx и dy - расстояния в пикселях от центра круга). На основании этих координат игровой движок вычисляет направление и скорость движения нашего героя. Например, если dx>0, наш персонаж движется вправо, eсли dy>0 - в верх.

Аудио модуль

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

Графический модуль

Этот модуль отвечает за вывод игровой ситуации на экран телефона. В Android существует несколько способов формирования изображения на экране. Можно рисовать прямо на canvas, полученный от View или использовать отдельный графический буффер и вы, а затем передавать его View, а можно воспользоваться возможностями библиотеки OpenGL. Полезно при разработке игры постоянно измерять FPS - число кадров в секунду, которые выдает ваш графический движок. Величина в 30 FPS означает, что за одну секунду наша программа успевает 30 раз обновить экран. Забегая вперед скажу, что для мобильного устройства 30 FPS более чем достойный показатель.

Создаем проект-заготовку для будущей Android игры

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

Создайте новый проект. В поле Project Name введитеDroidz . В качестве целевой платформы выберите Android 2.2 или выше. В Package Name - "ru.mobilab.gamesample ". Не забудьте поставить галочку около Create Activity. В качестве имени главной activity введитеDroidzActivity .

Откройте файл src/ru.mobilab.gamesample/DroidzActivity.java

import android.app.Activity;
import android.os.Bundle;

public class DroidzActivity extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
}

Метод onCreate вызывается при создании activity во время запуска приложения. Этот метод можно рассматривать, как точу входа в программу. Класс R.java автоматически генерируется Eclipse и содержит в себе ссылки на ресурсы. Каждый раз, когда вы изменяете ресурсы в Eclipse класс R пересобирается.

Главный игровой цикл

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

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

Давайте откроем файл DroidzActivity.java. В конструкторе класса вы увидите строчку

SetContentView(R.layout.main);

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

MainGamePanel.java

package ru.mobilab.gamesample;






SurfaceHolder.Callback {


super(context);
// Добавляем этот класс, как содержащий функцию обратного
// вызова для взаимодействия с событиями
// делаем GamePanel focusable, чтобы она могла обрабатывать сообщения
setFocusable(true);
}

@Override
}

@Override
}

@Override
}

@Override

}

@Override
}
}

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

GetHolder().addCallback(this);

Устанавливает текущий класс (MainGamePanel) как обработчик событий от поверхности.

SetFocusable(true);

Эта строка делает наш класс фокусируемым. Это означает, что он может получать фокус, а значит и события.

Давайте создадим поток, внутри которого собственно и будет реализован наш игровой цикл. Разделение игры на несколько параллельно выполняющихся потоков - общепринятая в современном геймдеве практика. Создадим для нашего потока класс MainThread.java

Package ru.mobilab.gamesample;

public class MainThread extends Thread {

//флаг, указывающий на то, что игра запущена.

Private boolean running;
public void setRunning(boolean running) {
this.running = running;
}

@Override
public void run() {
while (running) {
// обновить состояние игровых объектов
// вывести графику на экран
}
}
}

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

После того, как мы создали класс потока, его нужно запустить. Давайте запускать его при загрузке экрана. Изменим класс MainGamePanel

Package ru.mobilab.gamesample;

import android.content.Context;
import android.graphics.Canvas;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class MainGamePanel extends SurfaceView implements
SurfaceHolder.Callback {

Private MainThread thread;

Public MainGamePanel(Context context) {
super(context);
getHolder().addCallback(this);

// создаем поток для игрового цикла
thread = new MainThread();

SetFocusable(true);
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
thread.setRunning(true);
thread.start();
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
//посылаем потоку команду на закрытие и дожидаемся,
//пока поток не будет закрыт.
boolean retry = true;
while (retry) {
try {
thread.join();
retry = false;
} catch (InterruptedException e) {
// пытаемся снова остановить поток thread
}
}
}

@Override
public boolean onTouchEvent(MotionEvent event) {
return super.onTouchEvent(event);
}

@Override
protected void onDraw(Canvas canvas) {
}
}

Мы объявили объект thread

Private MainThread thread;

и создали его в конструкторе

Thread = new MainThread();

в методе surfaceCreated мы установили флаг running в значение true и запустили поток. К этому времени объект thread уже благополучно создан и можем без опасений запускать его.

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

Добавляем взаимодействие с экраном

Чтобы показать, как в Android обработать касания, напишем небольшой пример. Будем выходить из программы, когда пользователь коснется нижней части экрана. Если касание произошло где-то выше - будем просто выводить в лог соответствующие координаты. Добавим в класс MainThread следующие строки:

Private SurfaceHolder surfaceHolder;
private MainGamePanel gamePanel;

public MainThread(SurfaceHolder surfaceHolder, MainGamePanel gamePanel) {
super();
this.surfaceHolder = surfaceHolder;
this.gamePanel = gamePanel;
}

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

Измените строку в классе MainGamePanel, добабвив в конструктор вновь объявленные параметры

Thread = new MainThread(getHolder(), this);

Мы передаем текущий обработчик и панель в новый конструктор. Это позволит нам иметь к ней доступ из потока. В gamePanel мы создадим метод update и будем переключать его из потока, но пока оставим все как есть.

Логирование

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

Чтобы посмотреть записанные в процессе выполнения программы логи нужно выбрать меню
Windows -> Show View -> Other…
а затем в открывшемся диалоге
Android -> LogCat
В открывшемся окне можно не только просматривать логи, но и осуществлять фильтрацию и поиск.

Вернемся к нашему коду. Внесем изменения в MainThread.java

Package ru. mobilab. gamesample; import android. util. Log ; import android. view. SurfaceHolder; public class MainThreadextends Thread{ private static final String TAG= MainThread. class . getSimpleName() ; private SurfaceHolder surfaceHolder; private MainGamePanel gamePanel; private boolean running; public void setRunning(boolean running) { this. running= running; } public MainThread(SurfaceHolder surfaceHolder, MainGamePanel gamePanel) { super() ; this. surfaceHolder= surfaceHolder; this. gamePanel= gamePanel; } @ Override public void run() { long tickCount= 0L; Log . d(TAG, "Starting game loop" ) ; while (running) { tickCount++; // здесь будет обновляться состояние игры // и формироваться кадр для вывода на экран } Log . d(TAG, "Game loop executed " + tickCount+ " times" ) ; } }

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

Перейдем к файлу MainGamePanel.java и найдем метод onTouchEvent, который является обработчиком касаний экрана.

public boolean onTouchEvent(MotionEvent event) { if (event. getAction() == MotionEvent. ACTION_DOWN) { if (event. getY() > getHeight() - 50 ) { thread. setRunning(false ) ; ((Activity) getContext() ) . finish() ; } else { Log . d(TAG, "Coords: x=" + event. getX() + ",y=" + event. getY() ) ; } } return super. onTouchEvent(event) ; }

Сначала мы проверяем произошло ли событие касания экрана (MotionEvent.ACTION_DOWN). Если произошло, проверяем координату y и если она находится в нижней части экрана (50 пикселей снизу), мы посылаем потоку команду на завершение (установив переменную running в false), а затем вызываем метод finish() для главной Activity, который закрывает всю нашу программу.

Замечание. Начало системы координат у экрана находится в левом верхнем углу. Ось y направлена вниз, ось x - вправо. Ширину и высоту экрана можно получить с помощью методов getWidth() и getHeight() соответственно.

Изменим DroidzActivity.java, добавив команды записи в лог

Package ru. mobilab. gamesample; import android. app. Activity; import android. os. Bundle; import android. util. Log ; import android. view. Window; import android. view. WindowManager; public class DroidzActivityextends Activity{ /** Вызывается при создании activity. */ private static final String TAG= DroidzActivity. class . getSimpleName() ; @ Override public void onCreate(Bundle savedInstanceState) { super. onCreate(savedInstanceState) ; // запрос на отключение строки заголовка requestWindowFeature(Window. FEATURE_NO_TITLE) ; // перевод приложения в полноэкранный режим getWindow() . setFlags(WindowManager. LayoutParams. FLAG_FULLSCREEN, WindowManager. LayoutParams. FLAG_FULLSCREEN) ; // устанавливаем MainGamePanel как View setContentView(new MainGamePanel(this) ) ; Log . d(TAG, "View added" ) ; } @ Override protected void onDestroy() { Log . d(TAG, "Destroying..." ) ; super. onDestroy() ; } @ Override protected void onStop() { Log . d(TAG, "Stopping..." ) ; super. onStop() ; } }

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

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

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

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

Перевод и адаптация:Александр Ледков



Поддержите проект — поделитесь ссылкой, спасибо!
Читайте также
Адвокат Соколовского о Тинькове и «Немагии»: «Все это напоминает ситуацию с моим подзащитным Адвокат Соколовского о Тинькове и «Немагии»: «Все это напоминает ситуацию с моим подзащитным Яблочный пудинг с манкой для детей Молочный пудинг для ребенка 1 5 Яблочный пудинг с манкой для детей Молочный пудинг для ребенка 1 5 вышивка – все толкования вышивка – все толкования