Unityでゲーム開発をしているときに動作が安定しないと感じたことはありますか?私はたまにあります。
私の場合は処理の重いコードを書いていてその部分を修正すると比較的安定するのですが、結局のところ、原因は皆さんの開発状態によると思います。
このような場合皆さんはどうしているでしょうか?今回は私が使っている比較的簡単に動作を見直す方法をまとめてみました。
プロファイラを見て何が原因かを調べる
まず何が原因で動作が重いのかを見つけていきましょう。そのためにまずはUnityのプロファイラを見てどこが原因になっているかを見つけていきます。
見つける方法はプロファイラというゲームの実行状況を視覚的にわかりやすく見ることができるものを使用します。
プロファイラは「Window→アナリティクス→プロファイラ」で開くことができます。開くとこのような画面が表示されます。

プロファイラがRecord(PlayModeの隣の赤色の◯)状態で実行すると上の画像のような感じで表示されます。
上の状態だとCPUUsageの真ん中あたりが大きく乱れています。
この場合特定の箇所で大きく処理負荷がかかっているので原因を特定して修正してあげると上の尖ってる部分がなくなってラグが発生しなくなります。
これを見てどの項目(Rendering、Rigidbody、Scriptなど)が原因でラグが発生しているのか見つけてみましょう。
項目ごとに色分けされているのですぐに怪しい箇所にあたりをつけることができると思います。
レンダリング編
カリングをして画面外の見えないオブジェクトは描画しない
画面外のオブジェクトはどうせ見えないので描画しないようにするほうが処理が軽くなります。
他にもLODを使用することでも軽くなるので自分が作っているゲームの規模に対して使用するかどうか検討しましょう。
物理編
FixedUpdateの実行間隔の値を調整
コレは設定から変更できますが、例えば0.02であれば0.02秒間隔で実行されます。値を小さくすれば正確な物理表現ができますが処理負荷がかかります。
「処理を軽くしたいとき」や「物理演算にそこまで正確性を求めない」場合は物理表現が雑にならない程度に値を大きくしてみると少し処理が軽くなるかもしれません。
UI編
CanvasにUIをまとめるときはよく考える
UIは頂点の移動や表示、非表示などなにか変化があった場合にリビルドされます。
このリビルドという動作は重くてCanvas単位で実行されます。
なのでCanvasの子要素に一つでも頻繁にアニメーションしたり表示と非表示を切り替えをするオブジェクトがあった場合、他のオブジェクトが一切変更がなかったとしてもまとめて再構築されてしまいます。
なのでDOTWeenなどでアニメーションするUIはそれ単体で表示させたほうが処理負荷は下がります。
UIのGraphicRayCasterは必要なければオフにする
処理負荷も下がりますし、特にボタン系のUIは重なっていると反応しないなどよくわからないバグが発生してその原因になる可能性もあるのでRay系は必要なければ削除していまいましょう。
C#、コーディング編
なるべくInstantiateやDestroy関数を使うのは控える
どちらも重い処理なので頻繁にオブジェクトを生成したり破棄を繰り返すのはやめましょう。
生成する数がある程度決まっているならObjectPoolを使いましょう。ObjectPoolはUnityの機能やUniRxに入っているので試しに使ってみることをおすすめします。
GetComponentやGameObject.Findを使うのは控える
これらの機能をUpdateなど毎フレーム実行する状況で使わないようにしましょう。
GetComponentは内部でオブジェクトにアタッチしているコンポーネントを検索しているのでコンポーネントの数が増えるほど処理負荷がかかります。
Findもシーンのオブジェクトを全検索しているのでオブジェクトの数が増えるほどこちらも同様に処理負荷がかかります。
Awake、Startで最初に検索結果を変数にキャッシュしておくことで負荷を軽減できます。
他にも[SeliarizeField]属性を使ってインスペクターから設定しておくのもいいと思います。
.transformや.rigidbodyも使用を控える
こちらも内部的にはGetComponent関数を呼ぶことと変わらないのでStart関数などで変数にキャッシュしておくことで負荷を軽減できます。
なのでよく使う機能や変数に関してはキャッシュしてみることをおすすめします。
他にもQuaternion や Vector3、使い方によってはposition、rotation単位でキャッシュしたほうが処理効率が良くなると思います。
文字列の比較は控える
文字列の比較は処理負荷が重くなりやすいです。それだけならまだ妥協できるかもしれませんが、スクリプトに直接書くとタイピングミスや仕様変更に弱くなってバグの原因になる可能性が出てくるので気をつけましょう。
比較するときは文字列ではなくタグを使用してCompareTagで比較したり、ハッシュ値を使うとミスも減らせて効率よく比較できるので便利です。
空のイベント関数(Start、Update)は消しておこう
スクリプトを作成して開くとデフォルトでStartとUpdateが作成されますが、何も処理を書いてないStart、Updateを残していても何も処理しないイベント関数を実行するだけです。使わないのであれば削除しておくと処理負荷は若干下がります。
使わなければ忘れずに消しておきましょう。
距離の比較ではsqrMagnitudeを使おう
具体的には「計算時に√(ルート)が入ってると計算量が増えてしまう」ので例えばDistance関数も距離を計算する関数で計算結果が同じでもこちらのほうが処理が重いです。
なのでどんな計算をしているか理解して計算量が多いものは別の方法で解決できないか考えましょう。
まとめ
どうでしたか?このように調べると様々な改善策が出てくると思います。少しの工夫で安定してゲームが動くようになるので今後も改善策を見つけたら追記していこうと思います。