Android の会 2009/05/11 Android Game Programing Tips 株式会社タイトー ON!AIR 事業本部コンテンツ企画部開発課山田俊一 2009/5/8 Android の会 2009/05/11 1
自己紹介 2005 年入社その後の経歴 Vodafone/Softbank DoCoMo (Java) - iアプリ - JavaTMアプリ S! アプリ Web サイト管理 (html, perl, MySQL ) - なんだかいろいろ 2009/5/8 Android の会 2009/05/11 2
ゲームってどうやって動いてんの?(1/2) パラパラアニメ 1 秒間に xx 回のループ : xx fps(frame per second) - 例 :20fps=1 ループは 50ms 各種計算処理に 15ms -> 35ms スリープ各種計算処理に 80ms -> スリープ無し, 処理落ち発生中. 実例 アーケード コンシューマは 30fps or 60fps 携帯アプリは10~30fps 傍目に見てカクカクが目立つのは 8fps 以下 TVアニメは24fpsで製作 2009/5/8 Android の会 2009/05/11 3
ゲームってどうやって動いてんの?(2/2) 簡易図 ゲームの初期化 キー操作 タッチパネルなどの I/O 用バッファからユーザの入力状態を受け取る ゲーム固有の処理キャラクタの座標移動 画像の切り替えなど if(boolexe==true) 効果音 BGM の処理 ユーザ入力をバッファリング 画面にペイント 待機時間が終わるまでスリープ ゲームの終了 2009/5/8 Android の会 2009/05/11 4
Android の View いろいろあるよ (1/4) View ondraw(canvas ocanvas) ループ UI キットのようなものを利用し 複数機種へのレイアウト崩れを防止 処理が重い やっぱりツール向け //=== method ======================================= /** * View#onDraw() **/ //================================================== public void ondraw() /* * バッファ処理 数値計算など 各種処理を記載 */ update_userinput(); update_game(); update_sound(); // 画面への描画を実行する //ondraw() 終了時に次の ondraw が発生 = 無限ループ状態 invalidate(); // スリープ処理 game_sleep(lfinishtime - lstarttime); return; 2009/5/8 Android の会 2009/05/11 5
Android の View いろいろあるよ (2/4) SurfaceView サブクラス作成 別スレッドでループ管理 描画処理が軽い! アプリのライフサイクルが分かりにくい UIキットが使えない ( かも ) ゲーム向き 2009/5/8 Android の会 2009/05/11 6
Android の View いろいろあるよ (3/4) SurfaceView, sample public class MyView extends SurfaceView implements SurfaceHolder.Callback //=== implements =================================== /** * implements : surface 生成 */ //================================================== public void surfacecreated(surfaceholder osh) m_odrawthread = new DrawThread( SurfaceHolder ); m_odrawthread.start(); return; //////////////////////////////////////////////////// /** * SUB CLASS * DrawThread * * Surfaceを用いた描画用スレッド **/ //////////////////////////////////////////////////// class DrawThread extends Thread public void run() while(boolgameexecute == true) // ゲーム処理 return; 2009/5/8 Android の会 2009/05/11 7
Android の View いろいろあるよ (4/4) OpenGL を組み込む場合 SurfaceView+OpenGL 描画用スレッド - 更に設計が煩雑になる - ライフサイクルが分かりにくい - Canvas, Drawable を用いた描画処理ができず i アプリ S! アプリからの移植性が低い SDK1.5 にある新 API GLSurfaceView に期待? - OpenGL ES アプリケーションを作りやすくする らしい 2009/5/8 Android の会 2009/05/11 8
システム! Android 固有の問題と解法 システム全般の巻 2009/5/8 Android の会 2009/05/11 9
システム編 : ライフサイクル注意点 アプリをしっかりと終了させよう! Backボタンに任せる Activity#finish() を発行する - ゾンビアプリが多いよー 割り込み処理に対応しよう! Activity#onPause() Activity#onResume() 何も処理しないと 電話が来ても BGM が鳴り続けるよ 2009/5/8 Android の会 2009/05/11 10
システム編 : バイブレーション機能 manifest.xml の修正も必要 <manifest> <uses-permission android:name="android.permission.vibrate" /> </manifest> /** * View#onDraw(Bundle) */ public void oncreate( Bundle savedinstancestate ) // バイブレーション機能を取得 ovibrator = (Vibrator)getSystemService(Context.VIBRATOR_SERVICE); /** * ltime : 0~ 負数で強制停止 */ protected void setvibrator(long ltime) if( ovibrator!= null ) if(ltime > 0) ovibrator.vibrate(ltime); else ovibrator.cancel(); return; 2009/5/8 Android の会 2009/05/11 11
システム編 : ユーザ I/O (1/2) キー入力 onkeydown() : return true キー入力を無効化 - Back ボタン Home ボタンを無効化したい場合に public boolean onkeydown(int ikeycode, KeyEvent okeyevent) if(okeyevent.getaction() == KeyEvent.ACTION_DOWN) // KEY : BACK if(ikeycode == KeyEvent.KEYCODE_BACK) m_ikeybuf = KEY_SYS_BACK; return true; //return super.onkeydown(ikeycode, okeyevent); return super.onkeydown(ikeycode, okeyevent); 2009/5/8 Android の会 2009/05/11 12
システム編 : ユーザ I/O (2/2) トラックボール ゲームによっては 値そのまま処理すると違和感が出てくるため加速度をバッファリングするなど 何かしらの補正をつけるといいかも - たとえば 0.1f -> 1 pix 移動 0.3f -> 5 pix 0.5f -> 10 pix 1.0f -> 50 pix タッチパネル 重い! 激重! - 効果的な対応策 無し 2009/5/8 Android の会 2009/05/11 13
システム編 :Manifest.xml Tips configchanges 端末の縦横回転時に実行アプリケーションの再起動を行わない screenorientation Portrait/Landscape の固定を行う <activity android:name=".hogehogeappname" android:label="@string/app_name" android:configchanges="orientation keyboardhidden" android:screenorientation="portrait"> 2009/5/8 Android の会 2009/05/11 14
サウンド! Android 固有の問題と解法 音の巻 2009/5/8 Android の会 2009/05/11 15
サウンド編 : 再生形式 (1/2) Wav MP3 再生できるけど 再生開始に時間がかかる ( 毎回バッファリングしてるっぽい?) - BGM のループが途切れやすい - シューティングのショット音など SE( 効果音 ) の連続再生ができない 無理に連続再生すると 致命的エラーでアプリが落ちる! - それどころか OS すら落とす ダメじゃん! 2009/5/8 Android の会 2009/05/11 16
サウンド編 : 再生形式 (1/2) OGG Ogg Vorbis 圧縮音声フォーマット ライセンスフリー MediaPlayer#start() ですぐに再生開始! SE の連続再生もいけるね! SE も BGM も Ogg で! 2009/5/8 Android の会 2009/05/11 17
サウンド編 :G1 限定のお話 かも SE を頭から再生しなおす場合 MediaPlayer#seekTo(0) わざわざ pause() する必要無し ポート (= 同時に可能再生数 ) は 4 つ! API 側には制限が無いので ソフトウェア側でポートを管理 - 勝手に空きポートにサウンドデータが割り振られるので 最大同時再生数が 4 になれば良い - implements OnCompletionListener, oncompletion() i アプリも S! アプリもポート 4 つなので 経験者なら楽! ポート A ( 使用中 ) ポート B ( 使用中 ) ポート C ( ひま ) ポート D ( 使用中 ) BGM SE01 SE02 SE04 再生ちゅ! 再生ちゅ! よしよし まだ開きがあるな 再生ちゅ! SE03 命令は来たけど空き席が無いのでサボります 2009/5/8 Android の会 2009/05/11 18
グラフィック! Android 固有の問題と解法 グラフィックの巻 2009/5/8 Android の会 2009/05/11 19
グラフィック編 : こまごまとしたこと 処理の重さ = 描画範囲 描画範囲 描画する画像領域が広いほど重い - ondraw() を用いる場合 Invalidate(x,y,w,h) で書き換え範囲を限定するのも手 Png 無駄なヘッダが入っていると処理が重い - たぶん 律儀に全ヘッダ解析 + エンコードしてるのだろう 画像描画は Drawalbe を使おう createbitmap は Drawable よりもメモリを消費するため 2D 画像回転など 限定した処理で用いるほうがよい 拡大縮小はアンチエイリアスがかかるので綺麗 ただし すごく処理が重い 前もって拡大縮小済みの画像を持っていたほうがいい 透過 png だけでなく アルファ png にも対応 面白い演出ができるかも 2009/5/8 Android の会 2009/05/11 20
etc その他 2009/5/8 Android の会 2009/05/11 21
Eclipse& エミュレータとうまく付き合う 重い! PC 最高スペックだとさくさく? 補完機能は使い方次第では便利 親切すぎて邪魔にもなる 使い慣れたエディタで作成 Eclipseでバグチェックがいいかも 再現度が高い エミュレータでバグ 処理落ちがあるなら 実機でも同じことが起きる - タッチパネル関連 ホントどうしてくれよう トラックボールの操作は - エミュレータではアウトプットは 1.0f 単位 - 実機でのアウトプットは 0.1f 程度 3D に関してはエミュレータと実機で異なる部分が多々あるため 実機中心で開発しよう 2009/5/8 Android の会 2009/05/11 22
ログは便利 だが Eclipse 経由で 他人のアプリのエラーログ確認ができしてしまう 製品版アプリでは android.util.log を外しやすい設計を! ログ出力専用関数を作っておき 間に挟んでおくなど public void outlog(string smes) //* Log.w(TAG, "[warn] "+smes); //*/ return; 2009/5/8 Android の会 2009/05/11 23
今後の為に : 機能を切り分けよう プラットフォームによって異なる ユーザデータのセーブ & ロード 画像表示 サウンド どのプラットフォームでも共通 ゲームアルゴリズム 2009/5/8 Android の会 2009/05/11 24
以上! ご静聴ありがとうございました 2009/5/8 Android の会 2009/05/11 25