Unity单例MonoBehaviour类中如何通过[SerializeField]获取Camera?
解决SingletonMono自动创建对象时的Camera赋值问题
你的核心矛盾在于:自动创建的单例GameObject无法通过Inspector给[SerializeField]字段赋值,同时想避免手动挂载脚本的操作。以下是三种实用解决方案:
方案1:通过预制体初始化单例
提前在预制体中配置好Camera等参数,让单例自动加载预制体而非创建空对象,完美保留Inspector赋值的便利性。
修改SingletonMono基类
添加预制体加载逻辑,允许子类指定预制体路径:
public abstract class SingletonMono<T>: MonoBehaviour where T: MonoBehaviour { private static T _instance; protected static bool ApplicationIsQuitting; protected static bool IsGlobal; static SingletonMono() { ApplicationIsQuitting = false; IsGlobal = false; } // 子类重写此方法返回预制体路径 protected virtual string GetPrefabPath() => string.Empty; public static T Instance { get { if (ApplicationIsQuitting) { Debug.LogWarning($"Application is quitting, you cant operate a singleton mono object: [{typeof(T)}]"); return _instance; } _instance = FindObjectOfType<T>(); if (FindObjectsOfType<T>().Length > 1) { Debug.LogError($"the singleton type [{typeof(T)}] has more than one instances"); return _instance; } if (_instance != null) return _instance; GameObject obj = null; // 尝试加载子类指定的预制体 var prefabPath = ((SingletonMono<T>)Activator.CreateInstance(typeof(T), true)).GetPrefabPath(); if (!string.IsNullOrEmpty(prefabPath)) { obj = Resources.Load<GameObject>(prefabPath); if (obj != null) { obj = Instantiate(obj); obj.name = typeof(T).ToString(); } } // 预制体不存在时创建空对象 obj ??= new GameObject(typeof(T).ToString()); _instance = obj.GetComponent<T>() ?? obj.AddComponent<T>(); if(IsGlobal) DontDestroyOnLoad(obj); return _instance; } } public void OnApplicationQuit() { ApplicationIsQuitting = true; } }
修改StageManager子类
重写GetPrefabPath方法指定预制体位置:
public class StageManager: SingletonMono<StageManager> { [SerializeField] private float spaceOffset; [SerializeField] private Camera mainCam; // 假设预制体放在Resources/StageManagerPrefab路径下 protected override string GetPrefabPath() => "StageManagerPrefab"; public Vector3 GetWorldPositionByScreenPoint(Vector2 pos) { var z = -mainCam.transform.position.z; return mainCam.ScreenToWorldPoint(new Vector3(pos.x, pos.y, z)); } }
操作步骤:创建StageManager预制体,在Inspector中给mainCam赋值,将预制体放入Resources目录即可。
方案2:代码自动获取Camera(无需Inspector赋值)
如果只需使用主相机或特定标签的相机,直接通过代码获取,完全跳过手动赋值环节。
修改StageManager类
public class StageManager: SingletonMono<StageManager> { [SerializeField] private float spaceOffset; private Camera mainCam; private void Awake() { // 方式1:获取标签为"MainCamera"的主相机(会缓存结果,性能优) mainCam = Camera.main; // 方式2:获取指定标签的相机(适合多相机场景) // mainCam = GameObject.FindWithTag("GameCamera").GetComponent<Camera>(); // 方式3:获取场景中第一个Camera组件(适合单相机场景) // mainCam = FindObjectOfType<Camera>(); } public Vector3 GetWorldPositionByScreenPoint(Vector2 pos) { if (mainCam == null) { Debug.LogError("Main Camera not found!"); return Vector3.zero; } var z = -mainCam.transform.position.z; return mainCam.ScreenToWorldPoint(new Vector3(pos.x, pos.y, z)); } }
注意:使用Camera.main时确保目标相机的标签设为"MainCamera"。
方案3:允许场景中存在预设实例(自动检测)
优化单例逻辑,优先使用场景中已有的实例,只有当场景中无实例时才自动创建。这样你可以在场景中放置一个挂载了StageManager的GameObject,提前在Inspector中赋值Camera,单例会自动复用该实例。
修改SingletonMono基类
添加Awake阶段的实例检测逻辑:
public abstract class SingletonMono<T>: MonoBehaviour where T: MonoBehaviour { private static T _instance; protected static bool ApplicationIsQuitting; protected static bool IsGlobal; static SingletonMono() { ApplicationIsQuitting = false; IsGlobal = false; } protected virtual void Awake() { if (_instance == null) { _instance = this as T; if (IsGlobal) DontDestroyOnLoad(gameObject); } else { Destroy(gameObject); Debug.LogWarning($"Duplicate singleton instance of {typeof(T)} destroyed."); } } public static T Instance { get { if (ApplicationIsQuitting) { Debug.LogWarning($"Application is quitting, you cant operate a singleton mono object: [{typeof(T)}]"); return _instance; } if (_instance == null) { _instance = FindObjectOfType<T>(); if (_instance == null) { var obj = new GameObject(typeof(T).ToString()); _instance = obj.AddComponent<T>(); if(IsGlobal) DontDestroyOnLoad(obj); } } if (FindObjectsOfType<T>().Length > 1) { Debug.LogError($"the singleton type [{typeof(T)}] has more than one instances"); } return _instance; } } public void OnApplicationQuit() { ApplicationIsQuitting = true; } }
操作步骤:在场景中创建一个GameObject,挂载StageManager,在Inspector中给mainCam赋值即可。游戏启动时单例会自动识别并复用这个实例,不会创建新对象。
内容的提问来源于stack exchange,提问作者Wiosier
相关产品推荐
相关产品推荐

