Androidでオセロゲームを作ってみる (1)
Androidでオセロゲームを作ってみる (2) ゲームロジックの実装
Androidでオセロゲームを作ってみる (3) 思考ルーチンの実装
Androidでオセロゲームを作ってみる (4) 文字列をぐるぐる回す方法
Androidでオセロゲームを作ってみる (5) 裏返しアニメーションを付けてついに完成!
Androidアプリで2Dグラフィックスを扱う練習をしようと思う。
とりあえず簡単なものという事で、オセロ(リバーシ)ゲームを作りたい。
まずはViewを使って描画するか、SurfaceViewを使って描画するかを決めないと行けない。
GLSurfaceViewというのもあるけれどもこちらは今やろうとしている事にはオーバースペックなので置いておく。
SurfaceViewならAndroidで高速描画ゲームが作れる (1/3) - @IT
【libro】 Google androidプログラミング入門/SurfaceViewによる高速描画/SurfaceViewとは?
Graphics の基本
グラフィックス(1)-Viewクラスへの描画 - 愚鈍人
KENSINのホームページ-Androidで星が流れるプログラムを作成してみる
Viewを使った場合は大体4fpsぐらいしか出ないが、SurfaceViewだと30fpsぐらいは出るみたいだ。この差は大きい。
でも「チェスなどのボードゲームならViewで充分」という記述もよく見かけるので、今回はとりあえずViewで行こうと思う。どうしても必要なら後からSurfaceViewに変更するという事で。
まずはこんな感じで初期状態を描画してみた。それなりに見える。(笑)

横向きの場合はこんな感じになる。

カスタムビューによるグラフィック表示
Activityクラスではカスタムビューをセットするだけ。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.example.mireversi; | |
import android.app.Activity; | |
import android.os.Bundle; | |
public class GameActivity extends Activity{ | |
@Override | |
public void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setContentView(new ReversiView(this)); | |
} | |
} |
ReversiViewというカスタムビューを作ってこの中でオセロの表示処理を全て行う。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.example.mireversi; | |
import com.example.mireversi.model.Board; | |
import com.example.mireversi.model.Cell; | |
import com.example.mireversi.model.Cell.E_STATUS; | |
import android.content.Context; | |
import android.graphics.Canvas; | |
import android.graphics.Color; | |
import android.graphics.Paint; | |
import android.view.MotionEvent; | |
import android.view.View; | |
import android.widget.Toast; | |
public class ReversiView extends View { | |
private Board mBoard = new Board(); | |
public ReversiView(Context context) { | |
super(context); | |
setFocusable(true); | |
} | |
@Override | |
protected void onDraw(Canvas canvas) { | |
super.onDraw(canvas); | |
mBoard.setSize(getWidth(), getHeight()); | |
drawBoard(canvas); | |
} | |
@Override | |
protected void onSizeChanged(int w, int h, int oldw, int oldh) { | |
super.onSizeChanged(w, h, oldw, oldh); | |
} | |
@Override | |
public boolean onTouchEvent(MotionEvent event) { | |
float x = event.getX(); | |
float y = event.getY(); | |
switch (event.getAction()) { | |
case MotionEvent.ACTION_UP: | |
int r = (int)(y / mBoard.getCellHeidht()); | |
int c = (int)(x / mBoard.getCellWidth()); | |
if (r < Board.ROWS && c < Board.COLS){ | |
try { | |
mBoard.changeCell(r, c, mBoard.getTurn()); | |
mBoard.changeTurn(); | |
} catch (Exception e) { | |
//Toast.makeText(this.getContext(), e.getMessage(), 300).show(); | |
} | |
invalidate(); //画面を再描画 | |
} | |
break; | |
default: | |
return true; | |
} | |
return true; | |
} | |
private void drawBoard(Canvas canvas){ | |
int bw = mBoard.getWidth(); | |
int bh = mBoard.getHeight(); | |
float cw = mBoard.getCellWidth(); | |
float ch = mBoard.getCellHeidht(); | |
if (mBoard.getWidth() <=0 ) return; | |
Paint paint = new Paint(); //本当はここでnewするのはパフォーマンス上良くない。後で直そう。 | |
paint.setColor(Color.rgb(0, 180, 0)); | |
canvas.drawRect( 0, 0, bw, bh, paint); | |
paint.setColor(Color.rgb(40, 40, 40)); //罫線の色 | |
//縦線 | |
for (int i = 0; i < Board.COLS; i++) { | |
canvas.drawLine(cw * (i+1), 0, cw * (i+1), bh, paint); | |
} | |
//横線 | |
for (int i = 0; i < Board.ROWS; i++) { | |
canvas.drawLine(0, ch * (i+1), bw, ch * (i+1), paint); | |
} | |
//円を描く前にアンチエイリアスを指定。これをしないと円がギザギザになる。 | |
paint.setAntiAlias(true); | |
Cell[][] cells = mBoard.getCells(); | |
for (int i = 0; i < Board.ROWS; i++) { | |
for (int j = 0; j < Board.COLS; j++) { | |
Cell cell =cells[i][j]; | |
Cell.E_STATUS st = cell.getStatus(); | |
if (st == E_STATUS.Black){ | |
paint.setColor(Color.BLACK); | |
} else if(st == E_STATUS.White){ | |
paint.setColor(Color.WHITE); | |
} | |
if (st != E_STATUS.None){ | |
canvas.drawCircle(cell.getCx(), cell.getCy(), (float) (cw * 0.46), paint); | |
} | |
} | |
} | |
} | |
} |
onDrawから呼ばれるdrawBoardの中で
Paint paint = new Paint();
としているのはパフォーマンス上は良くないらしい。後でちゃんと直そうと思う。
色の指定なども本当はXMLファイルに出してしまいたいところ。
あと、円を描く前にアンチエイリアスを指定しないとギザギザになってしまうので注意。
モデルとビューの分離
オセロの盤面の状態を保持するのと、ゲームのロジックを記述するために2つのクラスを作成しておこう。盤面全体を表すBoardクラスと、個々のマスを表すCellクラスがあれば良いと思う。
Boardクラスにはwidth, height, top, leftプロパティと、Cellクラスのオブジェクトを格納する2次元配列を用意しておく。
Cellクラスには、width, height, top, leftプロパティと、そのマスがどういう状態にあるかを示す変数を作成しておこう。各マスは、「何もない」「黒」「白」の3つの状態を持つので、それらを表すEnum型も定義する。
Boardクラスのソースコードはこちら。
Cellクラスのソースコードはこちら。
とりあえずここまで
ここまでで、画面をタッチすればそこに黒または白の石を置く事が出来る様になった。
一応、既に石が置かれているマスをタッチしても反応しない様になっている。でもまだゲームのロジックと言えるものは何も書いていないので、オセロのルールに関係無く自由に石を置けてしまうし、挟んでも挟まれても何も起こらない。
しかし、これだけでも「一から自分で作っている」という感じがたまらない。(笑)
プロジェクト全体のダウンロードはこちらから。
mikehibm/MiReversi at master - GitHub
Androidでオセロゲームを作ってみる (1)
Androidでオセロゲームを作ってみる (2) ゲームロジックの実装
Androidでオセロゲームを作ってみる (3) 思考ルーチンの実装
Androidでオセロゲームを作ってみる (4) 文字列をぐるぐる回す方法
Androidでオセロゲームを作ってみる (5) 裏返しアニメーションを付けてついに完成!