GameManager 一直被标记为 null

GameManager keeps being marked as null

提问人:Nikola Savić 提问时间:3/29/2023 最后编辑:MorionNikola Savić 更新时间:3/29/2023 访问量:269

问:

我正在使用 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,但我尝试的任何方法都不起作用,我有点困惑为什么。

unity-game-engine nullreferenceexception

评论

0赞 Yeis Gallegos 3/29/2023
他,尼古拉,您能否举例说明其他脚本如何引用 GameManager.instance,如果没有一些关于如何调用它的上下文,您的层次结构很难发现问题?
0赞 Nikola Savić 3/29/2023
当然,给我一点时间
0赞 Nikola Savić 3/29/2023
在这里我引用它,这当然得到了空引用(我刚刚发布了我引用它的一部分,而不是整个脚本): public override bool GetTileAnimationData(Vector3Int location, ITilemap tilemap, ref TileAnimationData tileAnimationData) { tileAnimationData.animatedSprites = sprites; tileAnimationData.animationSpeed = sprites.长度 / (2 * GameManager.Instance.DayTime);返回 true;}
0赞 Nikola Savić 3/29/2023
由于我有“找不到游戏管理器”日志,因此问题一定出在脚本本身上。我怀疑其他脚本有任何问题。
0赞 hijinxbassist 3/29/2023
为了避免麻烦,如果实例为 null,我通常会在 getter 中添加一个,并将实例设置为该值。.您也可以将该调试替换为对象创建,这在某些情况下很好。FindObjectOfTypeInstance {get { if (instance == null) instance = FindObjectOfType<GameManager>(); if (instance == null) Debug.Log("Object Doesnt Exist"); return instance; }

答:

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);
}

}