続きモノのエントリです。
・前回(【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内で公開しています。
よかったら参考にしてみてください。

