スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

SurfaceViewの使い方3:ボールを描画して動かす

はじめに


前回の記事では、SurfaceViewに対して、定期的にテキストを描画してみました。今回はよりゲームっぽさを出すために、ボール(というか、単なるCircle)をSurfaceView上に描画して、動かしてみます。また、少しだけ高度に動かすために、画面の端に来たら跳ね返るようにしたいと思います。


ボールを描画するために、今回はCanvasクラスのdrawCircleメソッドを使用します。このメソッドは、引数としてX,Y座標と半径、Paintクラスのインスタンスを受け取ると、その情報に従ってCanvas上に円を描画します。このメソッドを、前回の記事のコードのrunメソッド内で呼び出せば、定期的に円を描画できます。後は、引数に与えるX,Y座標をちょっとずつ増やすor減らす処理を行えば、あたかも移動しているように見えます。


プロジェクトの新規作成


いつものようにEclipseを起動して、新規プロジェクトを作成します。「ファイル」→「新規」→「Androidプロジェクト」を選択して、「新規Androidプロジェクト」ウィンドウを表示させます。そして以下を設定します。



  • プロジェクト名:SampleSurViewCycle

  • ビルド・ターゲット:Android 1.6

  • アプリケーション名:Sample Surface View Cycle

  • パッケージ名:jp.sample.SampleSurViewCycle

  • Create Activity:SampleSurViewCycle


リソースレイアウトの修正


今回もリソースレイアウトmain.xmlファイルは使用しないため、修正は無しです。


ソースコードの修正


今回は、前回の記事で用いたソースコードをベースとします。まずは、全体のソースコード。


package jp.sample.SampleSurViewCycle;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class SampleSurViewCycle extends Activity {
// スレッドクラス
Thread mainLoop = null;
// 描画用
Paint paint = null;

// SurfaceViewを描画するクラス
class DrawSurfaceView extends SurfaceView implements SurfaceHolder.Callback, Runnable{
// 円のX,Y座標
private int circleX = 0;
private int circleY = 0;
// 円の移動量
private int circleVx = 5;
private int circleVy = 5;

public DrawSurfaceView(Context context) {
super(context);
// SurfaceView描画に用いるコールバックを登録する。
getHolder().addCallback(this);
// 描画用の準備
paint = new Paint();
paint.setColor(Color.WHITE);
// スレッド開始
mainLoop = new Thread(this);
mainLoop.start();
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO 今回は何もしない。
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
// SurfaceView生成時に呼び出されるメソッド。
// 今はとりあえず背景を白にするだけ。
Canvas canvas = holder.lockCanvas();
canvas.drawColor(Color.BLACK);
holder.unlockCanvasAndPost(canvas);
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO 今回は何もしない。
}

@Override
public void run() {
// Runnableインターフェースをimplementsしているので、runメソッドを実装する
// これは、Threadクラスのコンストラクタに渡すために用いる。
while (true) {
Canvas canvas = getHolder().lockCanvas();
if (canvas != null)
{
canvas.drawColor(Color.BLACK);
// 円を描画する
canvas.drawCircle(circleX, circleY, 10, paint);
getHolder().unlockCanvasAndPost(canvas);
// 円の座標を移動させる
circleX += circleVx;
circleY += circleVy;
// 画面の領域を超えた?
if (circleX < 0 || getWidth() < circleX) circleVx *= -1;
if (circleY < 0 || getHeight() < circleY) circleVy *= -1;
}
}
}

}

// アクティビティが生成されたときに呼び出されるメソッド
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new DrawSurfaceView(this));
}

@Override
public void onDestroy() {
super.onDestroy();
Thread.interrupted();
}
}

ボールの描画は、canvas.drawCircle(circleX, circleY, 10, paint);の部分で行います。単に円を単色で描画しているだけですが。


また、ボールの移動をさせるために、ソースコードでは、circleXとcircleYを変更します。


