GameObjects не будет загружаться после перезапуска игры - PullRequest
0 голосов
/ 10 декабря 2018

Я делаю игру-лабиринт, и ключи, которые необходимо собрать, чтобы завершить ее, больше не появятся, если игра перезапустится, я получаю следующую ошибку:

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 голосов
/ 11 декабря 2018

Расширение

Исключение, которое вы получаете, говорит не об объекте MazeKey, а о компоненте MazeDirectives.

К сожалению, вы нажали самую важную информацию в комментариях:

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

так что OnMazeReady кажется static и не является экземпляром, поэтому он не будет уничтожен при загрузке новой сцены, но останется нетронутым в новой сцене!

При вызове

MazeGenerator.OnMazeReady += StartDirectives;

вы добавляете вызов к методу StartDirectives экземпляра MazeDirectives в качестве слушателя этого события static.

Теперь, когда вы перезагружаете Scene all GameObject s и, следовательно, их экземпляры компонентов уничтожаются

=> как и экземпляр MazeGenerator ... НО событие static OnMazeReady равно не уничтожено!

, поэтому после следующего Awake вызова у вас теперь есть два слушателя

  • Один из "второй" / новой загруженной сцены
  • Все еще«старый», который вы добавили в первый раз

Но с момента появления MazeDirectives вы добавилиПервый слушатель для уничтожается, когда сцена перезагружается и генерируется новый экземпляр, вы получаете это исключение

MissingReferenceException: объект типа 'MazeDirectives' был уничтожен, но вы все еще пытаетесь получить к нему доступ.Ваш сценарий должен либо проверить, является ли он нулевым, либо вы не должны уничтожать объект.

, когда метод пытается получить доступ к значению transform уничтоженного экземпляра.


Solution 1a

Таким образом, вы должны удалить прослушиватель при уничтожении экземпляра

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

Solution 1b

или перезаписать его только одним слушателем наtime

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 в случае StartDirectivesникогда не вызывается до уничтожения объекта.

0 голосов
/ 11 декабря 2018

Обновление:

Этот ответ неверен в первую очередь.Исключением является жалоба на доступ к MazeDirectives transform, а не mazeGoal объекту.Но комментарии ниже дают некоторую полезную информацию.Поэтому я сохраняю этот пост для справок.

Для полного решения см. здесь .


Из строки 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.

С здесь :

Загрузка новой сцены уничтожает все текущие объекты сцены.

The mazeGoalбыл уничтожен, когда вы вызвали

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

для перезапуска игры.

И из MonoBehaviour.Awake () ,

Awake вызывается только один раз за время существования экземпляра скрипта.

Поскольку вы присваиваете только переменную mazeGoal внутри функции StartDirectives, которая была вызвана в Awake, после повторной загрузки той же сцены фактический объект mazeGoal был уничтожен.

Если вы хотите повторно использовать тот же объект при загрузке новой сцены, вы можете использовать DontDestroyOnLoad, чтобы сохранить объект mazeGoal.

Или вы можете переместить StartDirectives в Start функция, которая будет вызываться каждый раз при создании игрового объекта и повторной инициализации вашего mazeGoal.

...