【Unity】作ったゲームが重い・カクカクするときの対処法まとめ

ゲームが重いときの対処法 ゲーム制作メモ

Unityでゲームを作っていると「ゲームの動作が重い」「描画がカクカクする」といった問題に直面することがよくあります(※特に3Dゲームの場合)。このような問題は快適なゲームプレイを妨げるので最優先で対処したいところですが、ゲームが重くなってしまう原因は色々あるので知識がないと太刀打ちできないことが多いです。特に初心者の方は訳が分からず途方に暮れてしまうのではないでしょうか。

そこで今回はゲームが重くなってしまった時にぜひ試してほしい対処法(=最適化の手法)を一通り紹介していきますね。

スポンサーリンク

はじめに:プロファイラーで「何の処理が重いのか」をハッキリさせる

では早速対処法を紹介していきたいところですが、その前に必ずやってほしいことがあります。それはプロファイラーを使って「どの処理が重いのか?」を明確にすることです。

というのは、冒頭でも言ったようにゲームが重くなる原因は実に様々だからです。そこで、まずはUnityのプロファイラーを使って大まかな目星を付けておきましょう。

プロファイラーの使い方

プロファイラーとは、ゲームの処理負荷・処理内容等をグラフで視覚的に分析できる機能です。プロファイラーウィンドウはメニューバーの「ウィンドウ」→「分析」→「プロファイラー」から開くことができます。ゲームを実行するとリアルタイムで負荷などが表示されます(下図)。

Unityのプロファイラーの例

プロファイラーの項目は

  • CPU使用率
  • レンダリング
  • メモリ
  • オーディオ
  • 物理

など色々あるのですが、とりあえず真っ先に見て頂きたいのが一番上の「CPU使用率」のグラフです。このグラフは横軸が時間縦軸が負荷を表しており、色によってどの処理がどのくらいの負荷を生み出しているかが一目で分かります。デフォルトだと色分けは

  1. 青:スクリプト
  2. 緑:レンダリング
  3. オレンジ:物理演算
  4. 水色:アニメーション
  5. 明るい黄色:VSync(垂直同期)
  6. 暗い黄色:その他の処理(エディタの負荷など)

などとなっていると思います。

ちなみに、色分けされた項目のうちVSyncとOthersはゲーム自体の負荷には関係ないので、左の色のついた■の部分をクリックして表示をOFFにしたほうが見やすくなります。

どの処理が重くなっているのかを確認する

さてプロファイラーの使い方を覚えたら、実際にデータを取りながらゲームを実行してみましょう。このときグラフが目標となるフレームレート(=FPS)の横線を大きく超えてしまったら要注意です。ゲームを一時停止し、目標のFPSの横線を超えた瞬間にどの色の割合が大きくなっているのかを確認してください。

そうしたら、下の項目に当てはまる部分を読んで対処法を試してみてください。

  1. 目標のFPSが出ているのにカクカクする場合
  2. 全体的に目標のFPSが出ていない場合
    1. レンダリングが重い場合
    2. スクリプトが重い場合
  3. 一瞬だけ処理落ちしたようになる場合

目標のFPSが出ているのにカクカクする場合

まず、目標のFPSが出ているのにカクカクする場合は下記をお試しください。

  • カメラの移動処理を見直す
  • 物理演算の「固定タイムステップ」を変更する

カメラの移動処理を見直す

カメラをキャラクターに追従させるといった処理を行う場合、そのスクリプトが悪いせいでカクつくことが多いです。カメラのスクリプトを見直してみましょう。

改善のヒント:
もしかしてカメラの移動処理をUpdate関数内でやっていませんか?カメラの場合はLateUpdate関数内で移動処理を行いましょうUnityのマニュアルに次のような記述があります。

LateUpdate: LateUpdate は Update 終了後に、1 フレームにつき 1 度呼び出されます。Update で実行される計算は、LateUpdate が始まる前に完了します。LateUpdate の一般的な使用方法は三人称カメラの追跡です。Update 内でキャラクターを動かし、回転させる場合、LateUpdate ですべてのカメラの移動と回転の計算を行えます。これにより、キャラクターが完全に移動してからカメラが追跡することができます。