// 円の座標を移動させる
circleX += circleVx;
circleY += circleVy;

こうしておけば、次にrunメソッドが実行されて、canvas.drawCircleメソッドが実行されたときに、前回より少し移動したボールが描画されます。


また、このままでは画面外までボールが移動してしまうため、画面の端に到達したら、跳ね返るようにします。これは、ソースコードの


// 画面の領域を超えた?
if (circleX < 0 || getWidth() < circleX) circleVx *= -1;
if (circleY < 0 || getHeight() < circleY) circleVy *= -1;

getWidth()で画面の幅を、getHeight()で画面の高さを取得できますので、これらのメソッドを利用してcircleXとcircleYが画面内かどうかを判定しています。画面外となる場合は、ボールを移動させる方向を逆方向にします。


実行結果


SurfaceView_04_drawCircle.png


実行すると、白いボールが画面左上から右下へ移動していきます。どんどん右下へ移動していき、画面端までたどり着くと、壁に跳ね返ったように移動していきます。


なお、このプログラムを終わらせるためには、「←」ボタンを押します。


おわりに


SurfaceView上にボールを描いて移動させることで、けっこうゲームチックな感じになってきたと思います。ただし、このままでは単にボールが勝手に反射しているだけなので、何も楽しくありません。なので、次は、ユーザからの操作を受け付けて、ボールの動きを変えるようなプログラムを作っていきたいと思います。




テーマ : プログラミング
ジャンル : コンピュータ

SurfaceViewの使い方2:定期的な描画

はじめに


前回の記事では、SurfaceViewをとりあえず使ってみる、というところまでやりました。ただし、SurfaceViewの本領を発揮するためには、やはり定期的に再描画を行わせないといけないと思います。今回は、SurfaceView+定期的な描画、というプログラムを作成してみます。


いろいろなサイトをめぐってみると、SurfaceViewと描画の組み合わせで良く用いられているのは、「Runnableインターフェース」と、「Threadクラス」のようです。


今回も、@IT「SurfaceViewならAndroidで高速描画ゲームが作れる」にあるサンプルコードを参考にしたいと思います。参考にするコードは「GameSampleWithSurfaceView.java」です。


プロジェクトの新規作成


いつものようにEclipseを起動して、新規プロジェクトを作成します。「ファイル」→「新規」→「Androidプロジェクト」を選択して、「新規Androidプロジェクト」ウィンドウを表示させます。そして以下を設定します。



  • プロジェクト名:SampleSurViewCycle

  • ビルド・ターゲット:Android 1.6

  • アプリケーション名:Sample Surface View Cycle

  • パッケージ名:jp.sample.SampleSurViewCycle

  • Create Activity:SampleSurViewCycle


リソースレイアウトの修正


今回もリソースレイアウトmain.xmlファイルは使用しないため、修正は無しです。


ソースコードの修正


ソースコードSampleSurViewCycle.javaファイルを修正していきます。基本的には前回の記事のコードをベースとしていきます(SurfaceViewを使用するのは前回と一緒なので)。今回は、そのコードに、定期的に描画するためのコードのみを追加したいと思います。まずは、ソースコードの全体を以下に示します。


