提问人:Nikola Savić 提问时间:3/29/2023 最后编辑:MorionNikola Savić 更新时间:3/29/2023 访问量:269
GameManager 一直被标记为 null
GameManager keeps being marked as null
问:
我正在使用 Singleton 设计模式为 GameManager 编写脚本,但不知何故,当我运行我的游戏时,我得到了空引用异常。由于我经常更改场景,因此我制作了一个脚本,其中我不会销毁 GameManager 和一些不同的对象,而是使用 DontDestroyOnLoad,这很可能是异常的原因。
我将此脚本用于附加到场景中空游戏对象的游戏管理器。
using System.Collections.Generic;
using UnityEngine.SceneManagement;
using UnityEngine;
public class GameManager : MonoBehaviour {
private static GameManager instance;
public static GameManager Instance {
get {
if (instance == null) {
Debug.Log("Game Manager not found");
}
return instance;
}
}
[SerializeField] private List<GameObject> objectsNotToDestroy;
[SerializeField] private float dayAndNightTime;
private PlayerMovement player;
public float CurrentTime { get; set; }
public float DayTime { get; private set; }
private void Awake() {
if (instance != null) {
Debug.Log("Not null");
objectsNotToDestroy.ForEach(Destroy);
}
else {
Debug.Log("Here");
instance = this;
DontDestroyOnLoad(gameObject);
objectsNotToDestroy.ForEach(DontDestroyOnLoad);
}
PlayerMovement playerMovement = objectsNotToDestroy[1].GetComponent<PlayerMovement>();
if (playerMovement != null) {
player = playerMovement;
}
else {
Debug.LogError("PlayerMovement script not found on object in objectsNotToDestroy list.");
}
DayTime = dayAndNightTime;
}
public void Load(int buildIndex) {
CurrentTime += Time.time;
SceneManager.LoadSceneAsync(buildIndex);
player.Running(false);
}
}
当我运行我的游戏时,会输出“GameManager not found”和“Here”,这让我得出结论,不销毁我的 GameManager 脚本附加到的游戏对象会造成问题。我尝试了一些东西,例如包含/排除我的 GameManager 脚本附加到的 gameObject,但我尝试的任何方法都不起作用,我有点困惑为什么。
答:
0赞
Artur Karpiński
3/29/2023
#1
若要获取单例的可预测行为,请尝试以下操作:
- 设置脚本执行顺序,以便在任何其他将引用它的脚本之前实例化 GameManager: https://docs.unity3d.com/Manual/class-MonoManager.html
- 创建“init”类型的场景,该场景永远不会卸载,并且您的游戏管理器脚本位于顶级游戏对象上。将所有其他场景加载为累加场景,而不卸载“init”场景。
评论
0赞
Nikola Savić
3/29/2023
如何在加载新场景时引用我不想销毁的对象。我是否将它们放在 init 中,因为如果它们在游戏场景中,我无法从 init 引用它们
0赞
Nikola Savić
3/29/2023
谢谢你提供这个解决方案,它有效,但我不知道如何处理这个不要销毁onload gameObjects
0赞
Artur Karpiński
3/29/2023
使用您已经使用过的东西,例如单例模式
0赞
Nikola Savić
3/29/2023
我想我做到了,但我不知道如何从初始化到游戏场景引用 GameManager。我使用这行代码:GameManager.Instance.Load(buildIndex);在游戏场景中,并在初始化场景中使用 GameManager,因此它没有得到很好的引用
0赞
Artur Karpiński
3/29/2023
destroyonload 如果留在那里没问题,它不会造成伤害。
0赞
Nikola Savić
3/29/2023
#2
多亏了 @Artur Karpiński,我使 GameManager 完全正常运行,将它与我的一些游戏对象一起移动到一个单独的场景中,使这些游戏对象 DontDestroyOnLoad 并使用这个修改后的脚本(简单地说它不起作用):
using UnityEngine.SceneManagement;
using UnityEngine;
using System.Linq;
using System.Collections.Generic;
public class GameManager : MonoBehaviour {
private static GameManager instance;
public static GameManager Instance {
get {
if (instance == null) {
instance = FindObjectOfType<GameManager>();
if (instance == null) {
Debug.Log("Could not find GameManager object");
}
}
return instance;
}
}
[SerializeField] private float dayAndNightTime;
private PlayerMovement player;
[SerializeField] private List<GameObject> objectsNotToDestroy;
public float CurrentTime { get; set; }
public float DayTime { get; private set; }
private AsyncOperation sceneLoadingOperation;
private bool called = false;
private void Awake() {
DayTime = dayAndNightTime;
sceneLoadingOperation = SceneManager.LoadSceneAsync(1, LoadSceneMode.Additive);
}
private void Update() {
if (sceneLoadingOperation.isDone && !called) {
called = true;
if (instance != this) {
Destroy(gameObject);
}
else {
DontDestroyOnLoad(gameObject);
SceneManager.UnloadSceneAsync("Init");
instance = this;
objectsNotToDestroy.ForEach(DontDestroyOnLoad);
player = objectsNotToDestroy[2].GetComponent<PlayerMovement>();
}
}
}
public void Load(int buildIndex) {
CurrentTime = Time.time;
SceneManager.LoadSceneAsync(buildIndex);
player.Running(false);
}
}
评论
FindObjectOfType
Instance {get { if (instance == null) instance = FindObjectOfType<GameManager>(); if (instance == null) Debug.Log("Object Doesnt Exist"); return instance; }