Article by: Abuld D.
Unity では、開発中に思いがけない挙動に出会うことがあります。ホットリロード直後のプレイモードのフリーズ、突然広がるピンク一色のマテリアル、あるいは「transform はずっと null でしたよ」と丁寧に思い出させてくるスタックトレースなど。そんな瞬間にスプリントの残りが崩されないように、本記事では実行時によくある厄介者を4つに絞り、それぞれをどう再現し、どう見分け、どう直すかを具体的に紹介します。
扱う内容は次のとおりです。
- NullReferenceException: Object reference not set to an instance(オブジェクト参照がインスタンスに設定されていません)
- IndexOutOfRangeException: Array index problems(配列/リストのインデックスが範囲外です)
- MissingComponentException: Component not found(必要なコンポーネントが見つかりません)
- MissingReferenceException: Destroyed object access(破棄済みオブジェクトへの参照にアクセスしています)
具体性を担保するために、まっさらな HDRP サンプルプロジェクト上で各エラーをすべて作り直し、余計なものを省いた SentryCube スクリプトを組み込んで、問題(と修正)がリアルタイムでどう起きるかを確認できるようにしました。コードをそのままコピーしても良いですし、コンソールに出ている内容に一致するスニペットだけ流し読みしても良いですし、解決策セクションに飛んでも構いません。とにかく、より早く開発に戻れるやり方で進めてください。
1. Unity で NullReferenceException(Object reference not set to an instance)を修正する方法
このエラーはスクリプトが null の参照を使おうとしたときに発生します。ゲームのコンソールやログファイルでは、通常次のような表示になります。
UnassignedReferenceException: The variable target of SentryCube has not been assigned.
これはよくあるケースで、GameObject にスクリプトが付いていて public Transform target フィールドを宣言しているのに、そこに何も割り当てていない(未設定の)ときに起こります。

Start() が実行される時点で target は null のままなので、position への呼び出しが失敗し、Unity は処理を止めて上記の UnassignedReferenceException メッセージを表示します。
解決策
NullReferenceException が発生する主な原因は次のとおりです。
- public Transform target フィールドが Inspector で一度も設定されておらず、変数が「何も参照していない」状態になっている
- 参照しているオブジェクト(public Transform target)がプレイ中に別スクリプトで Destroy されているにも関わらず、変数がクリアされていない
- スクリプト実行順の問題で、このスクリプトが public Transform target を設定するはずのスクリプトより先に動いてしまっている
この問題を修正するには、参照を割り当てるか、または null を考慮してガードする必要があります。
まずは参照を割り当てます。
Inspector ウィンドウで、target スロットに正しい Transform をドラッグ&ドロップします。

Inspector で target が未設定の状態
- 別の方法として、最初に使う前にコードで設定することもできます。

参照が割り当てられていることが確認できたら、実行時にオブジェクトが消える可能性がある場合は、null 値に対するガードも入れておくべきです。

Unity の Editor は未割り当て参照に寛容で、役に立つ警告も表示してくれます。一方で、実行ビルドでは Unity は通常、null 参照エラーを握りつぶすように扱い、行番号なしでログに残すだけになりがちです。その結果、UI 要素が欠けたり、オブジェクトが期待どおりに表示されなかったりといった、分かりづらい挙動につながります。
初期化順序の問題が原因でエラーが起きている場合は、target を埋める役割のスクリプトが先に実行されるようにしてください。
方法は2つあります。
- 代入処理を Start() ではなく Awake() に移す
- Project Settings で Script Execution Order を調整する
2. Unity で「配列のインデックスが範囲外」エラーが起きる原因は?
このエラーは、コードが 存在しない配列/リスト要素にアクセスしようとしたときに発生します。
IndexOutOfRangeException: Index was outside the bounds of the array
これは典型的には、GameObject に付いたスクリプトが 固定サイズの配列を作っているのに、範囲を超えたインデックスにアクセスしてしまう場合に起こります。

