JS:端末の傾きに応じてボールを動かす

JS:端末の傾きに応じてボールを動かすJavaScript
スポンサーリンク

この記事ではJavaScriptから加速度センサーを利用する例として、スマートフォンやタブレットなどの端末の傾きに応じて画面上のボールを動かす処理のコード例を示します。

イメージ
JS:端末の傾きに応じてボールを動かす

サンプル
端末の傾きに応じてボールを動かす
※注)上記サンプルは、スマートフォンまたはタブレットで確認できます。

いくつかの端末で試しましたが、端末の性能によっては、動作がスムーズだったりぎくしゃくしたりしていました。
最新のスマホならかなりスムーズに動くと思います。
ちなみにスマホを家の床に置いてこのサンプルを実行すれば、家の傾きも検出できるかも。(我が家は傾いていました!)

加速度センサー値取得の基本をご覧になりたい方は、以下を参考にして下さい。

JS:JavaScriptでスマートフォンの傾きを検出する
JavaScriptを使うとスマートフォンやタブレットの傾きを検出できます。この記事では、deviceorientationイベントを使って加速度センサーの値をブラウザ上に表示させてみます。
スポンサーリンク

ボールが動いているように見せる考え方

今回のプログラムは以下のイメージで動いているように見せています。
JS:端末の傾きに応じてボールを動かす

プログラム自体は、大きく3つに分けました。

1.加速度センサー値を取得する部分(deviceorientationイベント)
2.ボールクラス(Ballクラス)
3.ボールをアニメーションさせる部分(関数mainLoop)

ボールのアニメーション処理は、requestAnimationFrame関数を利用してゲームループ(無限ループ)にします。
加速度センサーのイベント(deviceorientationイベント)で取得した値をBallクラスで定義されたボールのxy座標に加算して動いているように見せます。

以下でそれぞれ詳しく説明します。

加速度センサー値を取得する部分(deviceorientationイベント)

加速度センサー値の取得は、deviceorientationイベントを利用します。
加速度センサー値のプロパティには3方向あり、alpha, beta, gammaとなります。
今回のボールを端末の傾きに応じて動かす処理の場合だと、betagammaプロパティだけで十分です。

また、取得した加速度センサーの値を別の関数やクラスから利用するため、xとyのプロパティを持つグローバル変数vecを定義してdeviceorientationイベント発生時に加速度センサー値を変数vecに代入するようにします。

実際のJavaScript部分です。

/*
 * グローバル変数
 */
var vec = {x: 0, y: 0 };	// 加速度センサー値格納用

/*
 * 加速度センサーの値を取得
 */
window.addEventListener("deviceorientation", function(e){
	vec.x = e.gamma;	// x方向の移動量
	vec.y = e.beta;		// y方向の移動量
}, false);

ただ実際にボールを動かしてみるとかなり速い動きだったので、サンプルでは、取得した値を減らしてゆっくりとした動きに変えています。(単純にgammaとbetaを5で割って利用しているだけですが…)

こんな感じ。

/*
 * 加速度センサーの値を取得
 */
window.addEventListener("deviceorientation", function(e){
	vec.x = e.gamma / 5;	// x方向の移動量: そのままでは大きい為、小さくする
	vec.y = e.beta / 5;	// y方向の移動量:         〃
}, false);

ボールクラス(Ballクラス)

Ballクラスは、キャンバス上にボール(のようなただの塗りつぶし円)を表示するためのクラスです。

/*
 * ボールクラス
 */
class Ball{
	constructor(x, y, r){
		this.x = x;	// x座標
		this.y = y;	// y座標
		this.r = r;	// 半径
	}
	draw(){
		// 位置を計算
		this.x += vec.x;
		this.y += vec.y;
		// 円を描画(塗りつぶし円)
		g.beginPath();
		g.fillStyle = "orange";
		g.arc(this.x, this.y, this.r, 0, Math.PI*2, false);
		g.fill();
	};
};

ボールの初期位置半径をコンストラクタの引数x, y, rで設定しています。

constructor(x, y, r){
	this.x = x;	// x座標
	this.y = y;	// y座標
	this.r = r;	// 半径
}

ボールの表示は、drawメソッドを使います。

draw(){
	// 位置を計算
	this.x += vec.x;
	this.y += vec.y;
	// 円を描画(塗りつぶし円)
	g.beginPath();
	g.fillStyle = "orange";
	g.arc(this.x, this.y, this.r, 0, Math.PI*2, false);
	g.fill();
};

ポイントは、ボールの位置を計算している部分です。
HTMLのcanvasタグのx座標とy座標に加速度センサーのプロパティ値を照らし合わせると

x座標加速度センサーのgammaプロパティ
y座標加速度センサーのbetaプロパティ

がベストでした。
という訳で、

ボールのx座標 = 現在のx座標 + 加速度センサーのgamma値
ボールのy座標 = 現在のy座標 + 加速度センサーのbeta値

という計算をしてボールが加速度センサーの傾きに応じて動いているように見せることが出来ました。

ソースコードでは以下の部分です。

// 位置を計算
this.x += vec.x;
this.y += vec.y;

ボールをアニメーションさせる部分(関数mainLoop)

最後にアニメーション処理をして、ボールの一定間隔での表示を行います。

アニメーション表示には、関数をブラウザのリフレッシュレートに合わせて実行させるrequestAnimationFrame関数を使います。
例えば、mainLoopという関数を一定間隔で実行したいときは、

function mainLoop(){
	// 実行したい処理
	//	:

	// 再帰呼び出し
	requestAnimationFrame(mainLoop);
}

といった再帰呼び出し(関数内で自らを呼び出す)という方法をとります。

今回この関数で実行したい処理は、
キャンバスの画面クリアボールを描画する処理の2つです。
キャンバスの長方形塗りつぶし命令のfillRectとBallクラスのdrawメソッドを利用して以下のようにしています。

/*
 * ゲームループ
 */
function mainLoop(){
	// 画面クリア
	g.fillStyle = "#ddd";
	g.fillRect(0, 0, canvas.width, canvas.height);

	// ボールを描く
	ball.draw();

	// 再帰呼び出し
	requestAnimationFrame(mainLoop);
}

プログラム全体

プログラム全体を示します。
プログラムファイルは、index.html(HTML部分)main.js(JavaScript部分)に分かれています。

どうでしょうか?
動きましたか?加速度センサーを利用して何が出来るか考えてみるのも面白いですよ!
ぜひプログラミングを楽しんで下さい。

コメント