Написать игру для Android за 1 час. Реально?

от автора

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

Основные требования к разрабатываемой игре:
— Запускаемость в эмуляторе Android
— Запускаемость на конкретном Android устройстве (обязательно!!!)
— Высокая скорость разработки

Какую игру буду делать: простая игрушка, три игровых состояния: Стартовое меню, Игра, Меню GameOver.

На поле есть айфон, который ловит падающие яблочки от Эппл.

В качестве инструмента был взят JavaScript, J2ds (2D движок) и Intel XDK.

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

image

Если все еще интересно, прошу под кат =)

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

Далее я буду приводить куски кода, с некоторыми пояснениями.

Подготовка игровой сцены.

Так как я выбрал 2D движок в HTML5, то подготовка сцены — это создание специального формата HTML странички.

index.html

<!DOCTYPE html> <html>   <head>   <script type="text/javascript" src="j2ds/engineMath.js"></script>   <script type="text/javascript" src="j2ds/engineKey.js"></script>      <script type="text/javascript" src="j2ds/engineDOM.js"></script>   <script type="text/javascript" src="j2ds/engine2D.js"></script>   <meta http-equiv="content-type" content="text/html; charset=UTF-8" />   <meta name="viewport" content="width=device-width,user-scalable=no" />     <title></title>  </head>  <body id="gameBody">  <img id="buttons" src="img/buttons.png" alt="">   <canvas id="iCanvas" width="100" height="100"></canvas> <br> <div id="hint"></div>  <script type="text/javascript"> initKeyBoard('gameBody');  scene= createScene('iCanvas', '#ceeeee');  startGame(); </script>  </body> </html> 

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

<img id="buttons" src="img/buttons.png" alt=""> 

Сама картинка выглядит так:

Спрайт-карта

image

Основной файл, в котором я подглядывал функции: namespaces.js, там все функции разобраны по разделам и с комментариями.

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

initKeyBoard('game'); buttons= CreateImageMap('buttons'); // id объекта HTML scene= createScene('canvas',  // Первый агрумент - id объекта Сanvas                     'rgb(250, 250, 200)'); // Второй агрумент - цвет фона 

Как только мы инициализировали игровую сцену, развернем ее на весь экран:

scene.fullScreen(true); 

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

 // Кнопочки управления платформой anim= buttons.CreateAnimation(                  0, 0,   // Начальная позция первого кадра                  300, 300, // Размер кадра                  2       // Количество кадров (по горизонтали)                  ); // Анимация яблочка apples= buttons.CreateAnimation(                  8, 325,   // Начальная позция первого кадра                  81, 89, // Размер кадра                  2       // Количество кадров (по горизонтали)                  ); // Айфон                  iPhone= buttons.CreateAnimation(                  210, 345,   // Начальная позция первого кадра                  312, 56, // Размер кадра                  2       // Количество кадров (по горизонтали)                  ); 

Пришло время поговорить об игровых состояниях.
При запуске игры запускается первое игровое состояние — Стартовое меню. Давайте с ним и поработаем.

Разработка стартового меню

Выглядит стартовое меню так:

Меню для игры скриншот

image

Ниже приведен код функции «Menu()» с комментариями:

Меню для игры JS

 // Создание зеленого прямоугольника newGame= CreateRect(                 90, 20, // Положение                150, 100, // Размеры                'green' // Цвет               );  // Создание красного прямоугольника exitGame= CreateRect(                 90, 20, // Положение                150, 100, // Размеры                'red' // Цвет               );  dY= -100; // Переменная для смещения меню (для плавного появления сверху вниз) // А теперь опишем саму функцию меню function Menu() {  Mouse.updPosition(scene); // Обновляем позицию курсора/тач-касания относительно сцены  dY+= dY > 0 ? 0 : 1; // смещаем меню вниз до -100px   // Если произведен клик/тач по зеленому прямоугольнику - переключаемся на игровой процесс // а так же окращиваем зеленый прямоугольник белым цветом, символизируя реакцию игры на действия пользователя  if (Mouse.Click && Mouse.onNode(newGame)) {   newGame.color= 'white';   SetActivEngine(Game);  }   // Аналогично и для красного прямоугольника, только с выходом из игры   if (Mouse.Click && Mouse.onNode(exitGame)) {   exitGame.color= 'white';   ExitGame();  }    // Выводим текст со смещением dY  scene.DrawTextOpt(                     170, 100+dY, // Позиция                   'Rect Game', // Текст                   'bold 30px sans-serif', // Шрифт (аналогично CSS)                   'white', // Цвет текста                   'green', // Цвед обводки                   6 // Толщина обводки                   );                                                        // Позиционируем зеленый прямоугольник со смещением  newGame.setPosition(120, 200+dY);                     newGame.Draw(scene); // рисуем его  // То же самое для красного прямоугольника  exitGame.setPosition(370, 200+dY);                     exitGame.Draw(scene);    // Рисуем надпись поверх зеленого прямоугольника  scene.DrawText(90, 190+dY,  // Позиция                'Новая игра'); // Текст // Аналогично для красного  scene.DrawText(350, 190+dY,  // Позиция                'Bыход'); // Текст    } 

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

