ユーザーID パスワード

技術情報

  • FAQ よくある質問
  • 個人ユーザー向けサービスのお手続きについて

コード&コラム

第10回
ARゲームを作ってみよう(2)


前へ 1 |2 |3 |4 |5 次へ

Step1 カメラ画像へのオーバーレイと方位センサー情報の取得

ARアプリ作成の準備として、カメラ画像の表示と各センサー情報の取得を行います。カメラについては5、6回で行なった内容を、センサーについては7、8回で行なった内容が参考になります。分からない点があればそちらも参考にしてみて下さい。

1.プロジェクトの作成とManifestの設定
はじめにプロジェクの作成を行います。各設定項目は以下のように設定してください。

プロジェクト名 CompassApp
Build Target Google APIs(Android 2.2)
Application name GPSARApp
Package name com.example.gpsar
Activity GPSARApp
Min SDK Version 7

続いてAndroidManifest.xmlの設定を行います。
AndroidManifest.xmlを開きます。画面を横向きで実行するために、アプリケーションタブを開き、左下ApplicationNodesよりGPSARApp(Activity)を選択、Screenorientationの項目をlandscapeに設定します。
続けて位置情報のライブラリを使用するために、同じくApplicationNodesの追加ボタンを押し、UsesLibraryを選択、nameにcom.google.android.mapを選択します。
次にカメラ、GPSのアクセスを行うために、許可のタブを開き、追加、UsesPermissionよりandroid.permission.Camera、android.permission.ACCESS_FINE_LOCATIONの2つを登録します。

以上で下準備は完了です。それでは第5回の内容でも行なったCameraViewを作成しましょう。

2.CameraViewの作成
今回作成するARアプリではCameraViewを背景として使用します。View自体に機能を持たせることはないので特別な説明は必要無いでしょう。プロジェクトにCameraView.javaを追加し、以下の内容を記述して下さい。

package com.example.gpsarapp;

import android.content.Context;
import android.hardware.Camera;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class CameraView extends SurfaceView implements SurfaceHolder.Callback {

    private SurfaceHolder surfaceHolder;
    private Camera camera;

    // コンストラクタ
    public CameraView(Context context) {
        super(context);

        //サーフェイスホルダーの取得とコールバック通知先の指定
        surfaceHolder = getHolder();
        surfaceHolder.addCallback(this);
        // SurfaceViewの種別をプッシュバッファーに変更します
        surfaceHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
    }

    @Override
    public void surfaceCreated(SurfaceHolder surfaceholder) {
        try {
            camera = Camera.open();
            camera.setPreviewDisplay(surfaceholder);
        } catch (Exception e) {
        }
    }

    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width,
            int height) {
        // プレビューの開始
        camera.startPreview();
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        camera.setPreviewCallback(null);
        camera.stopPreview();
        camera.release();
        camera = null;
    }
}

以上でカメラを使用する準備が整いました。
それではCameraViewを背景とする処理を作成していきましょう。

3.オーバレイと方位センサー情報の取得
それでは実際にカメラ画像の上にオブジェクトの表示を行って行きましょう。Step1ではセンサーの情報を用いて簡単なコンパスを表示します。カメラ画像へのオーバーレイ表示はViewの重ね合わせによって実現します。
CameraViewは先程準備したのでARの内容を表示するARViewを作成しましょう。

まずプロジェクトにARView.javaを追加します。

package com.example.gpsarapp;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.view.View;

public class ARView extends View {

    // コンパスの描画位置を指定する
    private final float POS_COMPASSX = 20;
    private final float POS_COMPASSY = 20;

    // 向きを保持する変数
    float direction;
    public ARView(Context context) {
        super(context);
    }

    // (1)描画処理
    @Override
    protected void onDraw(Canvas canvas) {
        Paint paint = new Paint();
        paint.setAntiAlias(true);

        // コンパスを描画する
        drawCompass(canvas, paint);

    }

    // (2)コンパスの描画
    private void drawCompass(Canvas canvas, Paint paint) {
        Path path = new Path();
        path.moveTo(POS_COMPASSX, POS_COMPASSY - 20);
        path.lineTo(POS_COMPASSX + 10, POS_COMPASSY + 10);
        path.lineTo(POS_COMPASSX - 10, POS_COMPASSY + 10);
        path.moveTo(POS_COMPASSX, POS_COMPASSY - 20);
        paint.setColor(Color.RED);
        canvas.rotate(-direction, POS_COMPASSX, POS_COMPASSY);
        canvas.drawPath(path, paint);
        canvas.rotate(direction, POS_COMPASSXCOMPASSY, POS_);
    }

    // (3)センサー値の取得と再描画
    public void drawScreen(float preDirection) {
        // センサーの値から端末の向きを計算する
        direction = (preDirection + 450) % 360;
        // onDrawを呼び出して再描画
        invalidate();
    }
}

(1)描画処理
図形の描画には主にPaintクラスとCanvasクラスを使用します。Paintクラスでは描画する形式を指定します。
paint.setAntiAlias(true);ではアンチエイリアス処理を有効にしています。

(2)コンパスの描画
Pathクラスを使用してコンパスとなる三角形を描画しています。 Canvas.rotateメソッドを使用することで描画図形をdirectionの値によって回転させています。この処理により、常に北に鋭角を向ける簡易コンパスを実装します。

