強火で進め

このブログではプログラム関連の記事を中心に書いてます。

「COLOPL UnityNight」に行って来ました(その2)

Unityとスマートフォンアプリの最適化 - Kuma the bear準備室 栗原 秀行さん

(追記 2012/04/21)
スライドが公開されたので追記。

(追記ここまで)

発表者のご紹介
  • プログラマです
  • Objctive-C と C# は大好き
  • ゲームの移植とあはやってましたが、もともとはNativeアプリケーション屋でした
Kuma the bearとは・・・
  • オフラインで動作するアプリである事

バイスや通信速度に依存しないプラットフォームとして。
できるだけ多くの端末をカバーするため。

  • グローバルである事

App Store / Google Playのプラットフォームで展開する以上、ローカライズも積極的に。

  • ゲームとして面白いものである事

スマートフォンバイスの性能から、携帯の付加機能のゲームでなく、ゲームプラットフォームそのものとして考える。

Kuma the bearタイトルのご紹介

(筆者注:ちなみにこれらは全てUnity製)

Kuma the bear新タイトル「むしアミ!」

コロプラスマートフォン向けゲームアプリ『むしアミ!』を提供開始 〜家を侵略する「むし」を退治しろ!ディフェンス系シューティングゲーム登場! | 最新情報一覧 | 株式会社コロプラ位置ゲーで毎日の移動を楽しく】
http://colopl.co.jp/news/pressrelease/2012040901.php

Kuma the bearタイトルのメンバー
  • 基本はスモールチーム(3-4人)
  • プロジェクト初動は、
    • エンジニアがプロトタイピング
    • ディレクターとデザイナーが企画を固める

意思決定は早く!

  • プロジェクト終盤は皆でゲームバランスの調整
  • みんなUnityを使っている
  • メンバの特性を活かす

メンバの特性

  • iOSネイティブ周りに強いiTunes Connect
  • 3Dに強いコンシューマあがり、GLとか分かってる
  • Androidネイティブ周りに強い
  • Unityそのものに超詳しい、AssetStoreオタク
  • Unity EditorScriptでツール作り
  • チームメンバーのUnityに関するナレッジはフラットに!
ところでプログラマー内では派閥があります。
  • Unityは「早い」派 → 4人
  • Unityは「遅い」派 → 3人
  • EzGUI派 → 5人
  • ex2D派 → 2人
作る上での基本構成

基本は1シーン

  • 直ぐに始められるゲームを目指すために、必ずワンシーンにする
  • シーンロードは避けるように務める
  • そのために Resources.Load/UnloadUseAsset を使ってメモリロードはフレキシブルに

プロジェクト毎にツールを作成

  • プロジェクトに応じたツールは EditorScript・Shell などで作成する
  • ゲームパラメータの調整には必須

EzGUIは使っています

  • 悪名高いライブラリですが、パフォーマンス改善・省サイズには効きます
  • 上手く使えばMVCモデルにできてスッキリ

ひとつのバイナリで多言語に対応

  • EzGUIの機能を使って、ワンバイナリで多言語対応を実装

Nativeのソースは流用しまくる

基本のターゲットプラットフォーム

参考までに、リファレンス機
Android
Galaxy S 2010年10月発売

iPhone
iPhone 3GS 2009年6月

リズムコイン 〜ここでハマった〜

問題 その1.全体的に遅い、もっさりしている
→Profilerで見ると、CPU UsageがほとんどPhysics関係

疑いその1.Mesh Colliderの頂点数が多いんじゃない?

Primitive Collider ではどうしようもできないので、8角形のCollider用のMeshを別途作成
→結果、ほんの少しだけ軽くなったけど、基本は変わらない!

疑いその2.そもそもコインが重くて場に残り過ぎなのが問題では?
→コインの Physics Material の摩擦係数を軽くして、土台から流れやすくする事で、結果的に衝突回数を減らせて、Physicsの抱える問題を解決!
   ↓
これが正解だったけど、ゲームバランスを再調整する必要が発生

パフォーマンス調整でゲームバランスへの影響をする事は多いので段階的にパフォーマンスチェックもすべし!

問題 その2.フィーバーモード突入時に一部Android端末で落ちる
→クマの後ろで出している ReanderTexture が原因じゃないか?

どうやらテクスチャの初期化で落ちるのは GalaxyS で再現性が取れた
→動的にスクリーンのMaterialに SetTexture をしていたのが問題

・初期化のタイミングで RenderTexture を割り当てて、内部的に切り替える様にした

RenderTexture の使用そのものを控えるべきですが、その他 IS03 など一度に複数の RenaderTexture が使えない端末もありました。GPUに依存する所が大きいです。

わっさーゾンビ! 〜ここでハマった〜

問題 その1.ここでも全体的に遅い、もっさりしている
→ Skinned Mesh Renderer を使っているし、 Draw Call 数はゾンビの数だけ発生。あと、やはりPhysicsが重い。

→ボーン入りのキャラクターアニメーションを使っている都合上、 SkinnedMeshRenderer を切ることは不可能
→キャラクターはRigidBody同士の衝突となっているが、既にプリミティブの Collider となっている
→やや乱暴だが、Time設定の FixedDeltaTime を調整する事で物理エンジンの演算回数を減らす事で対応。その他、アプリケーションのフレームレート上限を30に指定。描画コスト減

Unity Script Reference – Time.fixedDeltaTime
http://unity3d.com/support/documentation/ScriptReference/Time-fixedDeltaTime.html

アクション性・物理特性がゲーム性に影響しないタイトルにのみ使用可能

