本日は C# と Unity の小ネタ枠です。
Get/Set アクセサを使ってアクセス時に変数を初期化する方法を Unity のコンポーネントで活用してみます。
アクセスするタイミングで初期化を行いたいケース
問題ケースとしてコンポーネントにアクセスするタイミングで変数の初期化を行いたいケースを想定します。
以下のような、オブジェクトをカメラの正面に移動するコンポーネントを介してオブジェクトを移動するケースを試しました。
・CameraTracker.cs
using UnityEngine; /// <summary> /// オブジェクトをメインカメラの位置を元に移動するコンポーネント /// </summary> public class CameraTracker : MonoBehaviour { private Transform cameraTransform; void Start() { cameraTransform = Camera.main.transform; } public void MoveToFront() { // 正面1mの位置に移動する this.transform.position = cameraTransform.position + cameraTransform.forward * 1.0f; } }
・ModelControl.cs
using UnityEngine; public class ModelControl : MonoBehaviour { [SerializeField] private CameraTracker cameraTracker; void Start() { // 起動時に対象オブジェクトを有効化して移動する cameraTracker.gameObject.SetActive(true); cameraTracker.MoveToFront(); } }
シーン上では移動対象のオブジェクトは初期状態で無効化されており、シーンの再生と共に有効化され、移動の処理が呼び出されます。
本シーンを再生すると Null 参照のエラーが発生します。
メンバー変数を初期化する Start 関数はオブジェクトを有効化した次のフレームで実行されるため、移動の処理を呼び出した時点ではまだ変数が初期化されていないためです。
Get/Setアクセサを使って変数のアクセス時に変数を初期化する
この問題を解決するため、Get/Set アクセサを使って変数のアクセス時に変数がまだ初期化されていなければ初期化を行うようにします。
スクリプトを以下のように修正しました。
・CameraTracker.cs
using UnityEngine; /// <summary> /// オブジェクトをメインカメラの位置を元に移動するコンポーネント /// </summary> public class CameraTracker : MonoBehaviour { private Transform _cameraTransform; private Transform cameraTransform { get { // 初期化されていない場合はカメラの Transform を取得する if (_cameraTransform is null) { _cameraTransform = Camera.main.transform; } return _cameraTransform; } set => _cameraTransform = value; } public void MoveToFront() { // 正面1mの位置に移動する this.transform.position = cameraTransform.position + cameraTransform.forward * 1.0f; } }
これでシーンを再生してもエラーが発生しなくなります。
アクセス時に必ず変数の初期化が行われるので Unity の MonoBehaviour をでフィールド変数を扱う際に役立つ手法です。
ラムダ式を利用する場合の方法は以下の記事を参照ください。
bluebirdofoz.hatenablog.com