重新启动游戏后,GameObjects将不会加载

时间:2018-12-10 20:10:22

标签: c# unity3d collision

我正在制作一个迷宫游戏,如果重新启动游戏,则需要再次收集才能完成的迷宫键,但出现以下错误;

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

2 个答案:

答案 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值时。


解决方案1a

因此,在销毁实例时应删除监听器

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

解决方案1b

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

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

第二种方法显然仅在没有其他实例或类在监听该事件时才有用。问题是,使用事件比这有意义多少?而且我还是会确保不需要时将其删除

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

解决方案2

我更喜欢这种解决方案。

完全不要将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

重新启动游戏。

MonoBehaviour.Awake()

  

唤醒在脚本实例的生存期内仅被调用一次。

由于仅在SceneManager.LoadScene(SceneManager.GetActiveScene().name); 中调用的mazeGoal函数内分配了StartDirectives变量,因此再次加载同一场景后,Awake的实际对象已被破坏

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

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