我正在制作一个迷宫游戏,如果重新启动游戏,则需要再次收集才能完成的迷宫键,但出现以下错误;
MissingReferenceException: The object of type 'MazeDirectives' has been destroyed but you are still trying to access it.
Your script should either check if it is null or you should not destroy the object.
我只是禁用MazeKey对象,而不是销毁它,有人可以帮忙吗?下面是我的代码;
MazeKey.cs
using UnityEngine;
using System.Collections;
public class MazeKey : MonoBehaviour
{
void OnTriggerEnter2D(Collider2D other)
{
transform.parent.SendMessage("OnKeyFound", SendMessageOptions.DontRequireReceiver);
gameObject.SetActive(false);
}
}
MazeDirectives.cs
MazeGoal mazeGoal;
MazeKey mazeKey;
void StartDirectives()
{
mazeGoal = Instantiate(mazeGoalPrefab, MazeGenerator.instance.mazeGoalPosition, Quaternion.identity) as MazeGoal;
mazeGoal.transform.SetParent(transform);
mazeKeyPositions = MazeGenerator.instance.GetRandomFloorPositions(keysToFind);
for (int i = 0; i < mazeKeyPositions.Count; i++)
{
MazeKey mazeKey = Instantiate(mazeKeyPrefab, mazeKeyPositions[i], Quaternion.identity) as MazeKey;
mazeKey.transform.SetParent(transform);
}
}
要重新启动游戏,请使用以下代码;
void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Player")
{
SceneManager.LoadScene(SceneManager.GetActiveScene().name);
gameObject.SetActive(true);
}
}
MazeGoal.cs
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class MazeGoal : MonoBehaviour
{
public Sprite closedGoalSprite;
public Sprite openedGoalSprite;
void Start()
{
GetComponentInChildren<SpriteRenderer>().sprite = closedGoalSprite;
}
public void OpenGoal()
{
GetComponentInChildren<SpriteRenderer>().sprite = openedGoalSprite;
}
void OnTriggerEnter2D()
{
transform.parent.SendMessage("OnGoalReached", SendMessageOptions.DontRequireReceiver);
}
答案 0 :(得分:3)
您得到的异常不是谈论MazeKey
对象,而是MazeDirectives
组件。
很遗憾,您在评论中打了最重要的信息:
private void Awake()
{
MazeGenerator.OnMazeReady += StartDirectives;
}
所以OnMazeReady
似乎是static
并没有被实例化,因此在加载新场景时它不会被破坏,但会保持原样膨胀到新场景中!
致电时
MazeGenerator.OnMazeReady += StartDirectives;
您将调用添加到StartDirectives
实例的MazeDirectives
方法作为该static
事件的侦听器。
现在,当您重新加载所有GameObject
场景时,它们的组件实例将被破坏
=> MazeGenerator
的实例也是如此……但 static
事件OnMazeReady
的事件未被破坏!< / p>
因此,在下一个Awake
通话之后,您现在有两个侦听器
但是由于重新加载场景并生成新实例时,您添加的MazeDirectives
实例被销毁了,所以您会得到该异常
MissingReferenceException:'MazeDirectives'类型的对象已被破坏,但您仍在尝试访问它。 您的脚本应检查其是否为null或不破坏该对象。
该方法尝试访问被破坏实例的transform
值时。
因此,在销毁实例时应删除监听器
private void OnDestroy()
{
MazeGenerator.OnMazeReady -= StartDirectives;
}
或一次只用一个监听器覆盖它
private void Awake()
{
MazeGenerator.OnMazeReady = StartDirectives;
}
第二种方法显然仅在没有其他实例或类在监听该事件时才有用。问题是,使用事件比这有意义多少?而且我还是会确保不需要时将其删除
private void OnDestroy()
{
MazeGenerator.OnMazeReady = null;
}
我更喜欢这种解决方案。
完全不要将MazeGenerator.OnMazeReady
设为静态。由于无论如何,我看到您正在使用Singleton模式,例如在
MazeGenerator.instance.mazeGoalPosition
您可以改为使OnMazeReady
为非静态,并以相同的方式使用它:
private void Awake()
{
MazeGenerator.instance.OnMazeReady += startDirectives;
}
因此它将与MazeGenerator
的实例一起销毁。
我会始终尽快删除我曾经添加过的所有侦听器,以避免出现确切的问题。
您可以另外将其删除,例如已经在StartDirectives
内部,以确保即使同一场景“偶然”两次调用了OnMazeReady
,该方法也只执行一次。
提示:我说了 additionally ,因为删除监听器总是可以保存/可能的,即使以前没有添加监听器,您也应该始终将它留在OnDestroy
中,以防StartDirectives
从未在销毁对象之前被调用。
答案 1 :(得分:2)
更新:
这个答案最初是错误的。例外是抱怨访问MazeDirectives
的{{1}},而不是transform
对象。
但是下面的评论确实提供了一些有用的信息。因此,我保留此帖子以供参考。
有关完整的解决方案,请参见here。
在mazeGoal
行中引发异常:
mazeGoal.transform.SetParent(transform);
来自here:
新场景的加载会破坏所有当前的场景对象。
您致电
时,MissingReferenceException: The object of type 'MazeDirectives' has been
destroyed but you are still trying to access it.
Your script should either check if it is null or you should not destroy the object.
已被破坏。
mazeGoal
重新启动游戏。
唤醒在脚本实例的生存期内仅被调用一次。
由于仅在SceneManager.LoadScene(SceneManager.GetActiveScene().name);
中调用的mazeGoal
函数内分配了StartDirectives
变量,因此再次加载同一场景后,Awake
的实际对象已被破坏
如果要在加载新场景时重用同一对象,则可以使用mazeGoal
保留DontDestroyOnLoad
对象。
或者您可以将mazeGoal
移至StartDirectives
函数,该函数将在每次创建游戏对象时调用,并重新初始化Start
。