スキップしてメイン コンテンツに移動

Androidのアプリを はじめて作ってみる #8 シェイクイベント取得

シェイクイベントを取得して、コマの配列のシャッフルを実行するようにします。

加速度センサーとか、使うみたいです。未知の領域です。。できるんでしょうか…。

やってみます。

センサーのイベントを取れるようにする

Androidでは、SensorEventListener を実装するコトでセンサーのイベントが取れる様になります。”イベントリスナーを実装する”っていい方になるようです。

MainActivity.java

public class MainActivity extends ActionBarActivity implements SensorEventListener {

// ゲームビューのインスタンス
private GameView gameView;

// センサーマネージャ
private SensorManager mSensorManager;

// シェイク判定用のメンバー変数
private float beforeX;
private float beforeY;
private float beforeZ;
private long beforeTime = -1;   // 前回の時間

private float shakeSpeed = 80;  // 振ってると判断するスピード
private float shakeCount = 0;   // 振ってると判断した回数

これで、イベントが取れるようになります。実装に必要なメンバー変数を追加しています。

SensorManager がセンサーのオブジェクトを操作するオブジェクト、肝心なやつですね。これは後で onCreate でインスタンスを作っていきます。

SensorEventListener を指定することで、センサーのイベントが取れる様になります。今回は onSensorChanged を使ってシェイクしているかを判断していきます。

@Override
public void onAccuracyChanged(Sensor sensor, int accuracy){
    // 未使用
}

@Override
public void onSensorChanged(SensorEvent event){
    // 色々実装していきます。

その前に、センサーオブジェクトの準備をしておきます。

センサーを登録する

まず、センサーマネージャを生成します。

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // ゲームビューのインスタンス作成
    gameView = new GameView(this);

    // センサーマネージャのインスタンス作成
    mSensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);

    // ツールバーを非表示
    requestWindowFeature(Window.FEATURE_NO_TITLE);

    // ゲームビューを表示
    setContentView(gameView);
}

onCreate で生成していきます。シェイクした時に、GameView のシャッフル関数と再描画を呼び出したかったので、GameView のインスタンスをメンバで持つように変えています。

で、onResume で、センサーオブジェクトを登録する、ってことをやります。

@Override
protected void onResume(){
    super.onResume();

    // 加速度センサーのオブジェクト取得
    List<Sensor> sensors = mSensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER);

    // センサーを登録
    if(sensors.size() > 0){
        Sensor s = sensors.get(0);
        mSensorManager.registerListener(this, s, SensorManager.SENSOR_DELAY_UI);
    }

    // 初期化
    beforeX = 0;
    beforeY = 0;
    beforeZ = 0;
    beforeTime = -1;
}

mSensorManager.registerListener の部分ですね。登録しないと、イベント取れないみたいです。

で、イベントを取りっぱなしにしていると、アプリが裏に行っても電池食うみたいです。恐ろしい!!!

なので、 onPause で、センサーの登録を解除しておきます。

@Override
protected void onPause() {
    super.onPause();

    // センサーの登録を解除
    if(mSensorManager != null)
        mSensorManager.unregisterListener(this);
}

mSensorManager.unregisterListener で解除できるそうです。

で、onResume / onPause については、下のページが大変参考になりました。
http://www.javadrive.jp/android/activity/index2.html

こちらのページには、事あるごとにお世話になっている気がします…。いつもありがとうございます。

で、いよいよ onSensorChanged の実装です。

@Override
public void onSensorChanged(SensorEvent event){

    switch(event.sensor.getType()){

    // 加速度センサーのイベントをハンドリング
    case Sensor.TYPE_ACCELEROMETER:

        float x = event.values[0];
        float y = event.values[1];
        float z = event.values[2];
        long nowTime = System.currentTimeMillis();

        // 最初のイベント→値を保持するのみ
        if( beforeTime == -1 ){
            beforeX = x;
            beforeY = y;
            beforeZ = z;

            beforeTime = nowTime;
            break;
        }

        // 0.5秒間隔でチェック
        long diffTime = nowTime - beforeTime;
        if( diffTime < 500 )
            break;

        // 前回の値との差から、スピードを算出
        // すみません、どうしてこれでOKなのか、不勉強でまだ理解出来ていません。。。
        float speed = Math.abs(x + y + z - beforeX - beforeY - beforeZ) / diffTime * 10000;

        // スピードがしきい値以上の場合、振ってるとみなす
        if( speed > shakeSpeed ){
            // 振ってると判断した回数が3以上、つまり1.5秒間振り続けたら、シャッフルする
            if(++shakeCount > 2){
                shakeCount = 0;

                // コマの並びをシャッフルし、再描画
                gameView.shufflePieces();
                gameView.invalidate();
            }
        }
        else {
            // 途中でフリが収まった場合は、カウントを初期化
            shakeCount = 0;
        }

        // 前回の値を覚える
        beforeX = x;
        beforeY = y;
        beforeZ = z;

        beforeTime = nowTime;

        break;
    }
} 

こんな感じです。特定の加速度が1.5秒以上キープされたらシャッフルする様にしています。

ホントは3回振ったら、とか思って実装していたのですが、勘違いでした。加速度の判断の部分がまだ不勉強で理解出来ていないのですが…、だいたい満足な動作をしています。

とりあえず振ってシャッフル、できました!!!

ただ、端末によって取れる加速度の値が大分異なるようなので…、3回タップでシャッフルってのも入れておこうかな。。

ソースコードはこちらで公開しています。
https://github.com/et79/Game15


参考

Amazon Affiliate