Извините, ничего не найдено.

Не расстраивайся! Лучше выпей чайку!
Регистрация
Справка
Календарь

Вернуться   www.boolean.name > Программирование игр для мобильных телефонов > Android

Android Разработка игр на платформе Android

Ответ
 
Опции темы
Старый 18.08.2015, 22:22   #1
Skaner
ПроЭктировщик
 
Аватар для Skaner
 
Регистрация: 30.01.2012
Сообщений: 162
Написано 40 полезных сообщений
(для 85 пользователей)
Статья о создании игры под Android за 1 час

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

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

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

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

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

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



Что ж, теперь к реализации задуманного. У меня есть всего час на разработку, с допущениями и поблажками, т.к. это первый опыт такой скоростной разработки, я приступил. Изучить 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="">
Выглядит это так:


Основной файл, в котором я подглядывал функции: 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       // Количество кадров (по горизонтали)
                 );
Пришло время поговорить об игровых состояниях.
При запуске игры запускается первое игровое состояние — Стартовое меню. Давайте с ним и поработаем.

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

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



Важно понять, что Menu() - это функция и одновременно игровое состояние. Их (состояний) может быть сколько угодно, хоть 1000.
Ниже приведен код функции «Menu()» с комментариями:
// Создание зеленого прямоугольника
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»:

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;
Они нужны для подсчета пойманных и упущенных яблочек, а так же скорости перемещения айфона.

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

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);  
}

Так же, как и Menu() и GamwOver() - Game() - это функция и одновременно игровое состояние.

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


И остался последний штрих, игру нужно запустить:
startGame(Menu, 30); // запускает игровое состояние Menu() и устанавливает сцене ограничение в 30 fps

<!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 тут же подхватила этот файл и предложила мне открыть его для редактирования. Я его открыл и перешел в режим эмуляции:


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

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

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

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



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

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

Если запускаете в браузере, то работает опять же — и на компах и на планшетах/смарфонах.
(Offline)
 
Ответить с цитированием
Эти 3 пользователя(ей) сказали Спасибо Skaner за это полезное сообщение:
ABTOMAT (18.08.2015), moka (18.08.2015), St_AnGer (19.08.2015)
Старый 18.08.2015, 22:39   #2
moka
.
 
Регистрация: 04.08.2006
Сообщений: 10,429
Написано 3,454 полезных сообщений
(для 6,861 пользователей)
Ответ: Статья о создании игры под Android за 1 час

Для такой игрушки даже 2д движок не нужен.
Разработка за 1 час - чтобы попробовать, идея не плохая, speed-coding.
Только вот теперь нужно накатать скилл так, чтобы за очень короткие сроки можно было реализовывать концепт, или хотя бы proof-of-concept, в весьма красивой обертке.

Я придерживаюсь пару визуальных правил: темно-серый фон, светлый текст, один яркий цвет в двух оттенках, например голубо-синий #0077ff и потемнее того же примерно цвета.
И минимал естественно, никаких градиентов, чаще всего все квадратиками.
А также консистентные отступы, нравятся числа 8, 16, 32.

Придерживаясь таким мелким правилам, частенько удается сделать простую но красивую визуализацию идей за несколько десятков минут.
(Offline)
 
Ответить с цитированием
Старый 18.08.2015, 22:44   #3
Nikich
Бывалый
 
Регистрация: 21.12.2011
Сообщений: 844
Написано 150 полезных сообщений
(для 275 пользователей)
Ответ: Статья о создании игры под Android за 1 час

ИМХО, ужасно, особенно для хабра. Статья почти полностью состоит из ужасного JS кода, который может лишь причинить новичку вред, но никак не помочь. Основной теме -- компиляции всего этого под мобильные устройства -- внимание практически не уделено. Зря потраченное время читателя и автора.
(Offline)
 
Ответить с цитированием
Старый 18.08.2015, 22:51   #4
Skaner
ПроЭктировщик
 
Аватар для Skaner
 
Регистрация: 30.01.2012
Сообщений: 162
Написано 40 полезных сообщений
(для 85 пользователей)
Ответ: Статья о создании игры под Android за 1 час

Дык на то и упор, что получу полезные коменты по поводу всего, к конкурсу ж готовлюсь! А что значит ужасный код на JS? Как сделать не ужасно? Можете взять любой кусок моего кода и привести его в неужасный вид? Вот за такую помощь я был бы очень благодарен. Век живи - век учись... вот и учусь)
(Offline)
 
Ответить с цитированием
Старый 19.08.2015, 11:19   #5
moka
.
 
Регистрация: 04.08.2006
Сообщений: 10,429
Написано 3,454 полезных сообщений
(для 6,861 пользователей)
Ответ: Статья о создании игры под Android за 1 час

Код да, далеко не лучший, основные проблемы:
  1. Использование движка с Basic дизайном API
  2. Стиль кода желает лучшего:
    • один пробел отступов?
    • много выражений на одной строке
    • прыгающие отступы
    • разные нотации наименований переменных/классов/методов, что создает конфузию что есть что
  3. Вообще использование движка для такой игры как уже говорил - перебор
  4. Структура файлов - много помогает дать идею о том что есть в проекте, качественно разделение кода помогает развязать спагетти
(Offline)
 
Ответить с цитированием
Ответ


Опции темы

Ваши права в разделе
Вы не можете создавать темы
Вы не можете отвечать на сообщения
Вы не можете прикреплять файлы
Вы не можете редактировать сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.


Часовой пояс GMT +1, время: 09:28.


vBulletin® Version 3.6.5.
Copyright ©2000 - 2018, Jelsoft Enterprises Ltd.
Перевод: zCarot
Style crйe par Allan - vBulletin-Ressources.com