【Android】SurfaceViewを使ってゲームっぽいアプリを作ってみる(ゲーム内容編)


続きモノのエントリです。
前回(【Android】SurfaceViewを使ってゲームっぽいアプリを作ってみる(入力編))
前々回(【Android】SurfaceViewを使ってゲームっぽいアプリを作ってみる(基幹編))

今回はいよいよゲームに必要な機能を追加していきます。



プロジェクトは前回のもの()を使いまわします。

ゲームのルールと仕様を決める



今回はブロック崩しライクなゲームを作ってみます。
・ボールは壁に当たると跳ね返る
 ・ボールが画面下に到達したらゲームオーバー
 ・タッチ操作でバーを移動できる
 ・画面のサイズはビューのサイズを使う
 ・バーのサイズは200×40
 ・ボールのサイズは30×30

あんまり面白みがありませんね…(´・ω・`)

仕様が決まったところで、ゲームに必要なクラスを作成します。


Ballクラス、Barクラスを作成する


・Ball.java
public class Ball {
	//ボールのサイズ
	int size = 30;
	// 表示座標
	float x, y;
	// 速度
	double vx, vy;
	// 画面の幅と高さ
	int view_w, view_h;
	// 弾の生死フラグ
	boolean isLive = true;

	//コンストラクタ
	public Ball( int _x, int _y, int width, int height ){
		//初期座標をセット
		x = (float)_x;
		y = (float)_y;
		//ビューの幅と高さをセット
		view_w = width;
		view_h = height;
		vx = 10;
		vy = 10;
	}
	public void move(){
		//玉を移動
		x = x + (float)vx;
		y = y + (float)vy;

		// 壁に当たった時の処理、速度を入れ替える
		if(x > view_w - size  ){
			vx = -vx;
			x = ( view_w - size );
		}else if( x < 0 ){
			vx = -vx;
			x = 0;
		}
		if( y < 0 ){
			vy = -vy;
			y = 0;
		}else if( y > view_h ){
			isLive = false;
		}
	}
}



・Bar.java
public class Bar {
	//表示座標
	public float x, y;
	//バーのサイズ
	public final float half_size = 100;
	//コンストラクタ
	public Bar( int _x, int _y ){
		//初期座標をセット
		x = (float)_x;
		y = (float)_y;
	}
	// 右移動
	public void right(float touch_x){
		x  = touch_x - half_size;
	}
	// 左移動
	public void left(float touch_x){
		x =  touch_x - half_size;
	}
}



Ballクラス、Barクラス共に、x座標、y座標を持ちます。

Ballクラスでは
 ・座標、速度、壁のサイズを初期化
 ・ボール移動、壁にぶつかった時は速度を反転
Barクラスでは
 ・座標初期化
 ・タッチされた座標にバーを移動

といった機能をつけました。

ループ処理にボールとバーの機能を組み込む


さっそく新しく作ったクラスをSampleHolderCallBack内で使ってみます。
インスタンスの生成はsurfaceCreated内で、移動の処理はrun関数の無限ループの中に書きます。

・SampleHolderCallBack.java
public class SampleHolderCallBack implements SurfaceHolder.Callback, Runnable{

	private SurfaceHolder holder = null;
	private Thread thread = null;
	private boolean isAttached = true;

  	private long t1 = 0, t2 = 0; // スリープ用


	private float touch_x; // タッチされたx座標
	int view_w, view_h;    // SurfaveViewの幅と高さ
	Ball ball;             //ボール
	Bar  bar;              //バー

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

	@Override
	public void surfaceCreated(SurfaceHolder holder) {
		// TODO 自動生成されたメソッド・スタブ
		this.holder = holder;
		thread = new Thread(this);
		thread.start(); //スレッドを開始

		touch_x = view_w/2;
		// ボールとバーを生成
		bar  = new Bar( view_w/2 , view_h - 100 );
		ball = new Ball( view_w/2, view_h/3 ,  view_w, view_h );
	}

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

	@Override
	public void run() {
		// TODO 自動生成されたメソッド・スタブ
		// メインループ(無限ループ)
		while( isAttached ){
			t1 = System.currentTimeMillis();

			// バー移動
			if(bar.x + bar.half_size < touch_x){
				bar.right(touch_x);
			}else{
				bar.left(touch_x);
			}
			//ボール移動
			if( ball.isLive ){
				ball.move();
			}

			//衝突判定
			if( ball.y + ball.size > bar.y && ball.y < bar.y + 20  ){
				if( ball.x > bar.x  &&  ball.x < bar.x + 200 ){
					ball.vy = -ball.vy;
					ball.y  = bar.y - ball.size;
				}
			}


			//描画処理を開始
			Canvas canvas = holder.lockCanvas();
			canvas.drawColor(0,PorterDuff.Mode.CLEAR );
			Paint paint= new Paint();
	        paint.setColor(Color.WHITE);

	        if( ball.isLive ){
		        canvas.drawCircle( ball.x, ball.y, ball.size , paint);
		        paint.setColor(Color.BLUE);
		        canvas.drawRect( bar.x, bar.y , bar.x + 200 , bar.y + 20  , paint);
			}else{
				paint.setTextSize(35);
				canvas.drawText("ゲームーオーバーです", 100, 100, paint);
			}
			//描画処理を終了
			holder.unlockCanvasAndPost(canvas);

			// スリープ
			t2 = System.currentTimeMillis();
			if(t2 - t1 < 16){ // 1000 / 60 = 16.6666
				try {
					Thread.sleep(16 - (t2 - t1));
				} catch (InterruptedException e) {
				}
			}
		}
	}
	public void getTouchPoint( float x, float y ){
		touch_x = x;
	}
}



getTouchPoint関数でタッチされた座標を取得しています。

49行目~
タッチされた場所と現在のバーの位置を比較して、
バーの移動させています。

61行目~
ボールとバーの衝突判定の処理です。
ぶつかった場合はボールの速度を反転させています。

75行目~
描画処理です。Paintを使ってボールをdrawCircle、
バーをdrawRectを使って描いています。
ボールが画面外に出た時はBallの生存フラグがfalseになり、
「ゲームオーバー」という文字が表示されるようになっています。

【実行結果】
SurficeViewを使ってのゲームアプリ作成、サンプルプログラム結果01

SurficeViewを使ってのゲームアプリ作成、サンプルプログラム結果02

上記のプログラムに、スコアをカウントさせる機能をつけ、
ボールの速度を変化させるように工夫を加えたりするとよりゲームらしくなると思います。

実際に色々改造してできたアプリをGooglePlay内で公開しています。

ゲームプログラム参考例

ゲームプログラム参考例「REFLEC」


よかったら参考にしてみてください。


関連記事

コメントは受け付けていません。