【问题标题】:GameObjects will not load after game Restarts游戏重启后不会加载游戏对象
【发布时间】:2019-05-11 18:45:10
【问题描述】:

我正在做一个迷宫游戏,如果游戏重新开始,需要收集完成它的钥匙不会再次出现,我收到以下错误;

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

【问题讨论】:

  • 哪一行代码抛出异常?以及如何重新开始游戏?
  • 嗨 ming060,我已经为你更新了我的问题,引发异常的代码行是 mazeGoal.transform.SetParent(transform);
  • 能否更新代码,包括变量mazeGoal的声明?是静态变量吗?
  • 没问题,刚刚为你编辑好了
  • 您是否在AwakeStart 或其他地方致电StartDirectives

标签: c# unity3d collision


【解决方案1】:

解释

您得到的例外不是MazeKey 对象,而是MazeDirectives 组件。

不幸的是,你击中了 cmets 中最重要的信息:

private void Awake() 
{ 
    MazeGenerator.OnMazeReady += StartDirectives; 
}

所以OnMazeReady 似乎是static 并且没有实例化,因此在加载新场景时它不会被破坏,但会在新场景中保持完整的膨胀!

当你打电话时

MazeGenerator.OnMazeReady += StartDirectives;

您添加对MazeDirectives 实例的StartDirectives 方法的调用作为static 事件的侦听器。

现在,当您重新加载场景时,所有 GameObjects 都将被销毁

=> MazeGenerator 的实例也是如此...... 但是 static 事件 OnMazeReady 销毁!

所以在下一次Awake 通话后,您现在有两个听众

  • “第二个”/新加载的场景中的那个
  • 仍然是您第一次添加的“旧”版本

但是由于您添加的第一个侦听器 MazeDirectives 的实例在重新加载场景并生成新实例时被销毁,因此您会遇到该异常

MissingReferenceException:“MazeDirectives”类型的对象已被破坏,但您仍在尝试访问它。 您的脚本应该检查它是否为空,或者您不应该销毁该对象。

当方法尝试访问被销毁实例的transform 值时。


解决方案 1a

所以你应该在销毁实例时移除监听器

private void OnDestroy()
{
     MazeGenerator.OnMazeReady -= StartDirectives;
}

解决方案 1b

或者一次只用一个监听器覆盖它

private void Awake() 
{ 
    MazeGenerator.OnMazeReady = StartDirectives; 
}

这第二种方法显然只有在没有其他实例或类监听该事件时才有用。问题是使用事件有多大意义?如果不是为了确定,我无论如何都会删除它

private void OnDestroy()
{
     MazeGenerator.OnMazeReady = null;
}

解决方案 2

我更喜欢这个解决方案。

根本不要将MazeGenerator.OnMazeReady 设为静态。因为无论如何我看到你正在使用单例模式,例如在

 MazeGenerator.instance.mazeGoalPosition

您可以改为将 OnMazeReady 设为非静态并以相同的方式使用它:

private void Awake()
{
    MazeGenerator.instance.OnMazeReady += startDirectives;
}

所以它将与MazeGenerator 的实例一起被销毁。


一般说明

我会始终尽快删除我添加的所有侦听器,以避免您遇到的问题。

您可以另外删除它,例如已经在 StartDirectives 内部,以确保该方法只执行一次,即使同一场景“意外”调用了两次 OnMazeReady

提示:我说 另外 因为它总是可以保存/可以删除一个侦听器,即使它之前没有添加,你应该把它留在OnDestroy,以防@987654348 @ 在对象被销毁之前永远不会被调用。

【讨论】:

  • 完美!谢谢德雨果!我选择了解决方案 1,并将 void awake 更改为 MazeGenerator.OnMazeReady = StartDirectives; ,如果我可以投票给你,我会的!
【解决方案2】:

更新:

这个答案首先是错误的。例外是抱怨访问MazeDirectivestransform,而不是mazeGoal 对象。 但是下面的 cmets 确实提供了一些有用的信息。所以我保留这篇文章以供参考。

如需完整解决方案,请参阅here


mazeGoal.transform.SetParent(transform);这一行抛出异常:

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.

来自here

新场景的加载会破坏所有当前场景对象。

mazeGoal 在您调用时已被销毁

SceneManager.LoadScene(SceneManager.GetActiveScene().name);

重新开始游戏。

来自MonoBehaviour.Awake()

Awake 在脚本实例的生命周期内只调用一次。

由于你只在Awake中调用的StartDirectives函数中分配了mazeGoal变量,在再次加载相同的场景后,mazeGoal的实际对象已被破坏。

如果您想在加载新场景时重复使用同一个对象,可以使用DontDestroyOnLoad 保留mazeGoal 对象。

或者您可以将 StartDirectives 移动到 Start 函数,该函数将在每次创建游戏对象时调用并重新初始化您的 mazeGoal

【讨论】:

  • 感谢 ming060!然而 MazeGoal 重新加载很好,它的 MazeKeys 不会重新加载
  • 哦,对不起。所以异常是由在MazeDirectives.cs中调用mazeGoal.transform.SetParent(transform);引起的,而transform为null?
  • 是的,我想是的!
  • 您有没有在Logtransform 前一行确认一下mazeGoal.transform.SetParent(transform);
  • Maze (UnityEngine.Transform) 出现在日志中
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多