Это продолжение моей прошлой статьи "Создаем html5 мини-бродилку на CraftyJS". Я подумал, сейчас так много возможностей относительно просто портировать любое html5 приложение на мобильную платформы, почему бы не попробовать?
![image](https://habrastorage.org/r/w1560/storage1/9338e00f/7086a7e8/739f12e1/3e264b16.png)
Ниже, то что из этого вышло. Внимательно читаем вывод!
Нужно портировать игру бродилку на android, сделать краткий вывод статистики и управление по средствам акселерометра.
С начала, выслушав критику к прошлой статье, я убрал из index.html множественные вызовы js файлов, оставив только главные библиотеки. Для этого я подключил библиотеку requirejs. Так же я сразу подключил phonegap.js и немного изменил верстку, вот как теперь все это выглядит:
/index.html
/css/game.css
/js/game.js
Обратите внимание, что я так же изменил width и height в соответствие с разрешением мобильного телефона.
Теперь давайте займемся управлением, для это изменим /js/objects/player.js заменив компонент Fourway на FourwayAccel, а так же вызов this.fourway(1) на this.fourway_accel(1). Дальше, нам нужно создать этот самый компонент, вот он:
После вызова метода fourway_accel, мы начинаем слушать событие «Acceleration», которое мы создадим чуть позже. Данное событие передает нам данные о наклоне (x,y,z). Нас тут интересует только x и y. Для упрощения, я проверяю достаточно большой уровень наклона, меньше -2 или больше 2.
Как только наклон достиг определенного градуса, вызывается функция «start_or_stop_move», которой передается направление наклона. Данная функция, в зависимости от скорости задает направление движения игрока, которое потом отрисовывается в событие «EnterFrame».
Дальше нам нужно создать сам генератор события «Acceleration», для этого добавим следующий код в /js/game.js:
Более подробно, о работе с акселерометром в phonegap, можно прочесть в документации.
Теперь, нам нужно вызвать startWatch() в сцене /js/scenes/main.js, а так же stopWatch() в сценах win.js и lose.js
Итак, будем считать что вы уже сделал все, что описано в документации. Нужно немного подправить AndroidManifest.xml, добавив в секцию activity строчку: android:screenOrientation=«landscape». Это необходимо для того, что бы ориентация экрана всегда была альбомной.
Приводим AndroidrpgActivity.java к такому виду:
Думаю переменная FLAG_FULLSCREEN говорит сама за себя.
Вот, что у меня в итоге получилось (извините за качество):
![](https://habrastorage.org/r/w780q1/storage1/01776130/b26b4a11/5b392280/9ba0bf1a.jpg)
Работает? О да! Доволен ли я? О нет!
Дело в том, что толи я криворукий, толи лыжи не едут, но приложение получилось крайне тормазнутым. Результат больше похож на пошаговую стратегию, чем на Action. И дело тут, я думаю, все же в лыжах, ответ наверное очевиден. PhoneGap — отличная библиотека для tumblr читалок и прочих новостных ридеров, но для игрушек лучше использовать нативный для android Java.
Исходники, как обычно на GitHub.
![image](https://habrastorage.org/storage1/9338e00f/7086a7e8/739f12e1/3e264b16.png)
Ниже, то что из этого вышло. Внимательно читаем вывод!
Что нам потребуется
- PhoneGap и окружение для работы с ним (инструкция по установке)
- Проект из предидущей статьи
- Крайне желательно наличие android телефона
Задача
Нужно портировать игру бродилку на android, сделать краткий вывод статистики и управление по средствам акселерометра.
Предварительная подготовка
С начала, выслушав критику к прошлой статье, я убрал из index.html множественные вызовы js файлов, оставив только главные библиотеки. Для этого я подключил библиотеку requirejs. Так же я сразу подключил phonegap.js и немного изменил верстку, вот как теперь все это выглядит:
/index.html
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<script type="text/javascript" src="js/require.js"></script>
<script type="text/javascript" src="js/phonegap.js"></script>
<script type="text/javascript" src="js/jquery.js"></script>
<script type="text/javascript" src="js/crafty.js"></script>
<script type="text/javascript" src="js/game.js"></script>
<link rel="stylesheet" href="css/game.css" type="text/css" media="screen" charset="utf-8">
<title>Simpe RPG</title>
</head>
<body>
<div id="cr-stage"></div>
<div id="sidebar">
<div id="level">
Level:
<span>1</span>
</div>
<div id="score">
Score:
<span>0</span>
</div>
</div>
</body>
</html>
/css/game.css
body, html { margin:0; padding: 0; overflow:hidden; font-family:Arial; font-size:20px; background-color: #000; }
#cr-stage { color:white; float:left; }
#sidebar { top: 0; left: 0; width: 150px; height: 100px; position: absolute; color:white;}
#sidebar div { margin: 10px 5px; text-align: center; }
/js/game.js
var Settings = {
width: 480, // ширина игрового поля
height: 320, // высота
poligon: 16, // размер полигона 16x16
level: 1, // текущий уровень
flower_count: 0 // цветков на уровне
};
var AllScripts = [
// objects
'js/objects/flower',
'js/objects/bush',
'js/objects/grass',
'js/objects/unit',
'js/objects/fourway_accel',
'js/objects/player',
'js/objects/fourway_ai',
'js/objects/monster',
// scenes
'js/scenes/loading',
'js/scenes/main',
'js/scenes/win',
'js/scenes/lose'
];
require(AllScripts, function() {
require.ready(function() {
Crafty.init(Settings.width, Settings.height); // создаем игровое поле
// подгружаем спрайт
Crafty.sprite(Settings.poligon, "images/sprite.png", {
grass1: [0,0],
grass2: [1,0],
grass3: [2,0],
grass4: [3,0],
flower: [0,1],
bush1: [0,2],
bush2: [1,2],
player: [0,3],
monster: [0,4]
});
// запускаем первую сцену
Crafty.scene("loading");
});
});
Обратите внимание, что я так же изменил width и height в соответствие с разрешением мобильного телефона.
Акселерометр
Теперь давайте займемся управлением, для это изменим /js/objects/player.js заменив компонент Fourway на FourwayAccel, а так же вызов this.fourway(1) на this.fourway_accel(1). Дальше, нам нужно создать этот самый компонент, вот он:
Crafty.c("FourwayAccel", {
_speed: 3,
_touch_element: null,
init: function() {
this._movement= { x: 0, y: 0};
this.accels = {};
this.accels['left'] = false;
this.accels['right'] = false;
this.accels['top'] = false;
this.accels['bottom'] = false;
},
fourway_accel: function(speed) {
var self = this;
self._speed = speed;
self.bind('Acceleration', function(acceleration) {
if (acceleration.y < -2) this.start_or_stop_move('left');
if (acceleration.y > 2) this.start_or_stop_move('right');
if (acceleration.x < -2) this.start_or_stop_move('top');
if (acceleration.x > 2) this.start_or_stop_move('bottom');
});
self.bind("EnterFrame",function() {
if (self.disableControls) return;
if(self._movement.x !== 0) {
self.x += self._movement.x;
self.trigger('Moved', {x: self.x - self._movement.x, y: self.y});
}
if(self._movement.y !== 0) {
self.y += self._movement.y;
self.trigger('Moved', {x: self.x, y: self.y - self._movement.y});
}
});
return self;
},
start_or_stop_move: function(move_type) {
var move_speed = this.get_speed(move_type);
if (this.accels[move_type]) {
// stop move
this._movement.x = Math.round((this._movement.x - move_speed.x)*1000)/1000;
this._movement.y = Math.round((this._movement.y - move_speed.y)*1000)/1000;
this.accels[move_type] = false;
} else {
// start move
this.accels[move_type] = true;
this._movement.x = Math.round((this._movement.x + move_speed.x)*1000)/1000;
this._movement.y = Math.round((this._movement.y + move_speed.y)*1000)/1000;
}
this.trigger('NewDirection', this._movement);
},
get_speed: function(key_id) {
switch (key_id) {
case 'top':
return {x: 0, y: -this._speed};
case 'left':
return {x: -this._speed, y: 0};
case 'right':
return {x: this._speed, y: 0};
case 'bottom':
return {x: 0, y: this._speed};
}
}
});
После вызова метода fourway_accel, мы начинаем слушать событие «Acceleration», которое мы создадим чуть позже. Данное событие передает нам данные о наклоне (x,y,z). Нас тут интересует только x и y. Для упрощения, я проверяю достаточно большой уровень наклона, меньше -2 или больше 2.
Как только наклон достиг определенного градуса, вызывается функция «start_or_stop_move», которой передается направление наклона. Данная функция, в зависимости от скорости задает направление движения игрока, которое потом отрисовывается в событие «EnterFrame».
Дальше нам нужно создать сам генератор события «Acceleration», для этого добавим следующий код в /js/game.js:
var watchID = null;
function stopWatch() {
if (watchID) {
navigator.accelerometer.clearWatch(watchID);
watchID = null;
}
}
function startWatch() {
var options = { frequency: 200 };
watchID = navigator.accelerometer.watchAcceleration(onSuccess, onError, options);
// с помощью этого куска, можно дебажить акселерометр в хроме
// window.addEventListener('deviceorientation', function(event) {
// Crafty.trigger("Acceleration", {x: event.beta, y: event.alpha, z: event.gamma})
// }, false);
}
function onSuccess(acceleration) {
Crafty.trigger("Acceleration", acceleration)
}
function onError() {
console.log('error!');
}
Более подробно, о работе с акселерометром в phonegap, можно прочесть в документации.
Теперь, нам нужно вызвать startWatch() в сцене /js/scenes/main.js, а так же stopWatch() в сценах win.js и lose.js
Непосредственный запуск на телефоне
Итак, будем считать что вы уже сделал все, что описано в документации. Нужно немного подправить AndroidManifest.xml, добавив в секцию activity строчку: android:screenOrientation=«landscape». Это необходимо для того, что бы ориентация экрана всегда была альбомной.
Приводим AndroidrpgActivity.java к такому виду:
package com.phonegap.simplerpg;
import android.os.Bundle;
import android.view.WindowManager;
import com.phonegap.*;
public class AndroidrpgActivity extends DroidGap {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().clearFlags(WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
super.loadUrl("file:///android_asset/www/index.html");
}
}
Думаю переменная FLAG_FULLSCREEN говорит сама за себя.
Результат и вывод
Вот, что у меня в итоге получилось (извините за качество):
![](https://habrastorage.org/storage1/01776130/b26b4a11/5b392280/9ba0bf1a.jpg)
Работает? О да! Доволен ли я? О нет!
Дело в том, что толи я криворукий, толи лыжи не едут, но приложение получилось крайне тормазнутым. Результат больше похож на пошаговую стратегию, чем на Action. И дело тут, я думаю, все же в лыжах, ответ наверное очевиден. PhoneGap — отличная библиотека для tumblr читалок и прочих новостных ридеров, но для игрушек лучше использовать нативный для android Java.
Исходники, как обычно на GitHub.