続きモノのエントリです。
・前回(【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になり、
「ゲームオーバー」という文字が表示されるようになっています。
【実行結果】
上記のプログラムに、スコアをカウントさせる機能をつけ、
ボールの速度を変化させるように工夫を加えたりするとよりゲームらしくなると思います。
実際に色々改造してできたアプリをGooglePlay内で公開しています。
よかったら参考にしてみてください。