Unityにおける Destroy と MissingReferenceException の理解と活用方法

1. 概要

Unityでオブジェクトを削除する Destroy の正しい使い方や、削除に伴うエラー(MissingReferenceException)を防ぐ方法を解説します。また、インスペクターやコンソールでのエラーや警告の違いについても触れます。


2. Destroy の基本動作

Destroy は、指定されたオブジェクトを 次のフレームのタイミング で削除します。削除直後のフレーム中では、オブジェクトにまだアクセス可能なため、適切な処理が必要です。

基本的なコード例

using UnityEngine;

public class DestroyExample : MonoBehaviour
{
    public GameObject myObject;

    void Start()
    {
        // myObjectを削除
        Destroy(myObject);

        // 現在のフレームではまだアクセス可能
        Debug.Log("Current frame: " + myObject.name);

        // 次のフレームで確認
        Invoke("CheckAfterDestroy", 0.1f);
    }

    void CheckAfterDestroy()
    {
        // 次のフレームでオブジェクトは削除済み
        Debug.Log("Next frame: " + myObject.name); // MissingReferenceException が発生
    }
}

3. 注意点とエラーの回避

3.1 NullReferenceException と MissingReferenceException の違い

エラータイプ原因
NullReferenceException変数が null の状態でプロパティやメソッドにアクセスした場合に発生。
MissingReferenceExceptionUnityオブジェクトが Destroy によって削除された後、まだ参照を持っている場合に発生。

3.2 NullReferenceException の例

using UnityEngine;

public class NullReferenceExample : MonoBehaviour
{
    private GameObject myObject;

    void Start()
    {
        // myObjectが初期化されていないため、以下でエラーが発生
        Debug.Log(myObject.name);
    }
}

3.3 MissingReferenceException の例(GetComponentの場合を含む)

using UnityEngine;

public class MissingReferenceExample : MonoBehaviour
{
    public GameObject myObject;

    void Start()
    {
        // オブジェクトを削除
        Destroy(myObject);

        // 次のフレームで参照しようとするとエラーが発生
        Invoke("CheckAfterDestroy", 0.1f);
    }

    void CheckAfterDestroy()
    {
        Debug.Log(myObject.name); // MissingReferenceException が発生
    }
}

さらに、GetComponent を使用してコンポーネントを取得しようとした場合も同様のエラーが発生することがあります。

using UnityEngine;

public class GetComponentExample : MonoBehaviour
{
    void Start()
    {
        // Rigidbodyが存在しない場合
        Rigidbody rb = GetComponent<Rigidbody>();

        // rbがnullなので以下でエラーが発生
        Debug.Log(rb.mass); // MissingReferenceException が発生
    }
}

4. インスペクターとコンソールでの違い

4.1 コンソールでの表示

MissingReferenceExceptionコンソールウィンドウ にエラーとして表示されます。

  • 例: MissingReferenceException: The object of type 'GameObject' has been destroyed but you are still trying to access it.

4.2 インスペクターでの表示

インスペクターでは、以下の状況で「Missing」と表示されることがあります:

スクリプト自体が削除されている場合

  • 「Script: Missing」と表示されます。

参照オブジェクトが失われている場合

  • スクリプト内のフィールドで指定されていたオブジェクトが削除されている場合、フィールドが「Missing」となります。

5. DestroyとDestroyImmediateの違い

メソッド動作
Destroyオブジェクトを次のフレームで削除します。現在のフレームではアクセス可能です。
DestroyImmediateオブジェクトを即座に削除します。現在のフレームで参照するとエラーが発生します。

DestroyImmediate の例

using UnityEngine;

public class DestroyImmediateExample : MonoBehaviour
{
    public GameObject myObject;

    void Start()
    {
        DestroyImmediate(myObject);

        // 即座にエラーが発生
        Debug.Log(myObject.name); // NullReferenceException が発生
    }
}

6. 削除後の適切な参照チェック方法

削除後にエラーを回避するため、null チェックを行うことが重要です。

6.1 基本的な Null チェック

if (myObject != null)
{
    Debug.Log("オブジェクトはまだ有効です。");
}
else
{
    Debug.Log("オブジェクトは削除されています。");
}

6.2 Unity特有の Null チェック

Unityのオブジェクトでは if (myObject) を簡潔に利用することもできます。

if (myObject)
{
    Debug.Log("オブジェクトはまだ有効です。");
}
else
{
    Debug.Log("オブジェクトは削除されています。");
}

7. まとめ

Destroy 使用時のポイント

  1. Destroy は次のフレームでオブジェクトを削除します。削除直後にアクセスするときは注意。
  2. 即座に削除する必要がある場合は DestroyImmediate を慎重に使用。
  3. 削除されたオブジェクトを参照する場合は、null チェックを徹底する。

よくあるエラーの回避策

  • NullReferenceException を防ぐには、変数の初期化を忘れない。
  • MissingReferenceException を防ぐには、削除されたオブジェクトへの参照を適切に管理する。

学習のための課題

  1. 各サンプルコードをシーンに配置して動作を確認してください。
  2. DestroyDestroyImmediate の違いを再現し、挙動の違いを体験してください。
  3. コンソールとインスペクターでの表示の違いを確認してください。

この資料を活用して、エラーの原因と解決方法を理解し、実践的なスクリプト作成に役立ててください。

Unity

Posted by hidepon