Android始めました
と言っても、何かアプリをリリースした訳じゃないですが、
宿題を出されたので、ライブ壁紙を一生懸命作ってみました。
ライブ壁紙でライフゲーム
最初は「日経ソフトウェア」の記事を写経してたんですが、
まぁ、それでうまくいったんですが、例外が起きてちょっとアレでして。
そこで、googleの公式サイトにもサンプルソースが上がってたので、
今度は、そっちからコードをパクって仕上げました。
まずは、ライフゲームのクラス
package your.domain.LifeGameWallpaper;
public class LifeGame {
private final byte
STATE_DEAD = 0,
STATE_STAY = 1,
STATE_BORN = 2;
private int _width;
private int _height;
private byte[] _buf;
public LifeGame(int w, int h) {
_width = w;
_height = h;
_buf = new byte[ _width * _height ];
for (int i=0; i<_buf.length; i++) {
_buf[i] = STATE_DEAD;
}
}
public int getWidth() {
return _width;
}
public int getHeight() {
return _height;
}
public void setPattern(byte[][] pattern, int offsetX, int offsetY) {
int x0 = offsetX;
int y0 = offsetY;
int x1 = offsetX + pattern[0].length;
int y1 = offsetY + pattern.length;
// 上下左右の端の行と列は計算対象外なので、
// データを書き込まないようにクリップ(LifeGameの仕様)
if ( x0 <= 0 ) { x0 = 1; }
if ( y0 <= 0 ) { y0 = 1; }
if ( _width <= x1 ) { x1 = _width - 1; }
if ( _height <= y1 ) { y1 = _height - 1; }
// 上下左右の端の行と列にかぶらない部分を初期化
for (int iy=y0; iy<y1; iy++) {
for (int ix=x0; ix<x1; ix++) {
int idx = (iy * _width) + ix;
if ( pattern[(iy - offsetY)][(ix - offsetX)] != 0 ) {
_buf[idx] = STATE_STAY;
}
}
}
}
public void exec(byte[] dst) {
// dstに結果を格納
execLifeGame( dst );
// 次の準備
for (int i=0; i<_buf.length; i++) {
_buf[i] = dst[i];
}
}
private int getAroundOf(int index) {
int ret = 0;
index -= _width; // 1つ前のラインから走査するためのデクリメント
for (int i=0; i<3; i++) {
if ( _buf[index - 1] != STATE_DEAD ) { ret++; }
if ( _buf[index ] != STATE_DEAD ) { ret++; }
if ( _buf[index + 1] != STATE_DEAD ) { ret++; }
index += _width;
}
return ret;
}
private void execLifeGame(byte[] dst) {
int iy = 1;
int lineOffset = _width * iy;
for (; iy<(_height-1); iy++) {
for (int ix=1; ix<(_width-1); ix++) {
int idx = lineOffset + ix;
byte state = _buf[idx];
int cnt = getAroundOf( idx );
if ( state == STATE_DEAD ) {
state = ( cnt == 3 ) ? STATE_BORN : STATE_DEAD;
}
else {
state = ( (cnt-1) <= 1 || 4 <= (cnt-1) ) ? STATE_DEAD : STATE_STAY;
}
dst[idx] = state;
}
lineOffset += _width;
}
}
}
そもそも、ライフゲームって何かというと、
自分の中心に3×3の計9マスを対象として、
その中心が死滅状態で周囲に3匹の生存していれば誕生、
もしくは中心に1匹と周辺に2〜3匹入れば生命を維持、
中心の他に生命が1匹以下、もしくは4匹以上居れば
過疎、もしくは過密により死滅するというプログラムです。
興味のあるヒトは、「ライフゲーム」検索してください。
例えば、こんな感じ。
で、最初は120×120くらいで計算してたのですが、
Androidシミュレータ上だと100ms以上時間が掛かってて、
描画処理も描画する長方形の数依存で気持ち悪いことになってて、
結果的に80×80を採用することにしました。
あと、初回execが時間掛かるので、
Engineのコンストラクタであらかじめ一回呼ぶようにしました。
一応、実測なんですが、実機にAcerのA500を使って計測したところ、
Androidシミュレータより画面(*1)が広くなって不安だったのですが、
結果的にはライフゲームが10ms以下で、描画処理は3〜5msくらい。
8fpsなら安定して動いてるようです。
あと、描画に必要な座標計算をonSurfaceChangedで行っていたので、
端末の向きが変わっても問題なく動作してました。
そんなこんなで、未だにソースコードを晒すときは
お酒を呑まないと恥ずかしくてやってられないネコでした。
おしまい。
(*1) シミュレータは320×240, A500は1280×800
Leave a Comment