Unity 実機テストでアプリ停止!アプリがフリーズした際の対処法(軽量化)
どうも皆さん、マカロンです。
今回は久々にunityの技術的な記事になります!
それではさっそく行きましょう!
はじめに
まず現在どこで負荷がかかってしまっているのかをたしかめるために
Window→Analysis→Profilerを起動します。
ここでは現在のアプリの負荷を確かめることが出来ます。
左の項目とグラフを照らし合わせながら、自分のプロジェクトのどこに負荷がかかっているかを探しましょう。
「Others」は内部処理なのでオフにしてからグラフを眺めるのがいいかと思います。
一番よく聞く「GetComponent」「GameObject.Find」問題
この二つが重いというのは結構有名な話ですが、初心者はこの二つを使いがちです。理由は2つで「感覚的にわかりやすくて簡単」なことと「ネットに転がっている簡単なサンプルがこれを使用していることが多い」ということです。
しかし、これはほんとに重い処理なんだなということを身をもって実感したのでこれはぜひ一番最初に改善していただきたいポイントです。
改善の仕方も簡単なので少し紹介します。
そもそもGameObject.Findとは
GameObject.FindはGameObjectをすべての中から検索をかけるのでStartなどで処理するにはまだ問題ないですが、Updateなど繰り返し処理する部分に入れてしまうと本当に重くなってしまうので今Updateに入れてしまっている皆さんはすぐに改善しましょう
GameObjectではなくそれに割り当てたScriptを呼ぶ
まず、GameObject.Findを使わない方法としてGameObjectをpublicなどで指定するなどが考えられますがこれはダメです!
なぜならこれだとまだGetComponentを使用しなくてはならないからです。
なのでpublicで指定するのは使用するScript名にしましょう
public Config config;//ConfigというScriptを入れる箱を用意
ここでは「Config」というScriptの入れるpublicを用意しています。
ここに「Config」を追加してある他のGameObjectを指定することで無駄な検索処理をカットしてほかのScriptの変数などを呼ぶことが出来るようになります。
「PlayerSettings」内でできる軽量化
まずはPlayerSettings内でできる軽量化について紹介していきます。
Quality-Levels-
処理速度はだいたいこのQualityで決まります。
以前の記事でも紹介したのですが、動作や処理速度を変更するLevelsでどれを選択したかによって動作がかなり変わります。なので、今現在自身が作ったものがスマホで試してみたら動作しない方はLevelsを一番制度の低いVeryLowを選択しましょう。
Script側が原因の場合も多々あるのでそっちが原因だった場合は段階的にLevelsの制度を上げてうまく調整してみてください!
Quality-Texture Quality-
この値はテクスチャの解像度を表します。凝ったエフェクトなどを入れていないならば見た目が変わらない程度にHalf Res (1/2 解像度)、Quarter Res (1/4 解像度)に値を変更して負荷を軽減してもいいと思います。
Quality-Resolution Scaling Fixed DPI Factor-
元の解像度を1として画面解像度を変更することが出来ます。
現在のスマートフォンならばここの値を0.5に変更したくらいでは表示される画面解像度はほとんど変わらないので、遠慮なく値を下げて軽量化しましょう!
Quality-V Sync Count-
これも上で紹介した記事で取り上げたのですが、ここの値をオフにして自分でフレームレートを指定したほうが軽量化と動作安定につながるのでここは推奨設定です。Script内でのフレームレートの指定の仕方なども上の記事で紹介しているのでぜい参考にしてみてください!
Scriptでできる軽量化と問題点
Unity側でどんなに設定してもScript内に無駄な工程が多いとその分だけ処理は重くなります。なので重くなっている原因などについて考えていきたいと思います。
必要のない代入
for (int i = 0; i < 300; i++)
{
a[i] = b[i];
}
例えばこういう感じの変数から変数への代入がUpdateで常に回っていると、負荷の原因となります。リアルタイムでパラメータを割り当てたりする際によくやってしまうミスです。
これが値の受け渡しならまだ問題ないのですが、画像などの受け渡しになると非常に無駄な負荷がかかってしますので、
for (int i = 0; i < 300; i++)
{
if (a[i] != b[i])
a[i] = b[i];
}
こんな感じにしておけば変更が起きた場合にしか値の受け渡しをしないので最低限これくらいはしておきましょう
一つ表示すればいいものを複数表示する
これはデバックしている段階で気づくケースがほとんどですが、フラグを立てずに同じコードが何度も呼ばれていることがあります。
Unity上でなら明示的に確認することが可能ですが、実機で動かさないと確認できない動作は重なって何度も表示されたりするケースがあるかもしてないので負荷が重い場合は疑ってみてください。
無駄な参照データ
たとえば敵を表示する際にEnemy.cs内でパラメータを持たせてしまうとエネミーを表示すればするほど変数がいっぱい増えてしまいます。
なのでその場合は別にパラメータを確保しておいてそれをEnemy.cs内で参照することで処理が軽くなったりします。
unityにはパラメータを管理する拡張機能としてScriptableObjectというものもありますので気になる方は調べてみてください!
フレームレートが高すぎる
基本フレームレートは60以下です。なので
Application.targetFrameRate = 60;
と書くと思うのですが、ここの値が90や120になっていると一気に処理が重くなってしまうので60より上には設定しないようにしましょう。
また60でも重い場合は値を段階的に下げることで処理を軽くできるかと思います。
画像でできる軽量化
最後は画像です。
画像のInspectorの下にこのような項目があると思います。
このMaxSizeの初期値は2048となっていますが、そんなに大きく表示しないなって画像はMaxSizeを下げてください。
大量に画像を使うプロジェクトであればそうすることで負荷を軽減することが出来ます。(ぼやけない程度度に)
最後に
いかがだったでしょうか
今回はアプリを実行した時にフリーズした実体験をもとに記事を書きました
こういう何でもない作業が一番大変でめんどくさかったりする。。。
ではまた!
ゲームを作るにはやはりお金がないとできることが限られてしまいます。なのでよろしければどうか支援してくださるとうれしいです