hyoromoのブログ

iOS/AndroidもしくはCocos2dxネタを書いています

AccelerometerSensorの使い方について

今回はいくつかセンサーがある中の「加速度(accelerometer)」を使ってみました。
端末を傾けることにより、"どの方向"へ"どれだけ傾けた"かが分かります。
先に言っておくと GitHub 上に全て置きました。ブログでは部分的な解説しかしませんので、全体像はそちらで確認してください。

センサー取得

/src/jp/android/AccelerometerActivity に関して説明します。
ますは、SensorEventListener を implements します。

public class AccelerometerActivity extends Activity implements SensorEventListener

implements すると、以下のメソッドが追加されます。

// センサーの精度が変更される毎に呼び出されるメソッド #使ったことが無いので、よく分かりませんが...
public void onAccuracyChanged(Sensor arg0, int arg1) {
}

// センサーの値が変更される毎に呼び出されるメソッド
public void onSensorChanged(SensorEvent event) {
}

追加されたメソッドは置いといて、次は外で以下を定義しておきます。

private SensorManager sensorManager;

次に onCreate() メソッド内でやることを説明します。

// センサーへアクセスするために getSystemService() メソッドで SensorManager を取得
sensorManager = (SensorManager)this.getSystemService(SENSOR_SERVICE);

onResume() メソッド内ではセンサーのリスナー設定を行います。

// 加速度センサーが存在するかのチェック後、リスナー設定
List<Sensor> sensors = sensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER);
for (Sensor s : sensors) {
    sensorManager.registerListener(this, s, SensorManager.SENSOR_DELAY_NORMAL);
}

onSensorChanged() メソッド内では加速度を取得します。

public void onSensorChanged(SensorEvent event) {
    // values には float型の[x, y, z]配列が格納されています 
    accelerometerView.setBitmapMove(event.values);
}

accelerometerView は別クラスで定義している移動するためのメソッドです。
ここまでの手順で加速度が取得できます。これ以降は私が試した加速度を使ったデモの紹介となります。

加速度デモ

/src/jp/android/AccelerometerView に関して説明します。
クラス名の通り、View を継承しています。このクラスでは主に描画処理を行っています。
やりたいことは「画像を表示して、傾けた方向へ画像を移動させたい」です。
まず始めにインスタンスメソッドから説明します。

// リソースを取得
Resources resources = getResources();
// リソースであるdemo画像を読み込みます
bitmap = BitmapFactory.decodeResource(resources, R.drawable.demo);

onDraw() メソッドでは画面描画させています。AccelerometerActivity クラス側で、invalidate() メソッド呼び出しで何回も再描画させています。

Paint paint = new Paint();
// アンチエイリアスを有効にする事で、フォントを綺麗に見せる
paint.setAntiAlias(true);
paint.setColor(getResources().getColor(R.color.accelerometer));
paint.setTextSize(FONT_SIZE);
// 塗りつぶす
paint.setStyle(Style.FILL);
canvas.drawText(REAL_NAME, 0, FONT_SIZE, paint);

移動メソッドは紹介するまでも無いのですが、ここで filter を使おうとしています。

public void setBitmapMove(float[] values) {
    x -= filter(values[0]);
    y += filter(values[1]);
}
private int filter(float f) {
    return (int)f;
}

本来なら滑らかに移動させるために、"予測される加速度"を考慮する必要があるのですが、今回は特別なことはしませんでした。

まとめ

まずは加速度を実験的に使ってみましたが、思ったより手軽に実装できて楽しかったです。
これから色々なセンサーを試していきたいと思います。

参考

yamashinaの日記 - Google Androidの傾きセンサーの値によって絵を動かす
センサーを使って何をするかの参考にさせて頂きました、どうもありがとうございます。

ソース(+追記+)

ソースはGitHubを見てもらえれば良いのですが、現時点と未来で大きく改変される場合があるので、一応乗せておきます。

package jp.android;

import java.util.List;

import android.app.Activity;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.util.Log;

/**
 * 加速度センサーのデモアプリ。
 * @author hyoromo
 *
 */
public class AccelerometerActivity extends Activity implements SensorEventListener {
	private static final String TAG = "AccelermeterActivity";
	private SensorManager sensorManager;
	private AccelerometerView accelerometerView;