要するに、他のゲームオブジェクトの移動計算が終わってからカメラを動かせば描画がカクつかないというわけですね。

物理演算の「固定タイムステップ」を変更する

カメラが原因ではない場合は物理演算が原因かもしれません。プロジェクト設定ウィンドウ(メニューバーの「編集」→「プロジェクト設定」)を開き、「時間」を選択して「固定タイムステップ」を「0.0167」にすると、物理演算で動かしているゲームオブジェクトのカクつきが改善されて滑らかになる場合があります(※この方法は処理を軽くするわけではないので注意)。

固定タイムステップの設定例

ちなみに0.0167という数値の根拠ですが、単純に1秒を60フレームで割った値です。つまりおおよそ1フレームに1回物理演算を行うようにすれば、物理演算で動かしているゲームオブジェクトが描画とマッチして滑らかに動くようになるというわけです。

全体的に目標のFPSが出ていない場合

次に全体的に目標のFPSが出ていない場合の対処法を見ていきましょう。

レンダリングが重い場合

プロファイラーのグラフで緑色の部分の割合が大きい場合、つまりレンダリングが重い場合は原因がいくつか考えられます。

  1. たくさんのメッシュを表示している
  2. たくさんのマテリアルを使っている
  3. 高解像度のテクスチャをガンガン使っている
  4. リアルタイムのライティングを使っている
  5. 複数のカメラを使っている

このうち一番よくあるのが1.の「たくさんのメッシュを表示している」場合です。ここではこの場合に焦点を当てると、解決策としては

  • メッシュの数を減らす
  • メッシュを結合する

などがあります。

メッシュの数を減らす

何よりもまずは「そもそも大量のメッシュを描画しない」ようにするのが先決です。

  • 大量のメッシュをシーンに配置しない
  • カメラのカリング機能を活用して必要ない部分を描画しないようにする
  • LOD(※遠くのメッシュを雑なものに切り替える機能)を活用する

といったことを行ってみてください。

また、Terrainを使っている場合は設定によってポリゴン数を減らして負荷を軽くすることができます。詳しくは以前の記事「重いTerrainの描画処理を少しでも軽くする方法」を参照してください。

メッシュを結合する

しかし、そうは言ってもたくさんのメッシュを表示したいときもあります。そんなときは複数のメッシュを一つのメッシュに結合しましょう。

有料ですがアセットストアにメッシュ結合ツール(Mesh Baker、Easy Mesh Combiner等)があるので調べてみてください。

スクリプトが重い場合

次にプロファイラーのグラフで青色の部分の割合が大きい場合、つまりスクリプトが重い場合も色々な原因が考えられます。スクリプトを見て、次のような処理を行っていないかを確認してください。

  1. 毎フレーム、もしくは頻繁にGetComponentやGameObject.Find等の重い処理を行っている
  2. 重い計算(Vector3.Distance、Mathf.Sqrt等)を1フレームの間にたくさん行っている
  3. 頻繁にInstantiateやDestroyを呼び出している

1や2の場合は、1回処理を実行した後に結果をキャッシュしておくことをお勧めします。また、3の場合には「オブジェクトプール」というやり方があるのでググってみてください。

一瞬だけ処理落ちしたようになる場合

さて最後は一瞬だけ処理落ちしたような感じになる場合です(プロファイラーのグラフが「とがった形」になる=スパイクといいます)。この場合は原因の特定が結構難しいのですが、主に

  • 一瞬だけ重い処理が呼び出された(特にスクリプト)
  • ガベージコレクション(=メモリ上のゴミを掃除する機能)が走った

等が考えられます。いずれにしてもどういうタイミングでどんな処理が行われたのかをよく観察して、地道に分析していきましょう。

もしかしたらプロファイラーの「ヒエラルキー」を見ると何か手がかりをつかめるかもしれません。ここではその辺については割愛しますが、気になる方はググってみてください。

おわりに:プロファイラーを上手く使ってゲームを軽くしよう

以上、ゲームが重くなってしまう原因とその対策について私が知っていることを一通りご紹介してきました。ここでは個々の原因についてあまり詳しく踏み込むことはできませんでしたが、何かしら参考になれば幸いです。