package jp.sample.SampleSurViewCycle;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class SampleSurViewCycle extends Activity {
// スレッドクラス
Thread mainLoop = null;
// 描画用
Paint paint = null;
// デバッグ用
int count = 0;

// SurfaceViewを描画するクラス
class DrawSurfaceView extends SurfaceView implements SurfaceHolder.Callback, Runnable{

public DrawSurfaceView(Context context) {
super(context);
// コンストラクタ。SurfaceView描画に用いるコールバックを登録する。
getHolder().addCallback(this);
// 描画用の準備
paint = new Paint();
paint.setColor(Color.BLUE);
paint.setAntiAlias(true);
paint.setTextSize(24);
// 加えて、スレッドを開始する
// 引数にはDrawSurfaceView、自分自身のインスタンスを渡す(Runnableをimplementsしていないといけない)。
mainLoop = new Thread(this);
// スレッドスタート。そうすると、runメソッドが実行される。
mainLoop.start();
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// TODO 今回は何もしない。
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
// SurfaceView生成時に呼び出されるメソッド。
// 今はとりあえず背景を白にするだけ。
Canvas canvas = holder.lockCanvas();
canvas.drawColor(Color.WHITE);
holder.unlockCanvasAndPost(canvas);
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// TODO 今回は何もしない。
}

@Override
public void run() {
// Runnableインターフェースをimplementsしているので、runメソッドを実装する
// これは、Threadクラスのコンストラクタに渡すために用いる。
while (true) {
Canvas canvas = getHolder().lockCanvas();
if (canvas != null)
{
canvas.drawColor(Color.WHITE);
canvas.drawText("count = " + count, 0, paint.getTextSize(), paint);
count++;
getHolder().unlockCanvasAndPost(canvas);
}
if (count == 100) {
break;
}
}
}

}

// アクティビティが生成されたときに呼び出されるメソッド
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(new DrawSurfaceView(this));
}

@Override
public void onDestroy() {
super.onDestroy();
Thread.interrupted();
}
}

ポイント1として、DrawSurfaceViewクラスでRunnableインターフェースをimplementsしている点です。このインターフェースをimplementsすると、runというメソッドを実装します。これは、後述するThreadクラスをインスタンス化して、startさせると呼び出されるメソッドです。ここで、定期的に描画するコードを記載すると、SurfaceViewに定期的な描画が可能となります。リアルタイムOSで言うタスクのコードをrunメソッドに記載すれば良いイメージ?


なので、上記のコードのrunメソッドでは、while (true) で無限ループさせています。whileループ内では、PaintクラスとCanvasクラスのインスタンスを用いて、テキストをSurfaceViewに描画しています。ただし、同じテキストだと書き換えられたことが分からないので、countという変数をインクリメントさせて表示させています。


後は、このrunメソッドを呼び出すスレッドを生成するだけです。これは、Threadクラスをインスタンス化して、startメソッドを呼び出すことで実現できます。インスタンス化するときに、コンストラクタの引数にRunnableインターフェースをimplementsしたクラスのインスタンスを渡すということです。コードでは、


mainLoop = new Thread(this);

の部分です。その後、mainLoop.start();を実行すると、runメソッドが呼び出されます。


実行結果


SurfaceView_02_runnable.png


今回は、定期的にカウントアップしたcount変数の値をSurfaceViewに表示させています(0~99の間)。


おわりに


今回は、SurfaceViewを用いた定期的な描画を行うサンプルプログラムを作成してみました。今回は何も考えず、定期的にテキストを描画するだけですが、runメソッドの中をいろいろ書き換えれば、画像を表示したり、それを移動させたり、あるいはキーボードイベントやタッチイベントに応じて画像を移動させることもできると思います。次は、そのあたりのプログラムを作りたいと思います。


参考サイト





テーマ : プログラミング
ジャンル : コンピュータ

SurfaceViewの使い方1

はじめに


今回からは、SurfaceViewクラスについて、調べていきます。SurfaceViewクラスは、@IT「SurfaceViewならAndroidで高速描画ゲームが作れる」にもあるように、ゲームアプリなどで、定期的に描画が必要となる場合に効果を発揮するクラスです。


今回は、まず@IT「SurfaceViewならAndroidで高速描画ゲームが作れる」にあるサンプルコード(zip圧縮したもの)を利用しようと思います。


と思いましたが、このサンプルコードには、大変親切なことにいろいろなサンプルをListViewで選択して試すことができるようで、SurfaceView導入編としては敷居が高いかも・・・と思ったので、やはりシンプルに最初から順々にやっていきます。ただし、@ITのサンプルコードは多いに参考させていただきます。参考とするコードはHello.javaです。


