Menu
CoddyTech

UnityのNull

CoddyのUnityジャーニー「Unityスクリプトの基礎」セクションの一部。レッスン 60/85。

Unityのオブジェクトには2つの側面があります。スクリプトが保持するC#オブジェクトと、その背後にあるエンジンオブジェクトです。Destroy(obj)はフレームの終わりにエンジン側を削除しますが、変数はまだC#側を指しているため、通常のC#の観点ではnullではありません。Unityはこれに対応するため==をオーバーライドしています。オブジェクトが破棄されると、obj == nullはtrueになり、短い判定である!objもtrueになります。これがUnityの疑似nullです。

?.、??、is nullは、その==を使いません。C#の参照を判定するため、参照がまだ存在していると呼び出しを通してしまい、破棄されたオブジェクトにアクセスするとMissingReferenceException: The object of type 'Transform' has been destroyed but you are still trying to access it.がスローされます。このラベルには、脱落(破棄)する可能性のあるレースの先頭走者の名前が表示されます。

[SerializeField] private Transform leader;

void Update()
{
    // leader が破棄されると例外が発生する: string shown = leader?.name ?? "nobody";
    string shown = leader != null ? leader.name : "nobody";
    Debug.Log("Leader: " + shown);
}

UnityEngine.Objectに由来するもの(GameObjects、コンポーネント、自分のスクリプト)には、== null、!= null、またはif (obj)で判定し、文字列などの通常のC#オブジェクトには?.と??を使いましょう。また、Destroyはフレームの終わりまで待機することも覚えておいてください。それまではオブジェクトはまだ有効で、== nullはfalseです。

challenge icon

チャレンジ

中級

ターゲットが破壊されたら、ドローンのエラーを止めましょう。

  1. Update()内で、2行をUnity独自のnull判定であるif (target != null)に置き換えます。
  2. その中に、transform.position = Vector3.MoveTowards(transform.position, target.position, speed * Time.deltaTime);と書きます。

「プレイ」を押すと、ドローンはターゲットを追いかけ、その後Consoleにエラーを出さずに停止します。それから「確認」を押します。

自分で試してみよう

using UnityEngine;

public class Chaser : MonoBehaviour
{
    [SerializeField] private Transform target;
    [SerializeField] private float speed = 2f;

    void Start()
    {
        Destroy(target.gameObject, 2f);   // 2秒後にtargetが破棄される
    }

    void Update()
    {
        Vector3 goal = target?.position ?? transform.position;
        transform.position = Vector3.MoveTowards(transform.position, goal, speed * Time.deltaTime);
    }
}

Unityスクリプトの基礎のすべてのレッスン

自分で練習してみよう: Unityプレイグラウンド