実行時に scores[3] は有効範囲(0〜2)の外になるため、エンジンは処理を止め、上記のメッセージを表示します。
解決策
IndexOutOfRangeException は、変数(配列/リスト)が保持している要素数よりも大きいインデックスを要求したときに発生します。この配列は固定長で要素数は3つ(インデックスは 0, 1, 2)ですが、存在しない インデックス 3 にアクセスしようとしています。
このエラーを防ぐには、要素へアクセスする前に コレクションのサイズを常に確認するか、必要に応じて伸長できる List<T> を使います。

このコードで SentryCube を動かすと、リストにアクセスする前にインデックスを確認します。インデックスが範囲外の場合は、Unity にエラーを握りつぶさせてしまうのではなく、警告をログに出します。これにより、UI 要素が欠けたり、想定外の挙動が発生したりといった、分かりづらい問題につながるのを防げます。

インデックス範囲エラー
このエラーを避けるポイントは、List なら Count、配列なら Length を使って、アクセスしようとしているインデックスが有効範囲内かを必ず確認することです。インデックスを直接指定して参照する箇所は、シンプルな範囲チェックで必ずガードし、サイズが変わり得る場合は配列より List を優先しましょう。
3. MissingComponentException を修正する方法
MissingComponentException は、スクリプトが GameObject 上に 存在しない Component を使おうとしたときに発生します。たとえば、ゲーム開始時に SentryCube を上方向に跳ねさせたいので、上向きの力を加えるスクリプトを書いたとします。
すると、こうなります。
MissingComponentException: There is no ‘Rigidbody’ attached to the “SentryCube” game object, but a script is trying to access it.
You probably need to add a Rigidbody to the game object “SentryCube”. Or your script needs to check if the component is attached before using it.(MissingComponentException: 「SentryCube」GameObject には「Rigidbody」がアタッチされていませんが、スクリプトがそれにアクセスしようとしています。「SentryCube」GameObject に Rigidbody を追加する必要がある可能性があります。あるいは、使用する前にそのコンポーネントがアタッチされているかをスクリプト側で確認してください。)
これはよくあるケースで、GameObject に付いたスクリプトが Component を取得し、その存在を確認しないまま即座に使おうとしているときに起こります。

SentryCube に Rigidbody コンポーネントが付いていないため、AddForce の呼び出しは参照先が null の状態に当たり、Unity は上記の MissingComponentException メッセージとともにエラーを投げます。

SentryCube には Rigidbody コンポーネントがない
解決策
MissingComponentException は、次のような場合に発生します。
- GameObject にその Component が追加されていない
- 実行中にその Component が削除される
- プレハブやバリアントに基づいて「付いているはず」とスクリプトが決め打ちしている
そのため、修正方法はいくつかあります。
いちばんシンプルなのは、Inspector で必要なコンポーネントを手動でアタッチする方法です。

Rigidbody コンポーネントを追加する
別の方法として、[RequireComponent] 属性を使う手もあります。これは、スクリプトを GameObject に追加したときに、必要な依存コンポーネントも自動で追加してくれます。

ただし、[RequireComponent] は問題を見えにくくすることがあります。というのも、コンポーネントを デフォルト設定のまま自動生成してしまい、意図した構成と一致しない可能性があるためです。たとえば自動で追加された Rigidbody の mass / drag / constraints が想定と違い、予期しない物理挙動につながることがあります。
より明示的な方法としては、コードでコンポーネントの有無をチェックし、存在しない場合を適切に処理します。

この方法なら、依存関係を明示でき、デフォルトの物理設定が意図と違っていたせいでキューブが期待どおりに動かない、といった 気づきにくい失敗(サイレントフェイル)を防げます。
4. オブジェクト破棄時に発生する MissingReferenceException を解決する方法
MissingReferenceException は、スクリプトが すでに Destroy されたシーン上のオブジェクトへの参照を保持したまま、それにアクセスしようとしたときに発生します。
UnassignedReferenceException: The variable projectile of SentryCube has not been assigned.
(UnassignedReferenceException: SentryCube の変数 projectile が割り当てられていません。)
これは典型的には、スクリプトがオブジェクトを Destroy した直後に、そのオブジェクトをすぐ使おうとする場合に起こります。

