ガンズターン 公式サイト

楽しいことに、まじめです。 ——ガンズターンアプリ研究所公式サイト

Unity備忘録 #6-1 Androidアプリ作るときに気をつけること①(More Faster !!)

Pocket

0. Acrovisionさん主催の勉強会に参加してきました

お疲れ様です。ガンズターンのRyosukeです。
実は昨日(10日)から池袋に泊り込み。
泊めてくれたMくん、マジでありがとう。
おかげで電車賃が2千円ほど浮きました。

というわけで、本日予定されている次の用事に向けて、夕方までコワーキングスペースでもくもくと作業することにしました。
利用しているのは、新宿の「パセラのコワーク」さん。
やばいっす。めちゃくちゃ居心地いいっす。
とくにメガネ拭きが常備されているあたりが個人的に超ツボです。

今日は一日、集中するぞ!! ( • ̀ω•́ )✧

さて。

8月末あたりからUnity関係の勉強会に参加しようと思い立ち、色々と登録させてもらっています。
9日は台風接近による大雨の中、池袋で開催された勉強会に参加してきました。

びしょ濡れになって雨の池袋を徘徊しつつ、早めの夕飯を久しぶりのこってりラーメンでやっつけて、時間調整のために入ったマク○ナルドの中では隣に座った女子高生が突然「なんかドブ臭くない?」と騒ぎ始めて、まさか自分のことではないよな、なんて不安になって挙動不審になってしまったという苦い思い出を噛みしめながら、勉強会の内容を振り返りたいと思います。(一文が長い!!)

株式会社Acrovisionさん主催の勉強会ということで、Unity5.1系の、とくにMecanimをどう使うか等について、簡単な「もぐら叩き」アプリを一緒に作成しながら学習するという内容でした。
(題材が「もぐら叩き」だったのは完全に偶然です。笑)

初心者向けの内容だけあって易しめの内容でしたが、Animatorウィンドウを具体的にどう使うかを理解できたのは、大きな収穫でした。

講師をしてくださったのは、本格的なリズムゲームをUnityで作っていらっしゃるという、チームEgg株式会社の方々です。
講義後の懇親会で講義のお礼を伝えに行ったら、非常に気さくに応じてくださり、しばらくお話させて頂きました。

そのお話の中で、何気なく「Android版がiPhone版と比べて動作が遅いので困っています」と言ったら、なんとプロの方から直々UnityでAndroid版を作るための秘訣を教えていただいちゃいまして……

さすがプロの方のお話ということで、一つ一つが目からウロコの、めちゃくちゃ有用な内容だと思いましたので、この場で共有させていただこうと思います。

つまるところ、ここに書いてある内容は、わたし個人が何かを調べて得た内容ではなく、すべてプロの方からの受け売りです。

なんだか他人のふんどしで相撲を取っているようで恐縮ですが、わたし個人的に非常に救われる内容だったので、同じような悩みで困っている人の助けになればと思い、こうして記事にさせていただきました。

1. Instantiateは使わない!

Unityの入門書などを読んでいると、よくスクリプトの中で動的にオブジェクトを生成している場面に出くわすと思います。

例えば、以下のような感じ。(表記はかなり簡略化してます)

public GameObject prefab;    
GameObject.Instantiate(prefab);

ただPrefabをエディタ上でひも付けておくだけで、いつでも動的にオブジェクトを作成できて非常に便利な仕組み……なんですが、Androidでアプリを作る場合にはアウトです。

というのも、InstantiateDestroyという処理は、動的にメモリの確保、解放を行なうため、そのたびにVM「ガーベジコレクション」という仕組みが働くトリガーとなってしまうからです。

では、どうするか?

答えは簡単です。

使用する予定のオブジェクトは動的に作らず、初めからシーンの中に配置しておく。

多少強引なようですが、こうすることで必要なメモリはシーンの開始時にあらかじめ全て確保され、増減することがなくなります。
これにより「ガーベジコレクション」の動作が抑制され、FPSの向上につながるというわけです。

「ガーベジコレクションってなに?」という方は、この記事の最後のほうで簡単に解説しますので、ここでは「ふうん、そういうもんか」ぐらいの認識でいてください。

2. オブジェクトプーリングの導入を検討する

