Edited at
phina.jsDay 14

phina.jsで加速度センサーを使ったミニゲームを作る

More than 1 year has passed since last update.


はじめに

この記事では、phina.jsのv0.2を使用しています。

https://cdn.rawgit.com/phi-jp/phina.js/v0.2.0/build/phina.js

14日目埋まらないなー、誰か埋めないかなー?と思いながら結局埋まらなかったので、自分が書くことにしました。

といっても、ネタがなくて、しばらく過去サンプルを眺めてました。

ちょうど目に止まった加速度センサーのサンプルが、あったので、あんまり加速度センサーの紹介してる人いないからということで加速度センサーでミニゲームを作ることにしました。


作ったゲーム

穴に落ちないようにGOALを目指すゲームです。

https://goo.gl/lrrTsL

runstantじゃなくて、runstant liteなのは、別ドメインのiframeだと何故かiPhoneで加速度センサーの値が取れないからです。


コードの解説

1時間ぐらいで作ったので、コードが汚いのとゲームの難易度が結構高いです。


加速度センサーの処理の部分

app.accelerometerで加速度センサーの情報が取得できます。

名前がややこしくてスペルがわかりにくいので、適当にメモっといてコピペしましょう。

重力センサーの情報は

app.accelerometer.gravityに入ってます。

あと回転情報とかもあったと思いますが、思い出せないので、気になる方はphina.jsのソースコード読んでみてください。

https://github.com/phi-jp/phina.js/blob/develop/build/phina.js


// 加速度センサーを使うよ
var accel = app.accelerometer;
// 重力情報
var gravity = accel.gravity;

var player = this.player;

// 重力の半分移動
player.x += gravity.x / 2;
player.y += -gravity.y / 2;

このgravityというやつは、重力を普通に受けているときにx,y,zがそれぞれ約9.8になります。

思いっきり振ったりすると100とかになります。

スマホだと、画面を上に向けて地面に水平で動かしてないときは

x = 0

y = 0

z = 9.8

画面を下にすると

x = 0

y = 0

z = -9.8

完全に右に向けている場合

x = 9.8

y = 0

z = 0

完全に左に向けている場合

x = -9.8

y = 0

z = 0

完全に上に向けている場合

x = 0

y = -9.8

z = 0

完全にスマホを逆さに持っている場合

x = 0

y = 9.8

z = 0

になります。


app.keyboard.getKeyAngle()

加速度センサー関係ないですが、PCで動作確認するとき用にキーボード操作に対応しました。

この関数は、十字キーの入力の角度を取得します。

右だと0

上だと90

左だと180

下だと270

同時入力ならその中間になります。

何も入力してないと数値じゃない何かが返って来ます。

なので、チェック処理が必要です。

ここからplayerを移動させる場合まず、取得した値に90を足します。

そうしないとなんかずれます。

あと適当に計算して適当にスピードを掛けると移動できます。

三角関数とかよくわからなくてもとりあえずこうしておけば動きます。

自分もよくわかってません。


var angle = app.keyboard.getKeyAngle();
if(typeof angle === 'number'){
var rad = (angle + 90).toRadian();
var cos = Math.cos(rad);
var sin = Math.sin(rad);
this.player.position.add({x: sin * 5, y: cos * 5});
}

this.player.position.addの部分は、次のようにしても良いです。


this.player.x += sin * 5;
this.player.y += cos * 5;


ロジックなどの解説

細かいところは解説しませんが、あんまり他の記事やサンプルでは見ない部分を解説します。


awake

phina.jsのElementにはawakeというプロパティがあり、通常trueですが、falseをセットするとupdateが行われなくなります。

それを利用して、今回は、プレイヤーが穴に落ちるときに穴の動きを止めるようにしています。

ana.awake = false;

これで、anaの更新がされなくなり、位置が移動しなくなります。

これで、プレイヤーが穴に落ちているのに、穴が動いて、よくわからない空間に落ちているように見えてしまうのを防いでいます。


positionに別のオブジェクトのpositionをセット

あんまり推奨できない感じのやり方ですが、当たり判定用の見えない小さい円を自分に追加して、当たり判定(hitTestElement)はその小さい円で判定するためにやっています。

なぜこうしないといけないかというと、hitTestElementpositionの数値を基準に判定しているからです。

これだとhitCircleのx,yは0になるので、画面の左上で当たることになってしまいます。

@alkn203 さんのコメントの通り、当たり判定自体は、矩形で判定されています。

setBoundingType('circle')では、当たり判定で使用する座標をradiusから計算するように設定していると考えてもらうとわかりやすいかもしれません。(radius=3はwidth, heightが6ということ)


// 本当の当たり判定 (落下判定の半径)
this.hitCircle = DisplayElement({
radius: 3,
}).addChildTo(this)
// 当たり判定を円に設定
.setBoundingType('circle')
// 非表示
.hide();

// Anaが表示されているpositionと共有化
this.hitCircle.position = this.position;


組み込み関数

phina.jsの組み込み関数や既存のオブジェクトを拡張して作った関数などの解説をします。


phina.isMobile()

スマホだと true それ以外 false


Math.randint(min, max)

min 以上 max 以下の整数をランダムで返す。

実数を返す、randfloat もあります。


Math.randbool()

truefalse をランダムで返す。


Object.prototype.$extend(obj, [obj2[,,)

こういう感じのことをします。


var obj = {
x: 1,
y: 2,
};

obj.$extend({
x: 5,
y: 10,
z: 100,
});

console.log(obj);

/*
{
x: 5,
y: 10,
z: 100,
}
*/


Object.prototype.$safe(obj, [obj2[,,)

$extend との違いはすでに定義済みの場合は上書きされない点です。


var obj = {
x: 1,
y: 2,
};

obj.$safe({
x: 5,
y: 10,
z: 100,
});

console.log(obj);

/*
{
x: 1,
y: 2,
z: 100,
}
*/


Number.prototype.times

定数回ループするやつです。


(5).times(function(i){
console.log(i);
});

/*
0
1
2
3
4
*/


終わりに

コードが汚い上に、特殊なことを結構やってる気がするので、わからないことがあったら遠慮なく質問してください。

JavaScript初心者レベルの質問でも全然構いません。

むしろ上級者レベルの質問されると怖いので初心者レベルの質問のほうが大歓迎です :sweat_drops: