Androidでのゲームの作り方

すっかり更新を忘れてしまった。
気付いたらAndroidSDKは1.0r1となっていた。RC1じゃないんだ。
米国でAndroidの年内の発売が発表された。
WSJは大嘘つき。


0.9から1.0r1になってまたしても複数の自作プログラムが動かなくなった。
自分だけならまだしも公式ブログにて公開された複数の"Apps for Andorid"も動かなくなったまま放置されている。
GlobalTimeだけでも直してください。
お願いします。


Android勉強会にてピカイチに輝いていた村上さんがご自身のブログにてまた輝いていた。
最高です。
Androidネタもぜひお願いいたします。


本日、Androidユーザー会の勉強会に参加してきました。
楽しかったです。
暑かったです。
空調の予約だけはどうぞ忘れないでください。
お願いします。


SDK WGのリーダーをされていらっしゃる江川さんがとても参考になるお話をされていた。
特に興味深かったのはセンサーまわり。
江川さんの公開資料にはなかったと思ったけど、講演にて使用されていたセンサーシミュレーターはこちら。
http://www.openintents.org/en/node/23
http://code.google.com/p/openintents/wiki/SensorSimulator

これはゲームを作りたくなりますね。
でも以下はセンサーは使ってません。
すみません。


Androidでのゲームの作り方

SDKに付属してくるLunar Landerのソースを読まれるのが一番てっとりばやいのです。
最近公開されたDivideAndConquerはまたちょっと違った作り方、かつタッチパネルを用いたゲームになっているのでそちらを参照するのも良いでしょう。
ここではLunar Landerについて極簡単に説明します。
長くなるのでソースは添付しません。
お手元にソースを用意して見ながら読んでみてください。

画面の設計

基本はSurfaceViewです。
こちらは画面の描画を直接行うことができる奇特なViewです。
画面更新が一番速いとGoogle認定スペシャリストの安生さんのお墨付きです。


Lunar Landerでは主に2つのViewを用いてゲームを作成しています。
1つはゲーム画面、もう1つはポーズやゲームオーバーのメッセージを表示するTextViewです。
まずFrameLayoutを用意します。
これは最も基本なLayoutで複数のViewを重ねるものです。
SurfaceViewをゲーム画面用に用意してFrameLayoutに追加します。
次にRelativeLayoutを用意します。
これはテキストの表示位置をど真ん中にレイアウトするために必要としています。
RelativeLayoutにTextViewを追加してそれを画面の真ん中に設定します。
ButtonのGravityにhorizontal_centerを設定。
そして重要なのがcenter_in_parentの設定です。
なぜなのかよくわかりませんが、gravityにCENTERを設定する方法では画面の真ん中になりません。
必ずcenter_in_parentを用いる必要があります。


通常のViewではHandlerを用いて画面更新を依頼することになるのですが、SurfaceViewでは自分で用意したThreadの中でCanvasを取得して画面領域をロックして、描画を終わったら一気に更新ということが可能です。
JavaAppletにてゲームを作られた方ならダブルバッファのテクニックを覚えていらっしゃると思いますが、Androidではプラットフォームがダブルバッファを行ってくれていますので自分でちらつき対策を行う必要がありません。

ゲームのメインループ

この画面の更新のループには自作のThreadを用意します。
Threadは名無しではなく、名前付きのThreadの内部クラスを用います。
なぜThreadが名無しではいけないかといいますと、名無しでThreadを作成すると純粋にThreadとしてのメソッドしか外側から呼び出すことができないため面倒なのです。


Threadには定番のrun()がありますのでそのなかのループでゲームのループを行います。
ループで行う基礎はCanvasの取得、ゲームのロジックの実行、Canvasへの描画、Canvasの開放とそれにともなう画面の更新です。


Canvasへの描画は通常は画面全体を対象としますが、画面のうち更新する必要がある領域がわかっている場合には引数にRectを用いて領域指定ができるようです。
これで速くなるかもしれませんが、筆者は測っていないのでチューニング命な方は試してみてください。


Canbasへの描画ですが、resのdrawableを用いてBitmapを描画しています。
Androidは回転・拡大縮小・変形などライブラリにて自由自在にできますのでオーダインとか頑張れば作れてしまうかもしれません。

キー入力

キー入力にはViewのonKeyDownとonKeyUpのイベント関数を用います。
これはJavaAppletと同じですね。


JavaAppletと同じく、キーの同時押しを実現するにはkeyDownの情報を一度ステータス変数に保存しておき、後からそれらをまとめて処理する方法が良いでしょう。


このとき、キー入力はViewのメソッドであることに注意してください。
メインループはThreadです。
Javaでは内部クラスのメソッドは一定の条件下で外部のメソッドや変数にアクセスできることを利用します。

メッセージの表示

アプリ実行時やポーズ、ゲームオーバー時にメッセージを表示するにはTextViewを更新しなければなりません。
この時に注意が必要なのはAndroidではViewへの更新はほとんどの場合、Handlerを経由してリクエストしなければならないことです。
Handlerを用いずにThreadの中からViewへ直接更新を実行すると動的例外が発生しますのでこれも経験と思って御自身で試してみてください。


タイトル画面でもデモ画面でも全部Canvasに書くのが当たり前だという硬派なゲームプログラマの方でしたらTextViewなんか必要ないですね。
その場合にはThreadのrunでloopを複数作ってゲーム上のステータス毎に画面表示を行えば大丈夫です。
Threadのライフタイムはrunの実行が全てですのでrunはいくつでもループを持ってかまいませんし、名前付きタグをうまく用いればアセンブラC言語で書くプログラムと同じような状態遷移を書くことも可能でしょう。