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

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

最佳答案

讲解

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

不幸的是,您在评论中遇到了最重要的信息:

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


因此OnMazeReady似乎是static且未实例化,因此在装入新场景时不会被破坏,但会保持原样膨胀到新场景中!

你打电话的时候

MazeGenerator.OnMazeReady += StartDirectives;


您可以将调用添加到StartDirectives实例的MazeDirectives方法作为该static事件的侦听器。

现在,当您重新加载场景中的所有GameObject时,它们的组件实例将被销毁

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

所以在下一个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中,以防万一在销毁对象之前从未调用过OnDestroy的情况。

10-08 07:12