ここでいう「オブジェクトプーリング」とは何か、というと「オブジェクトを動的に確保したり廃棄するのではなく、あらかじめ固定数のオブジェクトを確保しておき、必要に応じてそれを使い回す」という概念です。
(ひょっとしたら「動的に確保したオブジェクトを廃棄せずに使い回す」という意味でも使われているかも……)

例えばUnityでシューティングゲームを作っているとします。
この時、自機のショット1発分のGameObjectがPrefabに設定してあったとして。

「1. Instantiateは使わない!」でも説明した通り、ゲーム中で使用する可能性のあるオブジェクトは全てシーン内に配置すべきです。
……が、シューティングゲームで自機が打つショットの総数なんて予め分かりませんし、ゲームによっては1プレイで数千発以上発射する可能性もあります。

そんな膨大な数のオブジェクトを予め確保しておくなんてありえないですよね。
しかも、万一、その総数を超えるオブジェクトが必要になったら、その瞬間にアプリが落ちるという最悪の事態さえ起こり得ます。

こんな時、「オブジェクトプーリング」を使えば、全て解決します。

Unityにおける「オブジェクトプーリング」の手法についてはここでは詳細を書きませんが、以下のリンク先を参考にすれば、それほど難しくなく実装できると思いますので、ぜひ挑戦してみてください。

「Unity 公式チュートリアル」
(http://japan.unity3d.com/developer/document/tutorial/2d-shooting-game/optimization/01.html)

「Buravo46さんのGitHubGist」
(https://gist.github.com/Buravo46/10269295)
→このページの下部にあるリンク先の動画、めちゃくちゃ参考になりました。
音声は全部英語ですが、画面上の操作を見ているだけでも、オブジェクトプーリングがどんなものなのかがよくわかると思います。オススメ!!!

3. 使用していないGameObjectはSetActiveでfalseにしておく

「2. オブジェクトプーリングの導入を検討する」の内容とも被る内容……というより、「オブジェクトプーリング」を導入したらその時点でこの問題は解決してるも同然ですが、一応書いておきます。

それは「使われていない(表示されてない)GameObjectは無効にしておく」ということです。

ここでいう「無効」というのは、Inspector上で↓ここのチェックをOFFにすることと同義です。

Inspector上の有効/無効

ここでGameObjectの有効/無効を切り替えられる

これをスクリプト上で行う時は、このようにします。

gameObject.SetActive(false);

逆に有効にしたい時はこう。(当然ですがw)

gameObject.SetActive(true);

先ほど述べた「1. Instantiateは使わない!」の原則を守ろうとすると、どうしても1シーン内に登録されるGameObjectの数が多くなりがちです。
そんな時、画面に表示されていないGameObjectまで全て有効化されていると、その分無駄な「Update」が呼び出されて余計な計算コストがかかります。
なので、不要になったGameObjectは速やかに「SetActive(false)」しておきましょう。

1つ注意点をあげるとしたら「SetActive(false)」されているGameObjectは、find等での検索時に引っかからなくなる点です。
ただしpublic変数等にしておき、Editor上でドラッグ&ドロップして紐付けた場合は、問題なく参照できるので、工夫してみてください。

4. コンポーネント毎にも有効/無効を設定できる

上記「3. 使用していないGameObjectはSetActiveでfalseにしておく」と同じ考え方ですが、コンポーネント毎にも有効/無効を設定できます。
通常、そこまで最適化が必要な局面はないかと思いますが、例えばたくさんのGameObjectが1画面に表示されている状態で、あるタイミングでだけそれぞれに設定された任意のコンポーネントを動作させたい、というような場合。
任意のコンポーネントを常に有効化して待機しておくより、常時無効化しておいて、必要になったタイミングでだけ有効化したほうが、計算コスト的にはメリットがあるということです。

ちなみにスクリプトでコンポーネント毎に有効/無効を切り替える方法は以下のとおりです。

  • 無効化する時
GetComponent<任意のコンポーネント>().enabled = false;
  • 有効化する時
GetComponent<任意のコンポーネント>().enabled = true;

長くなってきたので、続きは次回!

……ふぅ。(ー。ー)

本当は一気に1記事で書き上げるつもりでしたが、あんまり長くても読むのが辛いと思うので、この続きは次回の記事で。

多分、すぐにアップします。

それでは、また。ガンズターンのRyosukeでした! m(_ _)m

Pocket

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です

トラックバックURL: http://gunsturn.com/2015/09/11/studying_unity_006_1/trackback/