ひつじのにっき

mhidakaのにっきです。たまに長文、気が向いたとき更新。

【MB-2】 Androidでリアルタイムゲームの開発方法 - Google Developer Day 2009

非常に実践的。とても参考になりました。
クリスさんがすごく楽しそうに話すのでゲーム作りたくなっちゃいますね。
気になったのが

パフォーマンス:タッチスクリーンを使うとUIスレッドは大量のMotionEventsを受け取る
OnTouchEventの中でSleepするとシステムを止められるよ(やっていいのかw)

の下り。

メインスレッドが16msぐらい寝ている、とのことなのでそれぐらいなら許容範囲なのかな?
ANRの条件には当てはまらないのは間違いないですが、
Androidのシステムとして想定している動きなんだろうか…。


まぁ、MotionEventsをホイホイなげつけてしまうのが
そもそも、どうなんかなーって思います。こういう話題はどこに投げればいいんだ?

Androidでリアルタイムゲームの開発方法
Google Developer Advocate(開発支援) クリス プルエット 氏
						Mr. Chris Pruett

もともとゲーム開発をしていました。
今回、Googleの20%ルールを活用して作っているゲームについてお話しします。

なぜAndroidでゲームを作るのか?
	3つのゴール
		- 楽しいゲームを作る
		- オープンソースのゲームエンジンを作る
		- 本当にAnroidでゲームはあり得るのかを確認したい
		
	うち、二番目のゴール「オープンソースの開発」について
		今のゲーム開発を終了した後に取り掛かります

横スクロールゲーム
	開発期間:5ヶ月間。週に1日のペース。
		ゲームにAndroidのAPIが役立つのか確認したい
		OpenGL ESなどなど。

	ここでDEMO 作成中のゲーム「ワンダのレプリカ島」
	
ゲームアーキテクチャの基本
	ゲームグラフを利用
		入力は経過時間、ボタン入力
		出力はレンダリングスレッドへのコマンド

		背景、キャラクタのサブグラフがあり、カメラの場所によって
		どのオブジェクトを更新するか決定される。
		
	基本的な仕組みで作った(実際の開発では特性に合わせてアーキテクチャを選択したら良い)

	大事な点として
	経過時間も入力として利用することでフレームスキップ(コマ落ち)しても
	自然に動くようにする。アニメーション時間など本当の経過時間を利用する必要がある。
	ハードが変わってしまうとゲーム性も変わる恐れがある。
	
	描画処理は分離しておくこと。
		レンダリングのコマンドのみ生成して、レンダリングは別スレッドで処理する

スレッドは3つ
	メインスレッド			入力イベントの受付
	ゲームスレッド			描画以外のすべてを担当
	レンダリングスレッド	描画、ハードウェア制御を行うため、スレッドを分割して非同期化
							SurfaceHolderに管理、フレーム単位でキューにたまった
							レンダリングコマンドをOpenGLに投げつける。


高速なJavaコードを生成するには?
	開発歴:C++が圧倒的。Javaは触りだして6カ月なので嘘をいうかも。
	
	高速なゲームはパフォーマンスと拡張性/保守性のバランスをとることが重要★
	開発フェーズで、やってみる→だめ→ほかのことしてみるの試行錯誤ができないとだめ。
	そのためには拡張性を持たせておかないとゲームに制限ができて、破綻する。
	
	
メモリ管理
	ゲーム中にメモリ確保や解放をしないように。
	GCが確保のタイミングで動く可能性がある。
	なんとGCのタイミングでプロセスが止まってしまう。(100msや300ms単位)

	対策:ゲームが始まるタイミングでメモリプールしておく

	メモリの使用状況はDDMSをつかってメモリの仕様状況を確認できる
	Javaはいつも内部でメモリを確保している。Enum。ValuesやArrays.Sortなどなど。
	(メモリ管理しなくて良いはずなのに、結構使ってるじゃないか、とコメントしてました)

関数を呼ばない
	(会場笑い)
	Javaの関数呼び出しはC++に比べてコストが高い。インライン展開もしてくれない。
	インターフェイス経由の関数呼び出しはクラス経由の仮想関数呼び出しより30%遅い
	JNI関数は処理が早いが呼び出しが遅い
	
	できるだけ避けたいところ。

Tips
	なるべくローカル変数を使う
	変数をFinalにする。G1では小数点演算はソフトで行うのでFloatやDoubleは演算が遅い。
	(気にするほどではないかもしれない)

描画を早くする方法
	SpriteMethodTest(code.google.comで公開中)
	1000スプライト、OpenGLで描画するとだいたい10FPS。

Androidの描画はどんな手法がある?
	canvas: 2Dレンダリング。
			描画オブジェクトが少なければ早い。その上、使いやすい。10スプライトで16ms
			
	OpenGL ES:3Dレンダリングだが2Dでも役立つ
			Canvasより遅くならないが、ビデオ管理などcanvasより使いにくい側面も。
			AndroidではOpenGL ES1.0までサポート
			メーカーによっては独自Extensionとして1.0以上を取り込むことがある。
			使えるものもあるかも。ただし、1.0以上のAPIを利用する場合でも端末依存が強いので
			注意したほうがいい。

			→ 10スプライトまでならCanvasでよいんじゃない?
		
			G1ではDrawtexture Extensionが最速
			かならずglGetStringng(GL10.GL_EXTENSIONS)で確認

	Canvasはパズルゲームなど頻繁な描画更新がないゲームで役に立つ。
	ベンチマークはcode.google.com/Androidで公開中

背景の描画
	背景は3レイヤーとした(いくらでも凝れるがここでは3層。)
	
案)背景マップのタイルを32x32ドットとする。
	最悪のケースで150個を再描画する必要がある。
		→ 最初は全部を1つのビットマップにまとめて描画
		   GlTexParameteribが遅すぎて使いものにならなかった
	       タイルを別々のテクスチャに分けてみました
	
	処理時間計ってみたら最悪のケースを考えると処理に19〜23ミリ、さらにレンダリングに9〜13ミリ。
	使いものにならない…。ステージ構成に限りがでてきてしまう。

案)複数のタイルをまとめて書き込む
	VBOをつかったら早くなった。ひとつひとつレンダリングするとOpenGLのState(状態)変更に
	時間かかるが、まとめるとState変更が少ないようだ。
	ワーストケースでもベストケースでも3-5ミリ秒程度ですむ。
	
	
Tips & Tricks落とし穴
	パフォーマンス:タッチスクリーンを使うとUIスレッドは大量のMotionEventsを受け取る
					OnTouchEventの中でSleepするとシステムを止められるよ(やっていいのかw)

	ポーズやレジュームの処理はメモリの待避とかでややこしい。標準のGLSurfaceViewを使おう。
	※Android1.0〜1.5ではIndirect BufferでVBOを使おうとするとちゃんと動かないことがある。
	Donutから治る。それまでは、うまくレンダリングしなかったり、落ちることもあるので
	DirectBufferを使うように。


	アプリケーションを小さくする。2-3MBにする。
		ユーザのフィードバックと端末に入っている時間が長いこと。大きすぎると消される。
		(会場笑い)
	
	ハードウェアキーやトラックボールのないデバイスがあるので、依存しないように。
		タッチスクリーンは必ずある。

	面白いゲームほどFeaturedされる可能性があります!
	頑張って作ってね!