Аналогично этой функции есть функция GameOver, которая отличается только выводимым текстом «Game Over» вместо названия «Rect Game»:

Меню GameOver

 function GameOver() {  Mouse.updPosition(scene);   dY+= dY > 0 ? 0 : 1;    if (Mouse.Click && Mouse.onNode(newGame)) {   newGame.color= 'white';   SetActivEngine(Game);  }     if (Mouse.Click && Mouse.onNode(exitGame)) {   exitGame.color= 'white';   ExitGame();  }    scene.DrawTextOpt(                     170, 100+dY, // Позиция                   'Game Over', // Текст                   'bold 30px sans-serif', // Шрифт (аналогично CSS)                   'white', // Цвет текста                   'green', // Цвед обводки                   6 // Толщина обводки                   );                                                         newGame.setPosition(120, 200+dY);                     newGame.Draw(scene);   exitGame.setPosition(370, 200+dY);                     exitGame.Draw(scene);     scene.DrawText(90, 190+dY,  // Позиция                'Новая игра'); // Текст  scene.DrawText(350, 190+dY,  // Позиция                'Bыход'); // Текст 	 } 

Уже хорошо. Осталось самое главное: игровой процесс. Тут все гораздо интереснее!

Помните, мы ранее загрузили спрайт-карту с кнопками? Пришло время ею воспользоваться! Создадим две кнопки для управления айфоном:

move= []; // массив с двумя кнопками  move[0]= CreateSprite(     0, 200, // Позиция в игре     100, 100, // Размеры в игре     anim    // Анимация     );  move[1]= CreateSprite(     400, 200, // Позиция в игре     100, 100, // Размеры в игре     anim    // Анимация    ); 

Немного поясню: anim — это объект анимации, который мы создавали вначале, прокрутите вверх, посмотрите, чтобы лучше понять. amin хранит у нас два кадра: первый — стрелка влево, второй — стрелка вправо. Идем дальше.

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

me= CreateSprite(     250, 180, // Позиция в игре     100, 20, // Размеры в игре     iPhone    // Анимация    ); 

Вроде всё. А, не все! Самих яблочек то нет! Даавй тоже их создадим:

arr= []; count= 5; // Объявим массив и количество яблок // Затем циклом создадим их for (var i=0; i<count; i+=1) {  arr[i]= CreateSprite(     Random(0, 450), -50, // Позиция в игре (по оси Х они рандомятся, чтобы падали по всей ширине)     20, 20, // Размеры в игре     apples    // Анимация (хранит в себе два кадра анимации)    );  arr[i].speed= Random(1, 3); // Устанавливаем скорость падения яблочка рандомно } 

Объявим еще три переменных:

speed= 4; score= 0; gameOverScore= 0; 

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

Теперь пришло время написать самую главную функцию: саму игру!

функция Game()

function Game() { // Обновляем позицию курсора/тач-касания  Mouse.updPosition(scene);     // Если игрок пропустил более 10 яблок, то Гейм Овер   if (gameOverScore > 10)  {    dY= -100;    SetActivEngine(GameOver);    gameOverScore= 0;   }     // Если кликает ли жмет на экран влево, двигаем айфон влево, пока не упрется в стену  if (Mouse.Click && Mouse.onNode(move[0])) {   if (me.posX > 0) me.Move(-speed, 0);   }   // Аналогично и вправо  if (Mouse.Click && Mouse.onNode(move[1])) {   if (me.posX+me.sizeX < scene.Canvas.width) me.Move(speed, 0);   }  // Начинаем цикл для проверки яблок  for (var i=0; i<count; i+=1) {    // Если яблоко коснулось айфона, мы перекидываем его за пределы видимости вверх (оно снова падает) // А игрок получает очко (игровое) и прибавляет в скорости  if (arr[i].Collision(me)) {   score+=1; speed+=0.2;    arrNewPos(i); // фнукция для перекидывания яблочка наверх  }      // Если пользователь пропустил яблочко, он приближается к своему концу // А яблочко снова перемещается и падает   if (arr[i].posY > me.posY) {    arrNewPos(i); gameOverScore+=1;   }       // двигаем яблочко вниз с его скоростью   arr[i].Move(0, arr[i].speed); // рисуем яблочко, анимируя его (в этом случае скорость анимации: 10)   arr[i].DrawAnimate(scene, 10);  }    // После всех яблочек рисуем айфон  me.Draw(scene);   // Выводим счет игрока вверху экрана  scene.DrawTextOpt(                     5, 5, // Позиция                   'Игровой счет: '+score, // Текст                   'bold 25px sans-serif', // Шрифт (аналогично CSS)                   'white', // Цвет текста                   'green', // Цвед обводки                   3 // Толщина обводки                   );                     // рисуем наши кнопки управления, где второй параметр функции Draw() - это номер кадра. // Если не забыли, 1 кадр - стрелка влево, 2 вправо  move[0].Draw(scene, 1); move[1].Draw(scene, 2);   // дебаг, выводит количество упущенных яблочек  dbg(gameOverScore); }  // функция, перемещающая яблочко за пределы видимости камеры вверх // рандомно устанавливает позицию и рандомно присваивает скорость function arrNewPos(_i) { 	arr[_i].setPosition(Random(0, scene.Canvas.width-arr[_i].sizeY),                       -Random(50, 300));  arr[_i].speed= Random(2, 5);   } 

Вот и весь игровой цикл, выглядит это вот так:

Смотреть

image

И остался последний штрих, игру нужно запустить:

startGame(Menu, 30); // запускает игровое состояние Menu() и устанавливает сцене ограничение в 30 fps 

Вот и все. Теперь, код целиком:

index.html

<!DOCTYPE html> <html>   <head>   <script type="text/javascript" src="j2ds/engineMath.js"></script>   <script type="text/javascript" src="j2ds/engineKey.js"></script>      <script type="text/javascript" src="j2ds/engineDOM.js"></script>   <script type="text/javascript" src="j2ds/engine2D.js"></script>   <meta http-equiv="content-type" content="text/html; charset=UTF-8" />   <meta name="viewport" content="width=device-width,user-scalable=no" />     <title>Rect Game</title>  </head>  <body id="game">   <img id="buttons" src="img/buttons.png" alt="">   <canvas id="canvas" width="500" height="300"></canvas> <br> <div id="hint"></div>  <script type="text/javascript"> initKeyBoard('game');  buttons= CreateImageMap('buttons'); // id объекта HTML  scene= createScene('canvas',  // Первый агрумент - id объекта Сanvas                     'rgb(250, 250, 200)'); // Второй агрумент - цвет фона  scene.fullScreen(true);  anim= buttons.CreateAnimation(                  0, 0,   // Начальная позция первого кадра                  300, 300, // Размер кадра                  2       // Количество кадров (по горизонтали)                  );  apples= buttons.CreateAnimation(                  8, 325,   // Начальная позция первого кадра                  81, 89, // Размер кадра                  2       // Количество кадров (по горизонтали)                  );                   iPhone= buttons.CreateAnimation(                  210, 345,   // Начальная позция первого кадра                  312, 56, // Размер кадра                  2       // Количество кадров (по горизонтали)                  );   newGame= CreateRect(                 90, 20, // Положение                150, 100, // Размеры                'green' // Цвет               );  exitGame= CreateRect(                 90, 20, // Положение                150, 100, // Размеры                'red' // Цвет               );  dY= -100; function Menu() {  Mouse.updPosition(scene);   dY+= dY > 0 ? 0 : 1;    if (Mouse.Click && Mouse.onNode(newGame)) {   newGame.color= 'white';   SetActivEngine(Game);  }     if (Mouse.Click && Mouse.onNode(exitGame)) {   exitGame.color= 'white';   ExitGame();  }    scene.DrawTextOpt(                     170, 100+dY, // Позиция                   'Rect Game', // Текст                   'bold 30px sans-serif', // Шрифт (аналогично CSS)                   'white', // Цвет текста                   'green', // Цвед обводки                   6 // Толщина обводки                   );                                                         newGame.setPosition(120, 200+dY);                     newGame.Draw(scene);   exitGame.setPosition(370, 200+dY);                     exitGame.Draw(scene);     scene.DrawText(90, 190+dY,  // Позиция                'Новая игра'); // Текст  scene.DrawText(350, 190+dY,  // Позиция                'Bыход'); // Текст    }  function GameOver() {  Mouse.updPosition(scene);   dY+= dY > 0 ? 0 : 1;    if (Mouse.Click && Mouse.onNode(newGame)) {   newGame.color= 'white';   SetActivEngine(Game);  }     if (Mouse.Click && Mouse.onNode(exitGame)) {   exitGame.color= 'white';   ExitGame();  }    scene.DrawTextOpt(                     170, 100+dY, // Позиция                   'Game Over', // Текст                   'bold 30px sans-serif', // Шрифт (аналогично CSS)                   'white', // Цвет текста                   'green', // Цвед обводки                   6 // Толщина обводки                   );                                                         newGame.setPosition(120, 200+dY);                     newGame.Draw(scene);   exitGame.setPosition(370, 200+dY);                     exitGame.Draw(scene);     scene.DrawText(90, 190+dY,  // Позиция                'Новая игра'); // Текст  scene.DrawText(350, 190+dY,  // Позиция                'Bыход'); // Текст 	 }   move= [];  move[0]= CreateSprite(     0, 200, // Позиция в игре     100, 100, // Размеры в игре     anim    // Анимация    );  move[1]= CreateSprite(     400, 200, // Позиция в игре     100, 100, // Размеры в игре     anim    // Анимация    );  me= CreateSprite(     250, 180, // Позиция в игре     100, 20, // Размеры в игре     iPhone    // Анимация    );  arr= []; count= 5;  for (var i=0; i<count; i+=1) {  arr[i]= CreateSprite(     Random(0, 450), -50, // Позиция в игре     20, 20, // Размеры в игре     apples    // Анимация    );  arr[i].speed= Random(1, 3); }  speed= 4; score= 0; gameOverScore= 0; function Game() {  Mouse.updPosition(scene);        if (gameOverScore > 10)  {    dY= -100;    SetActivEngine(GameOver);    gameOverScore= 0;   }       if (Mouse.Click && Mouse.onNode(move[0])) {   if (me.posX > 0) me.Move(-speed, 0);   }    if (Mouse.Click && Mouse.onNode(move[1])) {   if (me.posX+me.sizeX < scene.Canvas.width) me.Move(speed, 0);   }      for (var i=0; i<count; i+=1) {     if (arr[i].Collision(me)) {   score+=1; speed+=0.2;    arrNewPos(i);  }        if (arr[i].posY > me.posY) {    arrNewPos(i); gameOverScore+=1;   }        arr[i].Move(0, arr[i].speed);   arr[i].DrawAnimate(scene, 10);  }     me.Draw(scene);    scene.DrawTextOpt(                     5, 5, // Позиция                   'Игровой счет: '+score, // Текст                   'bold 25px sans-serif', // Шрифт (аналогично CSS)                   'white', // Цвет текста                   'green', // Цвед обводки                   3 // Толщина обводки                   );                      move[0].Draw(scene, 1); move[1].Draw(scene, 2);    dbg(gameOverScore); }   function arrNewPos(_i) { 	arr[_i].setPosition(Random(0, scene.Canvas.width-arr[_i].sizeY),                       -Random(50, 300));  arr[_i].speed= Random(2, 5);   }   startGame(Menu, 30); </script>  </body> </html> 

Разработка игры окончена. Осталось запустить ее на Android. Для этого я скачал и установил Intel XDK, прошел регистрацию, верифицировал данные, и создал новый проект. Передо мной открылось окно нового проекта.

Выбрал я пустой (blank) HTML5 документ, и сохранил проект.

После чего открыл его в файловом менеджере, и заменил все файлы в папке проекта WWW на свои, а там у меня всего одна папка с картиной, папка с движком и файл index.html, Intel XDK тут же подхватила этот файл и предложила мне открыть его для редактирования. Я его открыл и перешел в режим эмуляции:

Посмотреть

image

Все работает как надо, ничего не глючит.

Далее открыл вкладку с проектом и ввел необходимые данные, такие как версия программы, название, аписание, иконка и т.д. Заполнив все необходимые данные — я прошел с вежливого приглашения XDK во вкладку Build, и выбрал Build for Android, после чего мой проект выгрузился на сервер, откомпилировался, а система предоставела мне удобную ссылку для загруки уже готового apk файла.

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

Кстати, таким же образом я собрал еще одну игрушку (на том же J2ds)

Показать скриншот

image

Любой желающий так же может скачать APK файл и протестировать ловлю яблочек айфоном: Скачать APK файл

А так же попрыгать в небольшой 2D игрушке по платформам и понаблюдать красивый задний фон: Скачать APK или Запустить и поиграть в браузере

Если запускаете в браузере, то работает опять же — и на компах и на планшетах/смарфонах.

Видео всей работы

ссылка на оригинал статьи http://habrahabr.ru/post/265033/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *