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