(3)センサー値の取得と再描画
センサーの値については後述となりますが、引数より北を0度、東を90度、南を180度、西を270度とする端末の向きを取得し、directionに格納します。本来はセンサーの値をそのまま使うことができますが、端末を傾けて使用する場合には角度が90度変化するため上記のような計算が必要になります。
また、invalidate();はonDrawを呼び出す関数となっているのでメソッドdrawScreenを呼び出すことで画面の再描画行えるという事になります。

GPSARApp.javaの内容は以下のようになります。センサーの変化によってメソッドを呼び出すため、SensorEventListenerインターフェースを実装します。

package com.example.gpsarapp;

import java.util.List;

import android.app.Activity;
import android.content.Context;
import android.hardware.Sensor;
import android.hardware.SensorEvent;
import android.hardware.SensorEventListener;
import android.hardware.SensorManager;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;

public class GPSARApp extends Activity implements SensorEventListener {

    private SensorManager sensorManager;
    private float[] accelerometerValues = new float[3];
    private float[] magneticValues = new float[3];
    List listMag;
    List listAcc;

    private ARView arView;

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // フルスクリーン指定
        getWindow().clearFlags(
                WindowManager.LayoutParams.FLAG_FORCE_NOT_FULLSCREEN);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
        requestWindowFeature(Window.FEATURE_NO_TITLE);

        // ARViewの取得
        arView = new ARView(this);

        // (1)各種センサーの用意
        sensorManager = (SensorManager) getSystemService(Context.SENSOR_SERVICE);
        listMag = sensorManager.getSensorList(Sensor.TYPE_MAGNETIC_FIELD);
        listAcc = sensorManager.getSensorList(Sensor.TYPE_ACCELEROMETER);

        // (2)Viewの重ね合わせ
        setContentView(new CameraView(this));
        addContentView(arView, new LayoutParams(LayoutParams.FILL_PARENT,
                LayoutParams.FILL_PARENT));

    }

    @Override
    public void onStart() {
        super.onStart();
    }

    @Override
    protected void onResume() {
        super.onResume();
        // (3)センサー処理の登録
        sensorManager.registerListener(this,
                listMag.get(0), SensorManager.SENSOR_DELAY_NORMAL);
        sensorManager.registerListener(this,
                listAcc.get(0), SensorManager.SENSOR_DELAY_NORMAL);

    }

    @Override
    public void onStop() {
        super.onStop();

        sensorManager.unregisterListener(this);
    }

    @Override
    public void onAccuracyChanged(Sensor sensor, int accuracy) {
    }

    // (4)センサー値の反映
    @Override
    public void onSensorChanged(SensorEvent event) {
        switch (event.sensor.getType()) {
        case Sensor.TYPE_ACCELEROMETER:
            accelerometerValues = event.values.clone();
            break;
        case Sensor.TYPE_MAGNETIC_FIELD:
            magneticValues = event.values.clone();
            break;
        }

        if (magneticValues != null && accelerometerValues != null) {
            float[] R = new float[16];
            float[] I = new float[16];

            SensorManager.getRotationMatrix(R, I, accelerometerValues,
                    magneticValues);

            float[] actual_orientation = new float[3];

            SensorManager.getOrientation(R, actual_orientation);
            // 求まった方位角をラジアンから度に変換する
            float direction = (float) Math.toDegrees(actual_orientation[0]);
            arView.drawScreen(direction);
        }
    }

}

(1)各種センサーの用意
磁気センサーと加速度センサーを用意します。

(2)Viewの重ね合わせ
最初に作成したCameraViewの上にARViewを重ねて表示します。

(3)センサー値の反映
sensorManager.registerListenerは第1引数にセンサーによって呼び出される関数を持つクラスを、第2引数に対象となる値を、第3引数に呼び出し頻度を指定します。ここでは更新の頻度に一番オーソドックスなSENSOR_DELAY_NORMALを指定しています。ゲームに使用する場合などシビアな更新が必要とされる場合にはSENSOR_DELAY_GAMEなどの値を指定することが出来ます。

(4)センサー値の反映
owSensorChangedはセンサーの値が変わる度に呼び出されるメソッドです。magneticValuesでは3軸方向の磁力密度を、accelerometerValuesでは3軸方向の加速度を取得します。この2つの値を組合わえることで端末の傾きに左右されずに方位を求めることが出来ます。また、このメソッドの中で arView.drawScreenを呼び出すことで、センサー値が更新される度にARViewの再描画を行う事が出来ます。

プログラムを実行すると、下画像のようにカメラ画像へのコンパスのオーバーレイ表示が確認出来ると思います端末の向きを変えることでコンパスの向きも変わることが確認できます。それでは位置情報を使用したARを実現するためにStep2で位置情報の管理を行う処理を作成しましょう。

img


第10回 ARゲームを作ってみよう(2)
 Step1 カメラ画像へのオーバーレイと方位センサー情報の取得 
 Step2 位置情報の取得とデータベースの作成
 Step3 可視判定とテキストの表示
 Step4 現在位置の登録

サンプルコード

第1回 リファレンスコード(文字列編)

第2回 リファレンスコード2(グラフィックス編)

第3回 リファレンスコード3(タッチイベント編)

第4回 リファレンスコード4(チェックボックス/ラジオグループ編)

第5回 リファレンスコード5(スピナー編)

第6回 リファレンスコード6(サウンド/ムービー編)

第7回 リファレンスコード7(トースト編)

第8回 リファレンスコード8(Google Maps API利用編)

第9回 リファレンスコード9(SQLite編)

第10回 リファレンスコード10(音声認識編)

第11回 リファレンスコード11(日付/時刻ダイアログ編)

第12回 リファレンスコード12(Bluetooth編)