コガネブログ

平日更新を目標にUnityやC#などのゲーム開発アレコレを書いていきます

【Unity】GameObjectが削除されてnullになったかどうかはnull合体演算子では確認できない

MissingReferenceException: The object of type 'GameObject' has been destroyed but you are still trying to access it.
Your script should either check if it is null or you should not destroy the object.

すでに削除されたゲームオブジェクトを参照しようとすると上記のエラーが表示されます

なので、削除される可能性があるゲームオブジェクトを参照する場合は

if ( mGameObject != null )
{
    // ...
}

このようにnullチェックを行う必要があります

そこで、例えばゲームオブジェクトが存在しない場合は
新しくゲームオブジェクトを生成して代入するという処理を実装する場合は

if ( mGameObject != null )
{
    mGameObject = new GameObject();
    Debug.Log( mGameObject.name ); // 名前を出力
}

このように書くことができますが、この処理をnull合体演算子に置き換えて

mGameObject = mGameObject ?? new GameObject();
Debug.Log( mGameObject.name ); // 名前を出力

このように書いた場合、mGameObjectが削除されてnullになっていたとしても
new GameObject();は実行されず、Debug.Log関数の呼び出しでnull例外になります

Unityの仕様なのかどうかはわからないのですが
ゲームオブジェクトが削除されてnullになっているかどうかを確認したい場合は
null合体演算子ではなく、関係演算子( ==, != )を使用した方が良さそうです

検証用スクリプト

using UnityEngine;

public sealed class NewBehaviourScript : MonoBehaviour
{
    private GameObject mGameObject;

    private void Awake()
    {
        // シーン開始時に Hierarchy から
        // "GameObject" という名前のゲームオブジェクトを検索して保持します
        mGameObject = GameObject.Find( "GameObject" );
    }

    private void Update()
    {
        // Z キーが押された場合
        if ( Input.GetKeyDown( KeyCode.Z ) )
        {
            // ゲームオブジェクトが存在する場合
            if ( mGameObject != null )
            {
                // ゲームオブジェクトの名前をコンソールに出力します
                Debug.Log( mGameObject.name );
            }
        }
        // X キーが押された場合
        if ( Input.GetKeyDown( KeyCode.X ) )
        {
            // ゲームオブジェクトが存在する場合はそのゲームオブジェクトの名前を
            // 存在しない場合は新しいゲームオブジェクトを作成して
            // そのゲームオブジェクトの名前をコンソールに出力します
            var result = mGameObject ?? new GameObject( "GameObject" );

            Debug.Log( result.name );   // ゲームオブジェクトが存在しない場合はここでエラー
        }
        // C キーが押された場合
        if ( Input.GetKeyDown( KeyCode.C ) )
        {
            // ゲームオブジェクトを削除します
            Destroy( mGameObject );
        }
    }
}