強火で進め

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

「第9回 Unity開発技術勉強会」に参加して来ました

【増員】【TechBuzz】第9回 Unity開発技術勉強会 〜先行事例紹介/交流会〜 「Unityのメモリチューニング関連について」/ 「Unity初心者のプランナー主導型スマホゲーム開発事例」/ 「ゴルフゲームでUnityの限界を突破する方法」 : ATND
http://atnd.org/events/32037

「Unity初心者のプランナー主導型スマホゲーム開発事例」 - 株式会社ANGEWORK 代表 桐生さん

  • 空き部屋に全員のPC&机を持ち込み
  • 進捗会議無し
  • 全員が仕様と内部を把握
  • オンラインオフィスツール(Google Docsなど)
  • ホワイトボード
    • ステージ3D構造描画
  • Unity Web Player
    • 社内への進捗公開
Unityの良さをどう活かすか

どこまで実際に有効かは疑問 → じゃあこのプロジェクトを実験台にしよう!!

  • Pluginはどんどん活用
  • プランなに劣化ツクールを提供
  • 拡張メニューで操作を簡略化
  • オブジェクト動作:iTween
  • セーブロード:EsaySave
  • GUI処理:NGUI&TexturePacker
  • 課金:PaymentPlugin
  • パース処理:JSONObject
インスペクタを活用
  • インスペクタのD&D可能な特性を利用
  • D&Dがそのまま実装になるのが最終目標

   ↓
これによりプランナーが使える様になる

  • アイテム管理を徹底
  • 自前インスタンスプール管理
  • アイテムはタイプIDでユニーク化
  • アイテムの列挙体無し→仕様が固まって無いリスクとスピードを考慮した結果
  • アイテムクラスにフラグを準備
    • 商品名、価格、ProductID、残数管理有無
    • アイテム管理画面で一覧でチェック可能
    • これにより突然の仕様変更に強くなった
  • 自作クラスは130強
  • テスト期間:全員で直前の1週間程度
メリット・デメリット・反省点
  • 引きこもり作業:互いに逃げ場なし。緊張感が高い
  • D&Dインスタンス:密結合の元&シーン依存
  • 独自メニュー:実装時間以上の効果
  • Plugin:C#のみ(ライブラリ化されていない)もののみで構成されたタイプがお勧め

所感:「メンバ全員に悪い印象がないのが幸いでした」

QA

Q:利用したライセンスは
A:4人全員がProライセンス+Teamライセンス

Q:Pluginで発生したトラブルとその対処方法
A:PaymentPluginを使うと落ちる。Plugin、使い方、サーバ側の設定のいずれが原因か分からなかったがそれぞれについて修正しているうちに解消された。2D Tool Kit で一定以上のインスタンスを作ると落ちる。Win/Macでは問題無し、スマホだけで発生。インスタンスの作成数を制限して対応。

「Unityのメモリチューニング関連について」 - 株式会社リンクキット代表 竹内さん/取締役 和田さん

株式会社リンクキット
http://www.linkkit.co.jp/

Android
  • Linux ヒープが限界近くまで、メモリが消費されると動作が不安定に
  • バックグラウンドアプリがGCを発生させて自分のアプリが重い様な印象を与える事に
  • GCが何度も起動
  • ウィルス対策アプリがボトルネック
  • 現状はメモリ使用量は100MB程度にしているの良いという印象
レビュー
  • 動かないので☆1つ
  • 一分間に何回再起動するんだ!!
  • メモリを増加させない基本