	@Override
    public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		Log.d(TAG, "onCreate");
		sensorManager = (SensorManager)this.getSystemService(SENSOR_SERVICE);
		accelerometerView = new AccelerometerView(this);
		setContentView(accelerometerView);
	}
	
	@Override
	protected void onResume() {
		super.onResume();
		Log.d(TAG, "onResume");

		// リスナの登録
		List<Sensor> sensors = sensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER);
		for (Sensor s : sensors) {
			sensorManager.registerListener(this, s, SensorManager.SENSOR_DELAY_NORMAL);
		}
		
	}

	public void onAccuracyChanged(Sensor arg0, int arg1) {
	}

	public void onSensorChanged(SensorEvent event) {
    	Log.v(TAG, "onSensor");
        if (event.sensor.getType() == Sensor.TYPE_ACCELEROMETER) {
        	Log.v(TAG, "acceleometer");
        	accelerometerView.setAccelerometerValues(event.values);
        	accelerometerView.setBitmapMove(event.values);
        	accelerometerView.invalidate();		// 再度、onDraw を行う
        }
	}
}
package jp.android;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.util.Log;
import android.view.View;

/**
 * 加速度センサーのデモ描画処理。
 * @author hyoromo
 *
 */
public class AccelerometerView extends View {
	private static final String TAG = "AccelerometerView";
	private static final int FONT_SIZE = 20;
	private static final String REAL_NAME = "実加速度";
	private static final String SET_NAME = "設定加速度";
	private static final String[] PAINT_STRING = {"X:", "Y:", "Z:"};
	private Bitmap bitmap;
	private static float x, y;
	private static String[] realAccelerometerString = new String[3];
	private static String[] setAccelerometerString = new String[3];

	public AccelerometerView(Context context) {
		super(context);
		Log.d(TAG, "AccelerometerView");
		
		Resources resources = getResources();
		bitmap = BitmapFactory.decodeResource(resources, R.drawable.demo);
		x = 110;
		y = 160;
		for (int i = 0; i < realAccelerometerString.length; i++) {
			realAccelerometerString[i] = PAINT_STRING[i] + 0;
		}
		for (int i = 0; i < setAccelerometerString.length; i++) {
			setAccelerometerString[i] = PAINT_STRING[i] + 0;
		}
	}

	@Override
	public void onDraw(Canvas canvas) {
		Log.d(TAG, "onDraw");
		
		// 背景を描画する
		Paint background = new Paint();
		background.setColor(getResources().getColor(R.color.background));
		canvas.drawRect(0, 0, getWidth(), getHeight(), background);
		// デモ画像を描画する
		canvas.drawBitmap(bitmap, x, y, null);
		// 加速度を表示
		Paint paint = new Paint();
		paint.setAntiAlias(true);		// アンチエイリアスを有効にする事で、フォントを綺麗に見せる
		paint.setColor(getResources().getColor(R.color.accelerometer));
		paint.setTextSize(FONT_SIZE);
		paint.setStyle(Style.FILL);
		canvas.drawText(REAL_NAME, 0, FONT_SIZE, paint);
		for (int i = 0; i < realAccelerometerString.length; i++) {
			canvas.drawText(realAccelerometerString[i], 0, FONT_SIZE * (i + 2), paint);
		}
		canvas.drawText(SET_NAME, 0, FONT_SIZE * 6, paint);
		for (int i = 0; i < setAccelerometerString.length; i++) {
			canvas.drawText(setAccelerometerString[i], 0, FONT_SIZE * (i + 7), paint);
		}
	}
	
	public void setAccelerometerValues(float[] values) {
		Log.d(TAG, "setAccelerometerValues");

		for (int i = 0; i < realAccelerometerString.length; i++) {
			realAccelerometerString[i] = PAINT_STRING[i] + values[i];
		}
		for (int i = 0; i < setAccelerometerString.length; i++) {
			setAccelerometerString[i] = PAINT_STRING[i] + filter(values[i]);
		}
	}
	
	public void setBitmapMove(float[] values) {
		Log.d(TAG, "setBitmapMove");

		x -= filter(values[0]);
		y += filter(values[1]);
	}
	
	private int filter(float f) {
		return (int)f;
	}
}