DestroyImmediate(projectile) はオブジェクトを 即座に削除します。projectile に残っている参照は一見まだ有効に見えますが、そこに対して何らかの呼び出しを行うと MissingReferenceException エラーが発生します。
解決策
MissingReferenceException は、すでに存在しないオブジェクトにアクセスしようとしたときに発生します。参照先の GameObject が Destroy された後も、コードがその参照にアクセスし続けてしまうのは、たとえば次のような状況です。
- シーン遷移が起きたのに、前のシーンのオブジェクトへの参照を保持し続けている
- 親の GameObject が Destroy された後も、Coroutine が動き続けている
この問題を直すには、参照管理をきちんと行い、破棄済みオブジェクトへスクリプトがアクセスしないようにします。まずは Destroy を呼んだ後に参照を null にするところから始めましょう。

また、オブジェクトが想定外に Destroy される可能性に備えて、参照へアクセスする箇所はすべて null チェックでガードしておくべきです。そうすることで、破棄済み参照へのアクセスによるエラーを防げます。

より完全な解決策として、オブジェクトの破棄と参照管理をより安全に行うためのパターンを実装できます。

この方法では、projectile を破棄したうえで projectile の参照をクリア(null に設定)し、アクセスする前に null 参照チェックを行います。これにより MissingReferenceException を防ぎ、コードの堅牢性も高まります。

projectile が破棄されました
Sentry で Unity のエラーデバッグとパフォーマンスを改善する
Unity ではエラー原因の特定が難しいことがあり、またエラーにパフォーマンス問題が伴うことも少なくありません。そこで役立つのが Sentry です。Sentry の Unity SDK は、リアルタイムのエラートラッキングとクラッシュレポートを提供し、次のことができます。
- 例外を自動でキャプチャし、詳細なスタックトレースを表示する
- エラーが発生した状況(シーン情報やコンポーネントの状態など)を確認する
- エラーにつながり得るパフォーマンス問題を追跡する
- 複数のプラットフォーム/デバイスにまたがってエラーを監視する
- ボトルネックを特定してゲームのパフォーマンスを改善する
プレイヤーからの報告を待ったり、再現が難しいバグの再現に何時間も費やしたりする代わりに、Sentry はエラー発生時にすぐ通知し、迅速に修正するために必要なコンテキストを提供します。
Unity 向け Sentry を始める
Unity プロジェクトへの Sentry の導入は簡単です。まず、Unity Package Manager から SDK をインストールします。
- Package Manager を開く(Window → Package Manager)
- 「+」ボタンをクリックし、Add package from git URL を選択する
- 次を入力する:
https://github.com/getsentry/unity.git
次に、Sentry プロジェクトの詳細情報を使って SDK を設定します。

この設定により、Sentry は NullReferenceException や IndexOutOfRangeException のような未処理例外を自動的にキャプチャします。
また、明示的にエラーを追跡したい場合は、特定のエラーを手動でキャプチャすることもできます。

先ほど触れた MissingComponentException のようなエラーでは、Sentry はエラー発生時点の シーン階層(Scene Hierarchy) を丸ごと提供してくれるため、どの GameObject に必要な Component が足りていないのかを特定しやすくなります。

エラーが発生すると、Sentry のダッシュボードに詳細なレポートが表示されます。これらのレポートには、次の情報が含まれます。
- エラーが発生した正確なファイル名と行番号
- エラー発生時点のシーン階層のスナップショット
- プラットフォーム依存の不具合を特定するためのデバイス固有情報
- クラッシュに至るまでのユーザー操作(breadcrumbs)
- プレイヤーが見ていた画面を示す任意のスクリーンショット
Unity ゲームのエラー監視に Sentry を活用する方法をさらに知りたい場合は、Unity におけるエラー/クラッシュレポート向けに Sentry を使うガイドをご覧ください。あわせて、Sentry がゲーム開発者をどのように支援しているかも確認できます。Sentry Unity SDK を始めるには、ドキュメントを参照してください。
Original Page: Common Unity errors and how to fix them
IchizokuはSentryと提携し、日本でSentry製品の導入支援、テクニカルサポート、ベストプラクティスの共有を行なっています。Ichizokuが提供するSentryの日本語サイトについてはこちらをご覧ください。またご導入についての相談はこちらのフォームからお気軽にお問い合わせください。


