素人プログラマ奮闘記

javaの初心者がAndroidのことを独学で勉強しつつ、メモを残していきます。

Android描画SurfaceViewを使ってみる

Androidの画面表示の基礎クラスはViewなので、動きがないアプリを作成する際は事足りるが
高度な(簡単なゲームなど)描画にはSurfaceViewクラスを使用するのがいいらしいので、少し勉強してみようと思います。
簡単に言うと、SurfaceViewとは描画用のスレッドを持った Viewのことです。

今回作成予定のソフトは、画面上にボール(円)を描画して、画面の端にぶつかったら跳ね返る動作をするソフトを作ってみようと思います。

1.SampleSurfaceViewを継承したクラスを用意する。

SampleViewTestプロジェクトを作成して
SurfaceViewを継承したSampleSurfaceViewクラスを作成します。


SampleSurfaceView.java

public class SampleSurfaceView extends SurfaceView{

	public SampleSurfaceView(Context context) {
		super(context);
		// TODO 自動生成されたコンストラクター・スタブ
	}

2.SurfaceHolderを継承したクラスを用意する。

SurfaceHolderというものは、「サーフェイス」の生成や更新、破棄などを行った際に呼び出されるコールバック機能を実装するためのインターフェイスです。
SurfaceHolderCallbackを継承したSSmpleSurfaceHolderCallbackクラスを作成します。

SampleSurfaceHolderCallback.java

public class SampleSurfaceHolderCallback implements SurfaceHolder.Callback {

	@Override
	public void surfaceChanged(SurfaceHolder holder, 
			int format, int width,int height) {
		// TODO 自動生成されたメソッド・スタブ		
	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		// TODO 自動生成されたメソッド・スタブ		
	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		// TODO 自動生成されたメソッド・スタブ		
	}

}
上記のように、SurfaceHolder.Callbackの3つのメソッドを用意する必要があります。
それぞれ以下のようなものです。
surfaceCreated――サーフェイスが生成された時のコールバック。
surfaceDestroyed――サーフェイスが破棄された時のコールバック。
surfaceChanged――サーフェイスが変更された時のコールバック。

2.Runnableを継承したSampleCanvasThreadクラスを用意する。

スレッドクラスです。SurfaceHolderを用いてCanvasを取得し画面描画をします。
Runnableを継承したSampleCanvasThreadクラスを作成します。

SampleCanvasThread.java

public class SampleCanvasThread implements Runnable {

	@Override
	public void run() {
		// TODO 自動生成されたメソッド・スタブ
		
	}

3.BallInfoクラスを用意する。

移動量、現在地、描画Paintをプロパティに持ったBallInfoクラスを作成します。
BallInof.java

ppublic class BallInfo {
	//移動量
	public float dx,dy;
	//現在座標
	public int ballx,bally;		
	//ペイント
	public Paint myPaint;	
	//ボールの半径
	public float radius;
		
	//ボールの移動
	//円のx,y座標が画面端を超える場合(0以下、または画面幅を超える)場合は符号を反転し向きを変えています。
	//radiusはボールの半径です。drawCircleに与える描画座標は円の中心の座標のため、座標+半径で円の大きさを計算しています
	public void Move(float screenWidth ,float screenHeight){
		
		if ((ballx - radius) < 0 || (ballx + radius) > screenWidth)
	    	  dx = -dx;
	      if ((bally-radius) < 0 || (bally + radius) > screenHeight)
	    	  dy = -dy;
	      ballx += dx;
	      bally += dy;
	}

4.BallInfoリストを作成する。

画面上に10個のボールを表示しようと思うので、10個分のボール情報を作成します。

SampleCanvasThread.javaのコンストラクタ

//ボールリスト作成
ballList = new ArrayList<BallInfo>();
for(int i = 0 ; i < 10; i++){
	
	BallInfo tmp = new BallInfo();			
	tmp.myPaint = new Paint();
	
	Random rnd = new Random();

	//移動距離ランダム
	int rbx = rnd.nextInt(30) + 1;
	int rby = rnd.nextInt(30) + 1;
	tmp.dx = rbx;
	tmp.dy = rby;
	
	//開始位置ランダム
	int rballx = rnd.nextInt(50) + 40;
	int rbally = rnd.nextInt(50) + 40;
	tmp.ballx = rballx;
	tmp.bally = rbally;

	//ボールの色ランダム
	int a = rnd.nextInt(255);
	int r = rnd.nextInt(255);
	int g = rnd.nextInt(255);
	int b = rnd.nextInt(255);
	//透明度、赤、緑、青を指定します。
	tmp.myPaint.setARGB(255,r, g, b);			
				
	//円半径ランダム
	int radi = rnd.nextInt(20) + 10;
	tmp.radius = radi;

	ballList.add(tmp);
}

5.描画処理を作成。

SurfaceHolderのlockCanvas画面をロック、canvasクラスを取得して、必要な描画を終了後unlockCanvasAndPostでロックを解除します。

SampleCanvasThread.javaのメソッドdoDraw

private void doDraw(SurfaceHolder holder) {
	//画面描画ロック
    Canvas canvas = holder.lockCanvas();
    if (canvas != null){
    	//まずは画面を黒く塗りつぶす
      canvas.drawColor(Color.BLACK);
      //各ボールを描画
      for ( int i = 0; i < ballList.size(); ++i ) {
    	  //cx:中心のX座標 ,cy:中心のY座標 ,radius: 円の半径 ,paint: ペイントオブジェクト
	      canvas.drawCircle(ballList.get(i).ballx, ballList.get(i).bally, ballList.get(i).radius, ballList.get(i).myPaint);	    	  
      }	      
      //画面描画ロック解除
      holder.unlockCanvasAndPost(canvas);
    }
}		

6.ループ内処理作成

Runメソッドで円の中心座標を計算する処理を呼び出します。
SampleCanvasThread.java

@Override
public void run() {
	// TODO 自動生成されたメソッド・スタブ
while (true) {
		for(int i = 0 ; i < 10; i++){
		ballList.get(i).Move(screenWidth, screenHeight);
	}	
	doDraw(holder);
}

7.スレッド生成処理

surfaceChangedイベントが発生するとき、画面描画用のスレッドを生成します。

SampleSurfaceHolderCallback.java

@Override
public void surfaceChanged(SurfaceHolder holder, 
		int format, int width,int height) {
	// TODO 自動生成されたメソッド・スタブ		
	SampleCanvasThread th = new SampleCanvasThread();		
	th.screenHeight = height;
	th.screenWidth = width;
	th.holder = holder;

	thread = new Thread(th);
	thread.start();		
}

@Override
public void surfaceDestroyed(SurfaceHolder holder) {
	// TODO 自動生成されたメソッド・スタブ
	thread=null;
}

8.MainActivityクラス修正

onCreate内でSurfaceViewクラスをNewします

MainActivity.java

@Override
protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	//setContentView(R.layout.activity_main);
	setContentView(new SampleSurfaceView(this));
}

9.SampleSurfaceViewクラス修正

SurfaceViewのクラスです。SurfaceHoloderを取得し、addCallback()メソッドを呼び出しコールバック先のクラス(MySurfaceViewCallback)を設定します。

SampleSurfaceView.java

@Override
protected void onCreate(Bundle savedInstanceState) {
	super.onCreate(savedInstanceState);
	//setContentView(R.layout.activity_main);
	setContentView(new SampleSurfaceView(this));
}

後はシミュレーションで実行してみて、動作を確認してください。画面内でボールが飛び跳ねるはずです。





カテゴリーへ
inserted by FC2 system