Синглтон не получает ссылку в функции Start () после изменения сцены - PullRequest
0 голосов
/ 16 октября 2018

Я пытаюсь понять, почему я получаю исключение из-за отсутствующей ссылки после смены сцены при использовании синглетонов.

Итак, у меня есть два объекта GameObject в первой сцене.Основная камера с прикрепленным скриптом GameManager и еще один объект магазина с прикрепленным скриптом Покупателя.Оба сценария также являются синглетонами, созданными, например, следующим образом:

public static Purchaser Instance

    void Awake(){
        Instance = this
    }

Затем они оба ссылаются друг на друга в функции Start (), например, так:

    void Start(){
        game = GameManager.Instance
    }

ПередСмена сцены, оба сценария используют одиночные ссылки друг друга для вызова методов друг от друга, и все, кажется, работает нормально.Как только я меняю сцены, ни один из этих объектов не появляется в следующей сцене, поэтому они оба уничтожаются.Однако, как только я возвращаюсь на главную сцену, я получаю исключение отсутствующей ссылки, когда скрипт покупателя пытается вызвать метод из GameManager с использованием одноэлементной ссылки, получаемой из Start (), которая изменяет текст текстового объекта, присоединенного к основной.камера.Эта функция вызывается после нажатия кнопки, которая прикреплена к объекту магазина, который вызывает эту функцию в скрипте покупателя:

UpdateMoney(){
    game.UpdateMoney(100);
}

Я прочитал и увидел, что это может быть потому, что Start () будет толькобыть вызванным один раз на протяжении всей игры.Это означало, что одноэлементный экземпляр GameManger скрипта «Покупатель» все еще был старым до того, как сцены изменились и этот экземпляр был уничтожен.Но я просто проверил, верно ли это, поместив журнал отладки в каждую функцию сценариев Start (), и увидел, что после каждого перехода сцены обратно в основную сцену журнал отладки будет проходить из обоих сценариев Start ().Итак, было бы правильно сказать, что Start () вызывается только один раз для жизни сценария, а не для всей игры, правильно?Не должно ли это также означать, что после того, как игра вернется в основную сцену, и оба GameObjects будут созданы заново, сценарий «Покупатель» должен теперь иметь обновленную ссылку на вновь созданный сценарий GameManager, поскольку функция «Start») была вызвана снова?

Я также обнаружил, что это работает вместо использования ссылки на игру в UpdateMoney ():

UpdateMoney(){
    GameManager.Instance.UpdateMoney(100);
}

Итак, почему это работает вместо использования ссылки на игру, полученной в Start ()?Означает ли это, когда Start () называется GameManager.Instance по-прежнему старый GameManager.Instance, поэтому game = GameManager.Instance не работает?Извините, это очень многословно.Любая помощь очень ценится.

1 Ответ

0 голосов
/ 17 октября 2018

Исходя из того, что я понимаю, у вас есть синглтон на главной сцене.Игровой объект, к которому прикреплен синглтон, разрушается после смены сцен.

Прежде всего, есть ли причина, по которой вам нужен синглтон, чтобы быть MonoBehaviour и прикрепленным к игровому объекту?Поскольку вы можете просто создать класс с

private static MyClass instance = null
public static MyClass Instance
{
    get {
        if(instance == null)
            instance = new MyClass();
        return instance;
    }
}

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

Second, Start() вызывается только один раз.Однако до этого я сталкивался с проблемами, если MonoBehaviour присоединен к отключенному игровому объекту, Start() вызываться не будет.Вы можете проверить, происходит ли это с вами, когда вы переключаетесь обратно на главную сцену.

В-третьих, если вам действительно нужно, чтобы синглтон был MonoBehaviour, вы можете использовать DontDestroyOnLoad(instance.gameObject), чтобы игровой объектсинглтон не будет уничтожен даже после смены сцены.Тем не мение.Я предполагаю, что игровые объекты установлены на сцене.Если это не из префаба, вы можете просто сделать что-то вроде этого

private static MyClass instance = null;
public static MyClass Instance
{
    get {
        if(instance == null){
            GameObject inst = new GameObject("MyClass Singleton");
            instance = inst.AddComponent<MyClass>();
            DontDestroyOnLoad(inst);
        }
        return instance;
    }
}

Если вы сделаете это, вы можете удалить предустановленные игровые объекты с главной сцены и позволить первому вызову MyClass.Instanceсделайте игровой объект для вас.

Наконец, если вы не хотите этого делать, вы должны установить instance = null; для игрового объекта OnDestroy(), чтобы при входе в основную сцену новые экземплярыбыть установлен на синглтон.Это будет означать, что синглтон не будет иметь значения после того, как вы переключите сцены за пределы основной сцены.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...