スペースデブリスのソースコードを公開します。
スペースデブリスはMIDletクラス、2つのCanvasクラスを持っています。構成は以下の様になります。
appletクラスはMIDletクラスから継承されるエントリポイントクラスです。ファイル保存や共通のリソースデータを持っています。
appletクラスはGameCanvasから継承した、SpaceCanvクラスと、Canvasクラスから継承したSettingCanvasクラスを持ちます。
ゲーム自体はSpaceCanvにRunnableをインプリメントして実行させます。
ゲーム中に移動するもの(自機、敵機、弾)はbaseObjという基本クラスから継承されています。必要に応じてメンバー関数がオーバライドされています。
携帯Javaアプリを作成していて一番の問題はガベージコレクションです。ガベージコレクションとは、Javaが採用しているメモリ管理機構の一種で、C/C++等と違って生成したメモリをプログラマが開放しなくても、システム側で自動的に開放してくれる機構です。
一旦ガベージコレクションが始まるとアクションゲームの場合、ガベージコレクションの動作中動きが止まってしまいます。
Stringクラスは気をつけていないとすぐにメモリを食い尽くしてガベージコレクションを発生させてしまいます。例えば
System.out.println( "デバッグ" + ii );
等とメインループに入れてしまうと、文字列が次々に作成されてしまい、すぐにガベージコレクションが発生してしまいます。
なので、文字列は可能な限り固定にする等配慮が必要です。
例えばハイスコアやスコアの表示も単純に文字列を生成しないようにする必要があります。スペースデブリスではスコアをグラフィックスで描画しており、文字列クラスは生成されないようになっています。
//* -------------------------------------------------------- */ /** 4桁の数値描画 @param in 描画数値 @param ix 描画開始X位置 @param iy 描画開始Y位置 */ public void draw4Int( int in, int ix, int iy ) { int index; try { for( int ii = 3; ii >= 0; ii-- ) { index = in % 10; applet.sprFont16.setFrame( index+16 ); applet.sprFont16.setPosition( (ix+ii) * 10, iy * 16 ); applet.sprFont16.paint( g ); in /= 10; } } catch( Exception e ) { System.out.println(e.toString()); } }
ただ、全て厳格に文字列の生成を抑制しているかといえばそうでもなく、生成回数が少ないところはStringクラスも利用しています。
スペースデブリスは敵(debri)や弾(bullet)の管理を「まとめクラス」で行っています。敵の出現や弾の発射によって動的にインスタンスの生成を行うと、これもガベージコレクションの発生につながってしまう為です。従って下図の様にはじめに50個のオブジェクトを作成しています。
本来ですと、動的伸張なリストクラス等を採用すべきなのでしょうが、携帯アプリではちょっとキツイようです。
綺麗に作れば全ての移動オブジェクトが動的に生成されて、ひとつのリストで管理されると美しいのですが。
スペースデブリスは2つのCanvasを持っています。
Canvasを幾つ作成するかは相当悩みどころです。例えば全部の画面をひとつのCanvasで作りきってしまうことも可能ですし、画面毎にCanvasを分けるという手もあります。
スペースデブリスでは、移動するオブジェクトがある画面は全てSpaceCanvクラスに纏めています。唯一設定画面のみ別Canvasとしています。
実際この辺りはまだまだ自分自身研究の余地があるような気がしています。全ての移動オブジェクトをMIDletクラスへ集約して、Canvasを細かく分けた方が綺麗なような気もします。しかし、Runnableなクラスを複数作る事にも抵抗があります。なぜならMIDPのThreadクラスはStop〜Runが出来ないからです(出来てもするな、とSunも言っている)。