第2回 「AR画面の表示」
前回はブログの立ち上げに集中したあまり、Androidアプリの開発環境について何も書かないまま終わってしまったので、一言補足しておきたいと思います。
私の環境はEclipse上でAndroid-SDKを動かすという標準的なものです。インストール手順について、ここに詳細を書く余裕はありませんが、ウェブ上には多くの優れた解説があるので、それらを参考にしてください。たとえば、「Android SDK Eclipse インストール」などで検索し、なるべく新しい日付の解説を参照するとよいと思います。また、英語が読める人は、本家の
http://developer.android.com/sdk/index.html
も同時に参照するとよいでしょう。このサイトには Android OS に関する最新情報が書かれているので、この件に限らず、常に参照する癖をつけておくと確実です。
インストールそのものは2、3時間で終わります。仮に途中でトラブルが起こり、書かれているとおりの結果にならなかった場合でも、起こった現象やエラーメッセージをキーとしてウェブ上で検索すると、たいがいの場合、トラブルの解消方法に容易に行き当たります。
さて、本題です。
前回の「カメラ画面の表示」では、何の機能も持たず、ただひたすらカメラ画面を表示するアプリを作りました。今回は、それにもう一枚のビューを追加して、そこに画像を表示するアプリを作ってみます。追加するビューをARビューと呼べば、カメラ画面に重ねて情報を表示するわけですから、最も単純なARアプリの出来上がりというわけです。
メインのアクティビティは次のとおりです。
AimnShoot.java
package com.artiscc.aimnshoot;
import android.app.Activity;
import android.os.Bundle;
import android.view.Window;
import android.view.WindowManager;
import android.view.ViewGroup.LayoutParams;
public class AimnShoot extends Activity
{
private static final String TAG = "AimnShootMain";
private CamView mCamView = null;
private ARView mARView = null;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
mCamView = new CamView(this);
setContentView(mCamView);
mARView = new ARView(this);
addContentView(mARView, new LayoutParams(LayoutParams.FILL_PARENT,LayoutParams.FILL_PARENT));
}
}
第1回のプログラムと比較すると、ARView を追加したことにより 3 行だけ増えています。次に、新設したこの ARView クラスの内容を見てみましょう。
ARView.java
package com.artiscc.aimnshoot;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Point;
import android.view.View;
public class ARView extends View
{
private static final String TAG = "ARView";
public ARView(Context context)
{
super(context);
prepareImages();
}
@Override
public void onDraw(Canvas canvas)
{
if(bmpReticleOn != null){
canvas.drawBitmap(bmpReticleOn, coordReticle.x, coordReticle.y, null);
}
if(bmpBomb != null){
canvas.drawBitmap(bmpBomb, coordBomb.x, coordBomb.y, null);
}
}
private Bitmap bmpBomb = null;
private Bitmap bmpReticleOn = null;
private void prepareImages()
{
Resources r = getResources();
bmpBomb = BitmapFactory.decodeResource(r, R.drawable.bomb);
bmpReticleOn = BitmapFactory.decodeResource(r, R.drawable.reticleon);
setCoordBomb(new Point(300, 200));
setCoordReticle(new Point(200, 300));
}
private Point coordReticle = null;
public void setCoordReticle(Point p)
{
coordReticle = p;
invalidate();
}
private Point coordBomb = null;
public void setCoordBomb(Point p)
{
coordBomb = p;
invalidate();
}
}
各関数の内容は以下のとおりです。
- ARView(Context context)
- コンストラクタの中から prepareImages() を呼び出し、AR画面上に表示する画像をリソースからロードします。
- onDraw(Canvas canvas)
- この部分が本クラスの主要部です。invalidate() が実行されたタイミングでこの関数が呼び出され、キャンバス(AR画面)上に指定された内容を描画します。ここでは照準マーク (reticle) の画像が準備できていたら、それを指定された座標に表示し、次に、爆弾 (bomb) の画像が準備できていたら、それを指定された座標に表示します。もし画像が重なった場合は、後で描画したものの方が上になり、下の画像を隠します。
- prepareImages()
- リソースから bomb と reticleon という名前を持つ画像データをロードし、Bitmapに変換して保持します。さらに、爆弾の座標を (300, 200)、照準の座標を (200, 300) に設定します。座標は画面の左上隅から x 座標は右方向へ、y 座標は下方向へピクセル単位で数えます。
なお、これらの画像は下記のようにpng形式で作り、res > drawable-hdp の中にあらかじめ格納しておきます。bomb.png reticleon.png 格納時の Eclipse の画面は下のようになります。なお、icon.png という画像はアプリのアイコンとして使われるもので、自分で好きなアイコンを作って置き換えることができます。
- setCoordReticle(Point p), setCoordBomb(Point p)
- bmpReticleOn および bmpBomb の各表示座標を設定し、invalidate() を呼び出します。
なお、画像の描画タイミング (上記の onDraw() が呼ばれるタイミング) は重要です。この ARView クラスの内部では、invalidate() を実行すると onDraw() を呼び出すことができます。そのため、ある画像の状態(座標など)を変更した場合など、描画を更新するために invalidate() を呼び出します。
また、このクラスの外側から描画をさせたい場合には、このビューに対して postInvalidate() を実行します。これにより、その後このビューに制御が移った時点で描画が行われます。ただし、異なるスレッドからの postInvalidate() は禁止されているため、そのような場合にはメッセージハンドラを用いることになりますが、これらについては後の講義で具体例とともに説明したいと思います。
第1部 ARアプリ作成の基本
第1回: カメラ画面の表示画面上にカメラのプレビュー画像を表示し続けるだけのアプリで、ARの基本中の基本です。
第2回: AR画面の表示
カメラ画面の上にAR画面を載せ、カメラ画面上にいろいろな画像を重ね合わせます。
第3回: ジェスチャの認識
タップ、ダブルタップ、長押し、フリックなどの画面操作を認識し、対応する処理を行います。
第4回: アニメーションの表示
タイマーを用いてミサイルが目標に向かって飛んでいく単純なアニメーションを表示します。
第5回: 複雑なアニメーションの表示
ミサイルが当たった後の爆発や残像の表示など、複雑なアニメーションを表示します。
第6回: 複数の目標の扱い
同時に複数個の目標を設定し、それぞれをミサイルで撃破する枠組みを導入します。
第7回: ズーム機能の導入
ズームボタンを設置し、カメラ画面をズームして表示する機構を手作りで実装します。
第8回: ネイティブコードの利用
ズーム機構を高速化するため、C、C++ を使ったネイティブコードを導入します。