【Unity】Unite 2015「Unityプロジェクトをひも解き把握するには」レポート


# レポート一覧

- [Unity パフォーマンス・チューニング](http://qiita.com/baba_s/items/c536b923b6cdd919e73e)
- [Unityプロジェクトをひも解き把握するには](http://qiita.com/baba_s/items/446fa7a040f09bcd0ac6)
- [エディター拡張マニアクス 2015](http://qiita.com/baba_s/items/8abfebb18f43fcc5d319)
- [MOBIUS FINAL FANTASYにおけるUnity開発事例](http://qiita.com/baba_s/items/ce6b11a5a8952ecf2485)
- [白猫プロジェクトの裏側！～パフォーマンスチューニングとリアルタイム通信の全て～](http://qiita.com/baba_s/items/7c5680b4b808defddcb7)
- [Unity × Sprite Animation](http://qiita.com/baba_s/items/a410ca070a2d3d037ff8)
- [Unityを利用したスマートフォン向けゲームアプリ開発へのアプローチ方法](http://qiita.com/baba_s/items/34d97d970b7f8b17a568)

# 講演ファイル

http://japan.unity3d.com/unite/unite2015/files/DAY2_1300_room2_Yamamura.pdf

# プロジェクトをさくっと読む方法の紹介

- なぜこんなのが必要になったのか
	- バグレポートの構造解析のため
	- サンプルシーンの解析のため
	- コード書くのが面倒でリソースの再利用を簡単にするため
		- 昔作ったプロジェクトの再利用は難しい

# Unityの構造

- プロジェクト
	- シーン
		- オブジェクト
			- コンポーネント
- オブジェクトとコンポーネントがいろいろと動いてシーンを構成する

# プロジェクトの構造

- プロジェクトは複数のシーンを持つ
- シーンは複数のオブジェクトを持つ
- オブジェクトは複数のコンポーネントを持つ
- コンポーネントは複数のアセットへの参照を持つ

# コンポーネントはコールバックで動作する

- Start
- Update
- FixedUpdate
- OnColliderEnter
- etc.

# オブジェクトが動かない条件

- 非アクティブ
- コンポーネントを持たない
- 参照もコールバックもない

# オブジェクトへメッセージを送信する方法

- SendMessage
- BroadcastMessage
- SendMessageUpward
- AnimationEvent
- UnityAction
- EventSystem.Execute
- Invoke
- StartCoroutine

# コンポーネントへメッセージを送信する方法

- メソッドの呼び出し
- event
- UnityEvent
- StartCoroutine

# 参照の構築方法

- GetComponent
- GetComponentInChildren/Parent
- FindWithType
- FindWithTag
- public/SerializeFieldの変数をシーンで設定
- AddComponentでコンポーネントを追加

# オブジェクトを作る方法

- Instantiate
- LoadLevel
- LoadLevelAdditive
- new GameObject()

# オブジェクトの元を得る方法

- Resources.Load
- AssetBundle.Load
- Prefab

# コールバックの種類

- OnCollider/OnTrigger
	- 判定に使用される
- OnMouse...、uGUIのコールバック
	- 入力に使用される

# コンポーネントの列挙方法

- シーン内にあるオブジェクト情報からコンポーネント一覧を取得し、  
コンポーネント一覧からコールバック一覧を取得する必要がある
- リフレクションを使用する

# 文字列のメソッドコールの方法

- 任意のメソッド名で呼ばれる
- AnimationEvent
- SendMessage
- uGUIのEventSystem（シリアライズ）

# コンポーネントの参照先の確認方法

- Inspectorで確認可能
- privateな物もdebugモードで確認可能

# コンポーネントの参照元の確認方法

- 無理

# コンポーネントの依存関係の確認方法

- シーン内のコンポーネント一覧から  
特定のコードを持つコンポーネントを取得  
MonoScriptでMonoBehaviourのコード取得  

# 参照関係をグラフ化するツールを作成したい場合

- dotやgmlといったフォーマットを活用する
- コード解析がなければ正規表現で頑張る

# マネージャー系オブジェクト

- オブジェクト総数が一つでコンポーネントの参照が多い場合、  
マネージャークラスの確率が高い
- マネージャーは大体シングルトン
- 役割はさまざま
- どちらかといえば外部からのメッセージで動くことが多い

# ギミック系オブジェクト

- コライダーなどで自己完結するオブジェクト
- 他のオブジェクトに対する参照はあまりない
- トリガーやアクションをマネージャーに通知するタイプもある
- ステージを作る系のゲームによく見る

# Updateやコルーチンで自発的に動くオブジェクト

- メインオブジェクト
- 多くの参照を集めているタイプで多く存在する
- この手のオブジェクトはコードベースで動くため、コードを呼んで処理を追跡する

# そのオブジェクトはどうやって参照されたのか

- コードを追うより実際に参照させると楽

# 参照関係を把握する

- 自分で動くか管理されるかの2択
- 被参照が1つの場合、管理されている可能性がある
	- 大体マネージャー
- 被参照が多い場合、自分で動く可能性が高い
	- 大体ギミック

# 検索パターン

- ユニークなタグを持つ場合、FindWithTagで検索される
- 親子関係の場合、親子関係で検索される
- 名前で検索される場合もある

# 対マネージャー

- コンポーネントがマネージャーに自分自身を登録する方法と  
マネージャーがコンポーネントを探す方法の2種類がある

# なぜ参照を持つのか

- 検索のキャッシュ
- 対象の位置を得るため
- 対象のコンポーネントの情報を得るため
- メッセージングのため

# 生成コードの検索

- シーン内に最初から配置されているか
- シーン内でオブジェクトを生成するコードを検索する
- ResourcesやAssetBundleなどの処理はラッピングされて  
独自に管理機能を持つケースが多い
	- その場合はラッパークラスを探す

# 該当のプレハブを持つシーンを探す

- LoadLevelAdditiveの場合、ロードするシーンを探す
- 生成物がプレハブの場合、事前にシーン内の参照情報を保持しておくことでサクッと探せる
- Reference Viewer (Unite 2014)が便利
https://github.com/anchan828/unitejapan2014/tree/master/ReferenceViewer
- あとはシーンをロードするコードを探す

# シーン(YAML)をGREP検索

- メタデータ
- シーンのフォーマットをYAMLに変換し、Grep検索
	- オブジェクト名は見つかる
- あとはシーンをロードするコードを探す

# UnityYAMLMerge

- Unity5よりUnityYAMLMergeが導入され  
シーンやプレハブのマージが可能になった
- http://docs.unity3d.com/Manual/SmartMerge.html

# まとめ

- シーンが持つコンポーネントを知る
- オブジェクトの役割と参照関係を知る
- オブジェクトが作られる条件を知る
- コンポーネントの動くタイミングを知る
- コンポーネントの接続方法を知る
- オブジェクトの動きを把握すると大体シーンの構造がわかる