GameObject.Destroyについて
  • Unity 機能のインスタンスが不要になれば GameObject.Destroy を実行して即時破棄させるのが基本
    • シーンが変われば自動的に破棄
    • 逆にシーンを変えなければ溜まる一方
  • Destory すべきインスタンス
  • WWW.texture から取得した Texture
  • Renderer.material,Renderer.materials で生成されたマテリアル
  • clone material されたものと shared material が混ざるとやっかい
  • プロファイラのRendringカテゴリのUsed Textureの値は、
  • static なメンバ変数に代入したものは自分で破棄する必要有り
  • Dictionary や List などに代入したもの(続き有り
プレハブ
  • プレハブはシーンが開始された時点で全てメモリに展開される
  • Instantiate していないテクスチャやメッシュがOpenGL リソースとして存在
Resourcesディレクト
  • Resources ディレクトリに入れると1ファイルごとに管理情報が保持される
  • mainData ファイルにパスと実ファイルのマッピング情報が記録
  • iOSで1ファイルにつき約150バイト程度メモリ増加
  • Androidで1ファイルにつき約1KB程度メモリ増加
  • RGBA8(32bit)形式であれば StreamingAssets として PNGJPEG ファイルのまま使用することも視野に入れた方が良いかもしれません
サイズ補正
  • 2のべき乗で無い画像ファイルは内部では2つの画像を持つようになる
  • 準備しておく画像ファイルのサイズを2のべき乗にしておく
  • サイズ補正がかかるもの
    • エディタへインポートした画像ファイルのテクスチャ
    • WWW.texture で画像ファイルから取得テクスチャ
    • new Texture2D() で作成するテクスチャ
  • サイズ補正がされないもの
    • RenderTexture.GetTemporary() で作成された内容
  • OpenGL ES 2.0 は NPOT のテクスチャの使用自体は可能(※)

※筆者注:実際には OpenGL ES 2.0 での NPOT テクスチャの使用は拡張で実装されている環境でのみ使用可能。現状では OpenGL ES 2.0 を実装している環境ではこの拡張が実装されている環境がほとんど。

  • NPOT のテクスチャは MipMap 、 CLAMP 以外のフィルタは使用できない制限が有る
  • もともとポストプロセス用途が主
アニメーションキーと GameObject の結びつき
  • AnimationClip から結びつきの依存情報を引き出せる
    • AnimationUtility クラスから情報の取得と操作が可能
    • AnimationClipCurveData にパスと、要素名が文字列で記録されている

以下の様なプログラムで取得可能

※筆者による全体の記述を追加したもの。 AnimationClip を選択した状態でメニューから実行して下さい。

using UnityEditor;
using UnityEngine;
using System.Collections;

public class CheckAnimation : MonoBehaviour
{
	[MenuItem("Tools/AnimationClip/View")]
	static void animationclip_view ()
	{
		Object[] sel = Selection.GetFiltered (typeof(AnimationClip), SelectionMode.Unfiltered);
	
		foreach (AnimationClip clip in sel) {
			foreach (AnimationClipCurveData curve in AnimationUtility.GetAllCurves(clip)) {
				Debug.Log (string.Format ("path:{0}\npropertyName:{1}\ncurve.length:{2}\n\n",
				curve.path, curve.propertyName, curve.curve.length));
			}
		}
	}
}

ある要素(ここでは localScale )を削除するプログラム

※筆者による全体の記述を追加したもの。 AnimationClip を選択した状態でメニューから実行して下さい。

using UnityEditor;
using UnityEngine;
using System.Collections;

public class CheckAnimation : MonoBehaviour
{
	[MenuItem("Tools/AnimationClip/Delete/all localScale")]
	static void animationclip_delete_all_localscale ()
	{
		Object[] sel = Selection.GetFiltered (typeof(AnimationClip), SelectionMode.Unfiltered);
	
		foreach (AnimationClip clip in sel) {
			foreach (AnimationClipCurveData curve in AnimationUtility.GetAllCurves(clip)) {
				if (curve.propertyName == "m_LocalScale.x" ||
					curve.propertyName == "m_LocalScale.y" ||
					curve.propertyName == "m_LocalScale.z") {
					// 要素を全部削除する
					AnimationCurve crv = curve.curve;
					while (crv.length > 0) {
						crv.RemoveKey (0);
					}
					// 上書き
					AnimationUtility.SetEditorCurve (clip, curve.path, curve.type, curve.propertyName, crv);
				}
			}
		}
	}
}
  • キーフレームの圧縮。動作がプルプルしたりするのであまり圧縮率を高める事は出来ない
  • メモリに読み込む AnimationClip を減らす
  • AnimationClip を動的に読み込む
  • AnimationClip のデータ量の削減方法
  • AnimationClip の数を減らす
  • ボーンの数をできるだけ少なく
  • 不要なら localScale の要素を削除する
  • ボーン名を1文字に短縮する
  • AnimationClipを編集してもう一度プレハブ化する必要有り
  • モデルファイルを複製すればAnimationClipだけ取り出す事が可能
  • メモリ使用量の調べ方

iOS:Instruments上で、Activity Moniterを選択
Android:adb shell top | findstr [bundle identifierに設定した文字列]

もうちょっと詳しく知るには
adb shell cat /proc/[pid]/status
【表示結果の内容】
VmHWM:アプリ起動中にもっともメモリを使用した時の値
VmRSS:現在アプリが使用しているメモリ量

ゴルフゲームでUnityの限界を突破する方法 - KLab株式会社 饒平名さん

こちらに講演についての話&スライドが公開されています。

KLab若手エンジニアの これなぁに? : ゴルフゲームでUnityの限界を突破する方法
http://young.blog.jp.klab.com/archives/20172139.html