ガンズターン 公式サイト

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

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

Pocket

前回記事の続きです。

この記事はコチラの記事(Unity備忘録 #6-1 Androidアプリ作るときに気をつけること①)の続きです。
もしまだご覧になっていない方は、そちらから先にどうぞ。

5. ParticleSystemを使うときは Max Particle をできるだけ下げる

引き続き、UnityでAndroidアプリを作る時に気をつけること
ParticleSystem(Shurikenのこと)を使う時は、Max Particleをできるだけ下げる

というか、ParticleSystem自体が重いので、本当に効果的な場面でしか使わない
(もちろんゲームにとってエフェクトは非常に重要な要素なので、必要だと思った時はガッツリ使うことも重要ですが、そこは処理能力との駆け引きで)

Max Particleを下げると、一度に生成されるParticleの最大数を抑えることができます。

Particleとはいえ、その一つ一つがMesh(BillBoard)であり、3Dオブジェクト(ポリゴン)であることに変わりはないので、多すぎるとダイレクトに処理能力に影響します。

なので、Particle Systemを使う時はなるべく「Max Particle」を少なく、見栄えが悪くならないギリギリのラインを狙って設定してみるのがよいかと思います。

6. Project Settings の Fixed Timestep を可能な限り長くする

これ、わたしは不勉強ながら今回教わって初めて知ったんですが、Unityの中には時間軸が2つ流れているそうです。

  • Unityの中で流れている時間軸
    1. フレームを更新するための時間軸(通常のUpdateを呼び出すサイクル)
    2. 物理演算を更新するための時間軸(FixedUpdeteを呼び出すサイクル)

このうち、どんなゲームでも必ず使うのは「1. フレームを更新するための時間軸」の方で、わたしはこれまでこの時間軸しか認識していませんでした。

しかし、実際には裏で常に「2. 物理演算を更新するための時間軸」が走っており、気づかないところで「FixedUpdate」というメソッドが呼ばれていたんですね。

この「FixedUpdate」、物理演算を多用するゲームであれば重要なメソッドかと思いますが、そうでないゲームの場合は、ぶっちゃけ存在しなくてもまったく問題ないです。
(Colliderとか多用してるとまた話は別ですが)

わたしの作成してるようないわゆるカジュアルゲームの場合は、複雑な物理演算をすることはまれだと思うので、そういう場合は思い切ってこの「FixedUpdate」が呼ばれる頻度を少なくしちゃいましょう。

Unityのメニューから、
「Edit」->「Project Settings」->「Time」
を選ぶと、Inspectorにそのための設定が表示されます。
「Fixed Timestep」とある欄がそうです。

設定項目の場所

ここに「Time」という設定があります。

Inspector上のFixedTimestep

Inspector上ではここに表示されます。

デフォルト値は「0.02」秒なので1秒間に50回更新される頻度ですが、わたしの作っているゲームの場合、これを「1.0」秒に変更してもまったく支障ありませんでした。
(たぶん、もっと大きくしても問題ないです)

この設定だけでも計算資源を節約できると思うので、物理演算を多用していない場合はぜひこの設定をいじってみてください。

7. Project Settings の Maximum Allowed Time Step を可能な限り短くする

はい。これも教わるまで知りませんでした。
通常、Unityでの1フレーム60分の1秒(60FPS)か、30分の1秒(30FPS)です。
(何も設定してなければ、デバイスの特性に応じてこのうちどちらか、適切な方が自動で適応されるはずです。……多分。笑)

例えば60FPSの場合、1フレーム内の処理は0.0167秒程度で終わらないと、次のフレームの描画に支障が出ます。
負荷の重い処理が走った時、画面がカクついて見えたりするのは、主にこのことが原因です。
(いわゆる処理オチといわれる現象ですね)

Unityにはこの処理の遅延を何秒まで許容するか、という設定が存在します。

先ほどと同じく、Unityのメニューから、
「Edit」->「Project Settings」->「Time」
と選択しましょう。

Inspector上のMaximumAllowedTimestep

Inspector上ではここに表示されます。

Inspectorウィンドウに「Maximum Allowed Timestep」という項目があると思います。
こいつが、そのための設定です。

この設定は、ぶっちゃけ短ければ短いほど、パフォーマンスの向上に寄与するようです。
(例えば遅延を4フレーム以内に抑えたい時は0.0167×4=0.067など)

ただ1点、注意が必要なのは、Update内の処理がここで設定した秒数以上かかった場合は、例外なくその処理は見捨てられてしまうということです。

ご自身のプロジェクトで最も負荷のかかる処理は何か、それには通常何秒ぐらいかかるか、Androidで想定している端末のうち、低スペックのもので何秒かかるか等を考慮して、多少の余裕を持って設定することをお勧めします。

8. (まとめ)とにかくガーベジコレクションを黙らせる!

ここまで長々とUnityでAndroidアプリを作るにあたって気をつけるべきところをまとめてきましたが、つまるところ「ガーベジコレクションを黙らせる!」この一言に尽きるかと思います。

わたしはほぼ素人プログラマなので、知識として「ガーベジコレクションが重い」ことは知っていても、それがどれだけゲームのクオリティに影響するのかや、じゃあどうやったら発生を抑えられるのか、といったことはこれまでよく分かっていませんでした。

しかし今回、ありがたくもプロのプログラマの方から直接アドバイスを頂けたおかげで、ひとつ新たなレベルに続く道が開けたような気がしています。

改めて、講師を担当してくださった方に感謝したいと思います。
大変貴重な学習の機会を与えてくださり、ありがとうございました。 m(_ _)m

この記事が果たしてどれだけの人のお役に立てるかわかりませんが、わたしと同じようにAndroid版が遅くて困っているという人が、道を切り開く一つの助けとなれたなら幸いです。

んでは、今日はこのへんで!
久々に大量の文章を書いて、ちょっと疲れてしまったガンズターンのRyosukeでした!

9. (おまけ)ガーベジコレクションてなに?

wikipediaさんによりますと、「ガーベジコレクション(ガベージコレクション?)」とは、以下のものを指すようです。(抜粋)

ガベージコレクション(garbage collection; GC)とは、プログラムが動的に確保したメモリ領域のうち、不要になった領域を自動的に解放する機能である。

要は、プログラマが明示的にメモリを解放しなくても、裏側でOSなりVMなりが不要になったメモリを解放してくれる便利機能のことです。
(あ、VMっていうのは、Androidでいうところの「Dalvik」のことです。一応)

iOSは今のところ、ガーベジコレクション機能を持っていません。
それに代わるのが、「ARC(Auto Refference Counting)」という仕組みです。

「Android」と「iOS」における、メモリの動的確保・解放のパフォーマンスの大きな差は、主にこの仕組みの違いから来ています。

AndroidにおけるGCめちゃくちゃコストが高いです。
それが動いている間、他のタスクは動かないので、当然描画も動きません。
遅いといっても、数msから数十msなんですが、それでも60FPSで動いているゲームにとっては致命的です。

だから、なるべくGCの発生を抑える必要があります。
しかし、AndroidではこのGCの発生をプログラマが明示的に抑止することができないのです。

そのため、VMがGCを発生させる要因を探って、それを極力なくすことでGCの発生を抑えます
これまで解説してきたように、UnityにおけるInstantiateDestroyは、このGCを発生させるトリガーとなります。
例えばそれを、毎フレーム実施すると、下手をすればその度にGCによる遅延が発生することになり、FPSは半分ぐらいに落ちてしまいます(まあ、これはかなり極端な例ですが)。

なので、オブジェクトプーリングなどの仕組みを使って、なるべく動的なメモリ確保を少なくする必要があるというわけですね。

……正直、わたしはあんまりこの分野に詳しくないので、興味のある方は「ガーベジコレクション」等で検索するとたくさん有用な情報が見つかると思いますので、ぜひ!

Pocket

コメントを残す

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

トラックバックURL: http://www.gunsturn.com/2015/09/11/httpwww-gunsturn-com20150911studying_unity_006_2/trackback/