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です。
チャレンジ
中級ターゲットが破壊されたら、ドローンのエラーを止めましょう。
Update()内で、2行をUnity独自のnull判定であるif (target != null)に置き換えます。- その中に、
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プレイグラウンド