プロジェクトの新規作成


いつものようにEclipseを起動して、新規プロジェクトを作成します。「ファイル」→「新規」→「Androidプロジェクト」を選択して、「新規Androidプロジェクト」ウィンドウを表示させます。そして以下を設定します。



  • プロジェクト名:SampleSurView

  • ビルド・ターゲット:Android 1.6

  • アプリケーション名:Sample Surface View

  • パッケージ名:jp.sample.SampleSurView

  • Create Activity:SampleSurView


リソースレイアウト(XML)の修正


今回はリソースレイアウトを使用しないため、main.xmlファイルはデフォルトのままでOK。


ソースコードの修正


方針


SampleSurView.javaファイルをいじくっていきます。今回SurfaceViewを使用するために、メインクラスであるSampleSurViewクラスのサブクラスとして、DrawSurfaceViewクラスを作ることにします(コードの全体は以下)。このサブクラスがSurfaceViewを作って描画します。


package jp.sample.SampleSurView;

import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;

public class SampleSurView extends Activity {
// SurfaceViewを継承したサブクラス
class DrawSurfaceView extends SurfaceView implements SurfaceHolder.Callback {

public DrawSurfaceView(Context context) {
// コンストラクタ
super(context);
// SurfaceHolderを取得するために、getHolderメソッドを呼び出す
// そして、コールバックを登録するために、addCallbackメソッドも呼び出す。
getHolder().addCallback(this);
}

@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width,
int height) {
// SurfaceViewのサイズなどが変更されたときに呼び出されるメソッド。
// 今回は何もしない(ログ表示のみ)。
Log.d("SampleSurView", "surfaceChanged called.");
}

@Override
public void surfaceCreated(SurfaceHolder holder) {
// SurfaceViewが最初に生成されたときに呼び出されるメソッド
Log.d("SampleSurView", "surfaceCreated called.");

// SurfaceHolderからCanvasのインスタンスを取得する
Canvas canvas = holder.lockCanvas();
// Paintクラスのインスタンスを作る。これは、描画するときに使用する
// 色は青、アンチエイリアスON、テキストサイズ24
Paint paint = new Paint();
paint.setColor(Color.BLUE);
paint.setAntiAlias(true);
paint.setTextSize(24);
// Canvasの背景色を白で塗る
canvas.drawColor(Color.WHITE);

// Canvasに文字を書く。ここでPaintクラスのインスタンスを用いる。
// つまり、青色でテキストサイズが24でアンチエイリアスのかかった「Sample Text」を描画する
canvas.drawText("Sample Test", 0, paint.getTextSize(), paint);

// 描画が終わったら呼び出すメソッド。
holder.unlockCanvasAndPost(canvas);
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
// SurfaceViewが破棄されるときに呼び出されるメソッド
// 今回は実装しない。
Log.d("SampleSurView", "surfaceDestroyed");
}

}

/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// *注意:ここはレイアウトリソースであるR.layout.mainを使用せず、
//     SurfaceViewを継承したサブクラスDrawSurfaceViewのインスタンスを渡す。
setContentView(new DrawSurfaceView(this));
}
}

ポイント


このサブクラスは、SurfaceViewを使用するために、SurfaceViewクラスを継承(extends)します。また、SurfaceViewを使用するために、SurfaceHolder.Callbackクラスのインターフェースを実装しないといけないため、implementsします。


また、SurfaceHolder.Callbackクラスをimplementsすると、3つのメソッドsurfaceChanged、surfaceCreated、surfaceDestroyedを実装しなければなりません。今回のサンプルでは、surfaceCreatedメソッド、つまりSurfaceViewが生成されたときに呼び出されるメソッド、のみ実装しています。ここでは、SurfaceViewを白で塗りつぶして、「Sample Text」というテキストを青色で表示します。


