2015-08-06

加速度センサーを使った Android アプリの作成

スポンサーリンク

関連記事


前回作成したアニメーションを使った Android アプリはボールの動きをユーザが操作できるものではありませんでした。今回は加速度センサーを使ってスマートフォンを傾けた方向にボールが転がるようなアプリを作成します。

縦画面固定にする


初めに、スマートフォンを傾けたときに自動で画面が縦横切替してしまわないように縦画面固定の設定をします。縦画面の固定には以下の一文を "AndroidManifest.xml" に追記します。
activity android:screenOrientation="portrait"
※ 横画面固定の場合は "portrait" の部分を "landscape" に変更します。
  • "AndroidManifest.xml" を以下の通り書き換え(赤字の部分を追記)
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android=
    "http://schemas.android.com/apk/res/android"
    package="com.example.ball" >
    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait" >
            <intent-filter>
                <action android:name=
                    "android.intent.action.MAIN" />
                <category android:name=
                    "android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>
</manifest>

Ball クラスの変更


Ball クラスにボールが転がる速度を表すメンバ変数を追加します。
  • "Ball.java" を以下の通り書き換え
public class Ball extends View{
    int x, y, radius;
    float vx, vy;
    Paint paint;

    public Ball(Context context) {
        super(context);
        radius = 30;
        vx = vy = x = y = 0;
        paint = new Paint();
        paint.setColor(Color.WHITE);
        paint.setStyle(Paint.Style.FILL);
    }
    protected void onDraw(Canvas canvas){
        super.onDraw(canvas);
        canvas.drawCircle(x, y, radius, paint);
    }
}

加速度センサーの値を取得する


SensorEventListener インタフェースの実装


加速度センサーの値を取得するには MainActivitySensorEventListener インタフェースを実装します。複数のインタフェースを実装するには以下のようにカンマで区切って記述します。
public class MainActivity extends Activity implements Runnable, SensorEventListener {
    ...
}

SensorManager でセンサーのオブジェクトを取得


アプリでセンサーを利用するには SensorManager を取得します。SensorManager を取得したら getSensorList() メソッドで指定したセンサーのオブジェクトを取得します。
SensorManager manager = (SensorManager)getSystemService(SENSOR_SERVICE);
List<Sensor> sensors = manager.getSensorList(Sensor.TYPE_ACCELEROMETER);

指定できるセンサーの種類は以下があります。
TYPE_ACCELEROMETER 加速度センサー
TYPE_TEMPATURE 温度センサー
TYPE_LIGHT 照度センサー
TYPE_GRAVITY 重力センサー
TYPE_PRESSURE 圧力センサー
TYPE_MAGNETIC_FIELD 地磁気センサー
TYPE_PROXIMITY 近接センサー
TYPE_GYROSCOPE ジャイロスコープ
TYPE_LINEAR_ACCELERATION 直線加速度センサー
TYPE_ROTATION_VECTOR 回転ベクトル

具体的なセンサー値をアプリ内で利用するため onResume() メソッドにセンサー値が変化したことを検知するリスナの登録をします。
@Override
protected void onResume() {
    super.onResume();
    manager = (SensorManager)getSystemService(SENSOR_SERVICE);
    List<Sensor> sensors =
            manager.getSensorList(Sensor.TYPE_ACCELEROMETER);
    if (0 < sensors.size()) {
        manager.registerListener(
            this, sensors.get(0), SensorManager.SENSOR_DELAY_NORMAL);
    }
}

登録したリスナは onPause() メソッドで解除します。
@Override
protected void onPause() {
    super.onPause();
    manager.unregisterListener(this);
}

加速度センサー値の処理


加速度センサーの値に変化があった場合の処理を onSensorChanged() メソッドに記述します。ここでは x 軸と y 軸方向(スマートフォンを縦に持った場合の水平方向と鉛直方向)のセンサー値を使っています。
@Override
public void onSensorChanged(SensorEvent event) {
    gx = event.values[0];
    gy = event.values[1];
}


MainActivity の変更


以上を踏まえ MainActivity を以下の通り変更します。run() メソッドには、加速度センサーから得られた加速度を使ってボールの速度と位置を算出する計算式が出てきますが、詳細な説明は物理学の教科書に譲ります。
public class MainActivity extends Activity implements Runnable, SensorEventListener {
    SensorManager manager;
    Ball ball;
    Handler handler;
    int width, height, time;
    float gx, gy, dpi;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getWindow().addFlags(
                WindowManager.LayoutParams.FLAG_FULLSCREEN);
        requestWindowFeature(Window.FEATURE_NO_TITLE);
        LinearLayout linearlayout = new LinearLayout(this);
        linearlayout.setBackgroundColor(Color.GREEN);
        setContentView(linearlayout);

        time = 10;
        handler = new Handler();
        handler.postDelayed(this, 3000);
        dpi = getResources().getDisplayMetrics().densityDpi;

        WindowManager windowManager =
            (WindowManager) getSystemService(WINDOW_SERVICE);
        Display display = windowManager.getDefaultDisplay();
        width = display.getWidth();
        height = display.getHeight();
        ball = new Ball(this);
        ball.x = width / 2;
        ball.y = height / 2;
        linearlayout.addView(ball);
    }
    @Override
    public void run() {
        ball.vx += (float) (-gx * time / 1000);
        ball.vy += (float) (gy * time / 1000);
        ball.x += dpi * ball.vx * time / 25.4;
        ball.y += dpi * ball.vy * time / 25.4;

        if (ball.x <= ball.radius) {
            ball.x = ball.radius;
            ball.vx = -ball.vx / 3;
        } else if (ball.x >= width - ball.radius) {
            ball.x = width - ball.radius;
            ball.vx = -ball.vx / 3;
        }
        if (ball.y <= ball.radius) {
            ball.y = ball.radius;
            ball.vy = -ball.vy / 3;
        } else if (ball.y >= height - ball.radius) {
            ball.y = height - ball.radius;
            ball.vy = -ball.vy / 3;
        }
        ball.invalidate();
        handler.postDelayed(this, time);
    }
    public void onDestroy() {
        super.onDestroy();
        handler.removeCallbacks(this);
    }
    @Override
    protected void onResume() {
        super.onResume();
        manager = (SensorManager)getSystemService(SENSOR_SERVICE);
        List<Sensor> sensors =
            manager.getSensorList(Sensor.TYPE_ACCELEROMETER);
        if (0 < sensors.size()) {
            manager.registerListener(
                this, sensors.get(0), SensorManager.SENSOR_DELAY_NORMAL);
        }
    }
    @Override
    protected void onPause() {
        super.onPause();
        manager.unregisterListener(this);
    }
    @Override
    public void onSensorChanged(SensorEvent event) {
        gx = event.values[0];
        gy = event.values[1];
    }
    @Override
    public void onAccuracyChanged(
            Sensor sensor, int accuracy) {
    }
}

実機にインストールして実行すると、実機を傾けた方向にボールが転がることが確認できます。次はボールを転がす目標を設置してゲームらしく仕上げます
スポンサーリンク

3 件のコメント:

  1. 転がるボールのスピードを遅くすることはできますか?

    返信削除
  2. アプリ開発2017/08/15 17:52

    もちろんできますよ。
    ボールの速度を計算している箇所を変更するだけです。

    返信削除
  3. 上記のMainActivityをそのまま実装すると  SensorEventListener インタフェースを追記するところでエラー(Cannot resolve symbol "SensorEventListener" )と出て以降同様なエラーが多数発生するのですが解決策を教えてください。
    前回の”アニメーションを使った Android アプリの作成”では問題なく動作しました。

    返信削除