Unity中调用LoadLevels()出现NullReferenceException空引用错误求助
问题原因
你遇到的NullReferenceException是因为静态字段instance在调用LoadLevels()时还未被赋值,常见触发场景有3种:
LoadCustomLevels脚本未挂载到场景中处于激活状态的GameObject上,Awake方法从未执行,instance始终为null- 你调用
LoadLevels()的时机早于该脚本的Awake执行时机(比如其他脚本的Awake生命周期里就调用了该方法) - 场景中挂载该脚本的GameObject被设置为失活,
Awake生命周期不会触发
解决方案
第一步:修正单例写法,增加空校验
替换为以下版本的脚本,优化了单例赋值逻辑、增加调用空保护,同时保留你不需要将LoadTheLevels设为静态的需求:
using System.Collections; using System.Collections.Generic; using System.IO; using UnityEngine.UI; using UnityEngine; using System; public class LoadCustomLevels : MonoBehaviour { static LoadCustomLevels instance; public GameObject ButtonPrefab; // 请在Inspector中赋值 public Sprite DefaultPNG; // 请在Inspector中赋值 private void Awake() { // 单例防重复逻辑 if (instance != null && instance != this) { Destroy(gameObject); return; } instance = this; // 可选:如果需要跨场景保留这个对象,解开下面一行注释 // DontDestroyOnLoad(gameObject); } void LoadTheLevels() { string path = Application.persistentDataPath + @"\Levels"; if (!Directory.Exists(path)) Directory.CreateDirectory(path); string[] levelPaths = Directory.GetDirectories(path); foreach (string item in levelPaths) { if (File.Exists(item + @"\data") && File.Exists(item + @"\objects")) { GameObject currentButton = Instantiate(ButtonPrefab, transform); currentButton.transform.GetChild(0).gameObject.GetComponent<Text>().text = new DirectoryInfo(path).Name; currentButton.transform.GetChild(1).gameObject.GetComponent<Image>().sprite = DefaultPNG; if (File.Exists(item + @"\icon.png")) { Texture2D levelImagetex = new Texture2D(700, 500); levelImagetex.LoadImage(File.ReadAllBytes(item + @"\icon.png")); currentButton.transform.GetChild(1).gameObject.GetComponent<Image>().sprite = Sprite.Create(levelImagetex, currentButton.transform.GetChild(1).GetComponent<Rect>(), new Vector2(0.5f, 0.5f)); } string version = File.ReadAllText(item + @"\data").Split(',')[0]; if (Application.version != version) currentButton.transform.GetChild(2).gameObject.GetComponent<Text>().color = Color.red; currentButton.transform.GetChild(2).gameObject.GetComponent<Text>().text = version; long levelSize = 0; foreach (var item2 in Directory.GetFiles(item)) { levelSize += new FileInfo(item2).Length; } levelSize /= 1024; currentButton.transform.GetChild(3).gameObject.GetComponent<Text>().text = levelSize.ToString() + "Kb"; if ((DateTime.Now - new DirectoryInfo(item).LastAccessTime).Minutes <= 60) currentButton.transform.GetChild(4).gameObject.GetComponent<Text>().text = (DateTime.Now - new DirectoryInfo(item).LastAccessTime).Minutes + " minute(s) ago" ; else if ((DateTime.Now - new DirectoryInfo(item).LastAccessTime).Hours <= 24) currentButton.transform.GetChild(4).gameObject.GetComponent<Text>().text = (DateTime.Now - new DirectoryInfo(item).LastAccessTime).Hours + " hour(s) ago"; else currentButton.transform.GetChild(4).gameObject.GetComponent<Text>().text = (DateTime.Now - new DirectoryInfo(item).LastAccessTime).Days + " day(s) ago"; } } } public static void LoadLevels() { // 增加空校验,避免空引用报错 if (instance == null) { Debug.LogError("LoadCustomLevels实例不存在,请先将脚本挂载到场景激活的GameObject上"); return; } instance.LoadTheLevels(); } }
第二步:检查场景配置和调用时机
- 确认你已经把
LoadCustomLevels脚本挂载到场景里一开始就处于激活状态的GameObject上,且Inspector中已经给ButtonPrefab和DefaultPNG赋值 - 所有对
LoadCustomLevels.LoadLevels()的调用,都要放在Start生命周期及之后的阶段执行,不要放在其他脚本的Awake里调用,避免单例还未初始化就被访问
额外注意事项
如果后续还出现空引用报错,可以排查以下点:
- 实例化的
ButtonPrefab的子物体数量和索引是否和你代码中GetChild(0)~GetChild(4)的索引对应 - 上述代码已经修正了原代码中
ReadAllBytes().ToString()的错误,该写法会返回字节数组的类型名而非文件内容,替换为ReadAllText才能正确读取版本号
内容的提问来源于stack exchange,提问作者gamefal 1820
相关产品推荐
相关产品推荐

