今回はいくつかセンサーがある中の「加速度(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; } }