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

# はじめに

この記事では、phina.jsのv0.2を使用しています。
https://cdn.rawgit.com/phi-jp/phina.js/v0.2.0/build/phina.js

14日目埋まらないなー、誰か埋めないかなー？と思いながら結局埋まらなかったので、自分が書くことにしました。
といっても、ネタがなくて、しばらく過去サンプルを眺めてました。
ちょうど目に止まった加速度センサーのサンプルが、あったので、あんまり加速度センサーの紹介してる人いないからということで加速度センサーでミニゲームを作ることにしました。

# 作ったゲーム

穴に落ちないようにGOALを目指すゲームです。
https://goo.gl/lrrTsL
[<img width="320" alt="image" src="https://qiita-image-store.s3.amazonaws.com/0/60690/452d064a-4af2-e505-b8dd-08a67b5303d7.png">
](https://goo.gl/lrrTsL)

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

# コードの解説

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

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

`app.accelerometer`で加速度センサーの情報が取得できます。
名前がややこしくてスペルがわかりにくいので、適当にメモっといてコピペしましょう。

重力センサーの情報は
`app.accelerometer.gravity`に入ってます。

あと回転情報とかもあったと思いますが、思い出せないので、気になる方はphina.jsのソースコード読んでみてください。
https://github.com/phi-jp/phina.js/blob/develop/build/phina.js

```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を足します。
そうしないとなんかずれます。
あと適当に計算して適当にスピードを掛けると移動できます。
三角関数とかよくわからなくてもとりあえずこうしておけば動きます。
自分もよくわかってません。

```js

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`の部分は、次のようにしても良いです。

```js

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`)はその小さい円で判定するためにやっています。

なぜこうしないといけないかというと、`hitTestElement`が`position`の数値を基準に判定しているからです。
これだと`hitCircle`のx,yは0になるので、画面の左上で当たることになってしまいます。

**※ @alkn203 さんのコメントの通り、当たり判定自体は、矩形で判定されています。
`setBoundingType('circle')`では、当たり判定で使用する座標を`radius`から計算するように設定していると考えてもらうとわかりやすいかもしれません。(`radius=3`はwidth, heightが6ということ)**

```js

// 本当の当たり判定 (落下判定の半径)
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()`

`true` か `false`　をランダムで返す。

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

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

```js

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` との違いはすでに定義済みの場合は上書きされない点です。

```js

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`

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

```js

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

/*
0
1
2
3
4
*/

```


# 終わりに

コードが汚い上に、特殊なことを結構やってる気がするので、わからないことがあったら遠慮なく質問してください。
JavaScript初心者レベルの質問でも全然構いません。
むしろ上級者レベルの質問されると怖いので初心者レベルの質問のほうが大歓迎です :sweat_drops: