c# - Unity 类型为“GameObject”的对象已被销毁
问题描述
我的选项菜单中有 2 个按钮,“返回主菜单”和“静音音乐”每个按钮都附有一个脚本,并在按下时调用脚本的 OnPress() 方法。我还有一个主要的关卡对象/脚本来处理所有的场景加载和东西。因此主菜单按钮的脚本在其 Start 中执行 FindObjectOfType(),然后在其 OnPress() 中调用 level.LoadStartScene()。静音按钮的脚本做同样的事情,但调用 level.ToggleMuteMusic()。所以这之前工作得很好,但后来我用下面的代码把关卡变成了一个单例:
public void Awake() {
InitializeSingleton();
}
private void InitializeSingleton() {
if (FindObjectsOfType(GetType()).Length > 1) {
Destroy(gameObject);
} else {
DontDestroyOnLoad(gameObject);
}
}
所以现在主菜单按钮可以正常工作,但是静音按钮会出错;我认为这是因为在 Start() 中它找到了旧的关卡对象,然后带有 DontDestroyOnLoad 的那个进来并删除了旧的,但是为什么主菜单按钮起作用???
静音按钮代码:
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
public class MuteButton : MonoBehaviour {
[SerializeField] string mutedText = "Unmute Music";
[SerializeField] string unmutedText = "Mute Music";
private Level level;
private TextMeshProUGUI myText;
public void Start() {
level = FindObjectOfType<Level>();
myText = GetComponent<TextMeshProUGUI>();
}
public void OnPress() {
if (level == null) {
Debug.Log("log 1");
}
level.ToggleMuteMusic();
bool muteMusic = level.GetMuteMusic();
if (muteMusic == true) {
myText.SetText(mutedText);
} else if (muteMusic == false) {
myText.SetText(unmutedText);
}
}
}
菜单按钮代码:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MenuButton : MonoBehaviour {
Level level;
public void Start() {
level = FindObjectOfType<Level>();
}
public void OnPress() {
level.LoadStartScene();
}
}
完全错误:
MissingReferenceException:“GameObject”类型的对象已被销毁,但您仍在尝试访问它。您的脚本应该检查它是否为空,或者您不应该销毁该对象。UnityEngine.GameObject.GetComponent[T] () (在 C:/buildslave/unity/build/Runtime/Export/Scripting/GameObject.bindings.cs:28) Level.ToggleMuteMusic () (在 Assets/Scripts/Level.cs: 74) MuteButton.OnPress () (在 Assets/Scripts/MuteButton.cs:23)
谢谢你的时间 :)
解决方案
确定导致此问题的事物执行的确切顺序可能有点困难,但是您在 Start() 中丢失了在 Awake() 中处理的引用这一事实很奇怪。过去我FindObjectOfType<>
在 Start() 中使用时遇到过问题,所以最好改变你处理单例的方式。
我建议您制作关卡 static
,以便您可以更轻松地引用它,因为您已经在实现一种单例形式。
这是一个如何重写 Level.cs 文件顶部的示例:
public static Level instance;
private void Awake()
{
if (instance != null && instance != this)
{
Destroy(this.gameObject);
return;
}
else
{
instance = this;
}
DontDestroyOnLoad(this.gameObject);
}
这会导致它创建 Level 类一次,然后销毁它的所有后续版本(例如重新加载它所在的场景时)。
现在,要在您的其他脚本中引用它,您无需FindObjectOfType<Level>()
再次使用!您可以静态引用Level.instance
,如下所示:
//New way to call ToggleMuteMusic()
Level.instance.ToggleMuteMusic();
希望这会有所帮助!
推荐阅读
- c++ - 无法使用 QtCipherSqlitePlugin 打开手动加密的 SQLite 数据库,反之亦然
- c++ - 在 C++ 中将 IANA 时区转换为 Windows 时区
- git - 以编程方式检查 HEAD 是否分离?
- maven - Maven模块具有相同库的不同版本
- ffmpeg - 通过 FFMPEG 监控 GPU 使用情况
- git - 应用补丁不会在 Git 中创建新创建的文件
- typescript - 打字稿:对象和原语之间的keyof typeof联合总是永远不会
- performance - 从内存加载寄存器而不是触发页面错误时是否可以“中止”?
- node.js - Firestore 不支持带有自定义原型的 JavaScript 对象?
- sql - pyspark sql jdbc错误-关键字'SET'附近的语法不正确