問題 その2.実時間ベースでのゲームバランス調整は正直きつい
→ツールやシミュレーションベースの方法を使ってテスト
→Time.timeScale での設定でx倍速モードでテスト出来るように構成しておく
→シミュレータ上からゲームの進行ログをConsoleだけなく、CSVではける様にしておく。経過時間とイベント発生をグラフ化して、ゲーム内の進行状況に偏りが出ないようにする


問題 その3.iOS上でプチフリが発生(iPad/iPhone 3GS/iPhone 4)
→データ保存のホーリング中に発生

→ゲームの特性上、PlayerPrefsが肥大化、またゲームの特性上、更新頻度が上がってしまった事が原因

→PlayerPrefsの保存は必ず処理が一時停止するため、まずは保存の項目の省サイズ化
PlayerPrefsは非同期で無い事に注意

→ OnApplicationPause と OnApplicationQuit できちんとセーブしてあげれば、問題無し

ポーリングでデータ保存すると、壊す可能性も否定出来ないため要注意!

むしアミ! 〜ここでハマった〜

問題 その1.ここでも全体的に遅い、もっさりしている
→Skinned Mesh Renderer 使っているし DrawCall 数はむしの数だけ発生。あと、やはりPhysicsが重い
→Physicsは衝突はさせていませんが、Triggerには使ったりしています
 →Physicsの計算を端折ったり、FPSを落としたりできない!
→やられポイント取得などのエフェクトの拡大、縮小などをモデルとアニメーションが行われていたため、そこでの DrawCall をバッチングさせるために、テクスチャのOffsetアニメーションなどで実装。演出もEzGUIで実装
 →Draw Callのバッチングが効くケースと効かないケースをしっかりと把握しておく事
→全体的に敵の流れが良くなるように、ゲームのバランスを調整

→結果として真っ向勝負しないようにして、パフォーマンスを改善


問題 その2.全ステージ300ステージ
→Inspector上からの編集は正直難しい。CSVが必要でやる事に決めた
→Inspector上からの調整は誤入力が起きそうで正直怖い
→Export/ImportスクリプトをEditorスクリプトで調整
Excelでグラフ化しながら大雑把に調整
→300ステージでのパラメータ入力にあたり、難易度にゆらぎ・誤入力が出ないように、Editorスクリプト上でバリエーションを実装
バリデーションでエラーが出たらコンソールに出力

Inspectorでの配列操作は50くらいまでが上限かと、、
それ以上のパラメータはCSVとの連携が可視化の意味でオススメ!

EzGUI Localize Tips! その1
  • フォントスプライトシートの出力はMacなら BMGlyph か GlyphDesigner で
  • 両方ともEzGUI用のExport設定有り
  • 文字の装飾はGlyphDesignerが綺麗に出せるので、こちらを推奨します!
EzGUI Localize Tips! その2

GUIのスプライトシートは無圧縮16bit画像つき、メモリの圧迫サイズが大きいのでシステム言語環境に応じて、 Resources.Load でMaterialのMainTextreを変更。全言語で共通のUIはそのまま共有。

【コード例】

		Material LocalizeMaterial;
		if (Application.systemLanguage != SystemLanguage.Japanese) {
			Texture2D t = (Texture2D)Resources.Load("LocalizeResource/GUILocalizedEnMaterial", typeof(Texture2D));
			LocalizeMaterial.mainTexture = t;
		} else {
			Texture2D t = (Texture2D)Resources.Load("LocalizeResource/GUILocalizedJpMaterial", typeof(Texture2D));
			LocalizeMaterial.mainTexture = t;
		}
Android メモリ小技

Androidの実行メモリの使用量につき、OSによりActivityが終了させらる事が有ります。
メモリの使用量は、AdmobなどNativeまわりも考慮してUnity単体で100MB以下におさえる必要が有ります。

端末のタスクマネージャーに表示されている数字については、端末毎に異なった数字が返ってくるので当てになりません(Galaxy S2とか)

以下のコマンドで確認しましょう

adb shell top | grep package name

adbを使えば、正しいメモリ使用量が取得できますので、adbを使って実際のメモリの使用量として参考にして下さい。

プロジェクトの序盤ではUnityから直接APKを作っていて問題ありませんが、後半では、Native側の連携が重要となり、なおかつ実機テストが必要となります。

いちいちEclipseを通してのパッケージングは面倒臭いので、UnityBuild後に、Antでコマンドビルドするようにしました。

UNITY_PROJECT=/Documents/unity/title/
ECLIPSE_PROJECT=/Documents/Eclipse/title/

cp -r $(UNITY_PROJECT)/Temp/StageArea/assets $(ECLIPSE_PROJECT)
ant clean
ant release
date

InAppBillingのテストなど署名付きビルドをする場合には署名のパスフレーズも Build.properties に書いておけば入力しないで済むので超便利!

まとめ

1.パフォーマンスがらみは正面から勝負するよりも分析。またSCMで必ず遡れるゆ鬼して原因の差分を比べる
Profiler/Instruments/OpenGL ES Perfomance Detective/adbを駆使

2.特定の問題の出やすい端末を把握しておく事が必要
IS03/Arrows X/Infobar/Galaxy/iPhone 3GS ... more

3.UnityのEditorScriptはエクスポート・インポートだけでなく、バリデーションにも使える。
Excelとの連携にも便利になるので、プロジェクト毎でも起こす価値がある。
SerializeしてInspectorでの調整はべんりだけど、数の多い配列はCSVも考慮して。

4.ゲームとしての面白みにこだわるための近道は常に確保。AssetStoreは眺めるだけでも楽しいもんです。

5.ツールを作るのはプログラマ的に、超楽しい。