最後に重要なポイントとしては、SampleSurViewクラスのonCreateメソッドでsetContentViewメソッドを呼んでいますが、通常はR.layout.mainというようにリソースレイアウトを指定します。しかし今回は、DrawSurfaceViewクラスのインスタンスを渡しています。今の私にはよく分かりませんが、SurfaceViewを使用する際はこれが一般的だそうです(by @IT)。


実行結果


エミュレータで起動すると、アプリが起動して以下のような実行結果となります。うまく表示できました。


SurfaceView_01_showText.png

一応アンチエイリアスはONにしていますが、見た目汚いように思います。テキストを表示するときはBMPファイルなどにしたほうが良いかも。


おわりに


今回は起動時に一度だけ描画するのみなので、SurfaceViewのありがたみがまったく分かりませんでした。次は定期的に描画するプログラムを作成してみたいと思います。


[メモ]最初、Android SDK 1.6でSurfaceViewを使用したコードを実行すると、なぜか「NullPointerException」例外が発生して実行できませんでした。いろいろ調べてみると、どうやらEclipse 64bit版をインストールしていたことが原因だったようでした。アンインストールして32bit版Eclipseをインストールすると、うまく動いたので・・・64bitアプリというのは、何かと問題があるようです。





テーマ : プログラミング
ジャンル : コンピュータ

Snow LeopardでEclipseで日本語化

Eclipseのプラグインで、Pleiades (プレアデス) という日本語化プラグインがあるのは知っていたのですが、てっきりWindowsオンリーかと思っていました。今日よくよく調べてみると、どうやらMacでもできるそうです。


参考にしたのは、THE MAN WHO WAS BORN IN TIME DAY「Eclipse 3.5 Galileo Mac版の日本語化」です。感謝!


基本的には上記手順にそっていけば大丈夫なのですが、一点、気をつけるのは、「eclipse.ini」ファイルに追加するオプション。



-javaagent:../../../plugins/jp.sourceforge.mergedoc.pleiades/pleiades.jar

とありますが、正確には「pleiades.jar」のあるパスを「-javaagent:」の後ろに記載します。私の環境では、以下のように書くことで、日本語化できました。



-javaagent:/Applications/eclipse/plugins/jp.sourceforge.mergedoc.pleiades/pleiades.jar

それにしても、こういうプラグインを無償で提供していただけるのは、とてもすばらしいですね。



テーマ : プログラミング
ジャンル : コンピュータ

Androidエミュレータのウィンドウサイズを変更する。

Xperia X10のエミュレータスキンを入手して使用していますが、デフォルトのウィンドウサイズが大きすぎて、下端がディスプレイからはみ出してしまいます。そこで、なんとかデフォルトのウィンドウサイズを変更しないと使いにくくてしょうがない。


そこで、ウィンドウの変更方法について調べてみました。まず、Eclipseのツールバーの電話マークみたいなボタンをクリックして、「Android SDK and AVD Manager」ウィンドウを開きます(以下)。


XperiaX10 emulator window size

次に、ウィンドウ右にある「Start」ボタンをクリックします。すると、Launch Optionsウィンドウが開きます(下図)。


XperiaX10 emulator window size

「Scale display to real size」にチェックを入れて、Screen Size(in)の値を変更することで、エミュレータのウィンドウサイズを変更することができます。


XperiaX10 emulator window size

後は、ウィンドウ下にある「Launch」ボタンをクリックすると、任意サイズの拡大率でウィンドウを表示できます。

テーマ : プログラミング
ジャンル : コンピュータ

プロフィール

sepiablue

Author:sepiablue
組込みソフトウェアエンジニアやってます。普段はC言語使い。
趣味はプログラミング、京都旅行で神社巡り。
AndroidアプリをMacで開発中。

最新記事
スポンサードリンク
スポンサードリンク
月別アーカイブ
カテゴリ
検索フォーム
RSSリンクの表示
リンク
QRコード
QRコード
上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。