Search Unity

NullReferenceException when finding button after another Scene is loaded

Discussion in 'Scripting' started by Dante93, Apr 4, 2018.

  1. Dante93

    Dante93

    Joined:
    Jul 12, 2017
    Posts:
    4
    Hello

    I've got a problem.
    My code for ButtonManager is:

    Code (CSharp):
    1.  
    2. using System.Collections;
    3. using System.Collections.Generic;
    4. using UnityEngine;
    5. using UnityEngine.UI;
    6. using UnityEngine.EventSystems;
    7. using UnityEngine.SceneManagement;
    8. public class ButtonManager
    9. {
    10.  
    11.     private Button resetCounter;
    12.     private Button changeToMainSceneButton;
    13.     private Button changeToHistorySceneButton;
    14.     private Button addCigaretteButton;
    15.     public ButtonManager ()
    16.     {
    17.         initializeSceneButtons ();
    18.     }
    19.     public void initializeSceneButtons ()
    20.     {
    21.         if (Manager.MY_SCENES_MANAGER.SceneName.Equals ("MainScene")) {
    22.             Debug.Log (Manager.MY_SCENES_MANAGER.SceneName);
    23.             changeToHistorySceneButton = GameObject.Find ("ChangeToHistoryScene").GetComponent<Button> ();
    24.             changeToHistorySceneButton.onClick.AddListener (() => Manager.MY_SCENES_MANAGER.ChangeScene ());
    25.             addCigaretteButton = GameObject.Find ("AddCounter").GetComponent<Button> ();
    26.             addCigaretteButton.onClick.AddListener (() => Manager.COUNTER_MANAGER.AddCigarette ());
    27.             resetCounter = GameObject.Find ("ResetCounter").GetComponent<Button> ();
    28.             resetCounter.onClick.AddListener (() => Manager.COUNTER_MANAGER.ResetCounter ());
    29.  
    30.         } else if (Manager.MY_SCENES_MANAGER.SceneName.Equals ("HistoryScene")) {
    31.             Debug.Log (this);
    32.             Debug.Log (Manager.MY_SCENES_MANAGER.SceneName);
    33.             changeToMainSceneButton = GameObject.Find ("ChangeToMainScene").GetComponent<Button> ();
    34.             changeToMainSceneButton.onClick.AddListener (() => Manager.MY_SCENES_MANAGER.ChangeScene ());
    35.         }
    36.     }
    37. }
    38.  
    39.  
    Code for GameManager:
    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine.UI;
    4. using UnityEngine.SceneManagement;
    5. using UnityEngine.EventSystems;
    6. using UnityEngine;
    7.  
    8. public class Manager : MonoBehaviour {
    9.  
    10.  
    11.     public static MyScenesManager MY_SCENES_MANAGER;
    12.     public static CounterManager COUNTER_MANAGER;
    13.     public static ButtonManager BUTTON_MANAGER;
    14.  
    15.  
    16.     void Start () {
    17.         MY_SCENES_MANAGER = new MyScenesManager ();
    18.         COUNTER_MANAGER = new CounterManager ();
    19.         BUTTON_MANAGER = new ButtonManager ();
    20.     }
    21.  
    22.  
    23.     public void OnApplicationQuit()
    24.     {
    25.         PlayerPrefs.Save();
    26.     }
    27.  
    28.     void Awake() {
    29.         DontDestroyOnLoad(this);
    30.     }
    31.  
    32.     void Update () {
    33.  
    34.     }
    35.  
    36.  
    37.  
    38.  
    39.  
    40.  
    41. }
    42.  


    When I'm on MainScene buttons works correctly, but after i have switched from Main Scene to History scene I've got an error on line:
    Code (CSharp):
    1. changeToMainSceneButton = GameObject.Find ("ChangeToMainScene").GetComponent<Button> ();
    Code (CSharp):
    1. NullReferenceException: Object reference not set to an instance of an object
    2. ButtonManager.initializeSceneButtons () (at Assets/ButtonManager.cs:40)
    3. MyScenesManager.ChangeScene () (at Assets/MyScenesManager.cs:32)
    4. ButtonManager.<initializeSceneButtons>m__0 () (at Assets/ButtonManager.cs:28)
    5. UnityEngine.Events.InvokableCall.Invoke () (at C:/buildslave/unity/build/Runtime/Export/UnityEvent.cs:165)
    6. UnityEngine.Events.UnityEvent.Invoke () (at C:/buildslave/unity/build/Runtime/Export/UnityEvent_0.cs:58)
    7. UnityEngine.UI.Button.Press () (at C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/UI/Core/Button.cs:36)
    8. UnityEngine.UI.Button.OnPointerClick (UnityEngine.EventSystems.PointerEventData eventData) (at C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/UI/Core/Button.cs:45)
    9. UnityEngine.EventSystems.ExecuteEvents.Execute (IPointerClickHandler handler, UnityEngine.EventSystems.BaseEventData eventData) (at C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/EventSystem/ExecuteEvents.cs:50)
    10. UnityEngine.EventSystems.ExecuteEvents.Execute[IPointerClickHandler] (UnityEngine.GameObject target, UnityEngine.EventSystems.BaseEventData eventData, UnityEngine.EventSystems.EventFunction`1 functor) (at C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/EventSystem/ExecuteEvents.cs:261)
    11. UnityEngine.EventSystems.EventSystem:Update()
    12.  
    It's really strange.
    I think I can't find this button because it is in another scene.



    What do You think about that? How to resolve this problem?
    Thanks for helping me ;]
     
    Last edited: Apr 4, 2018
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,745
    You are correctly saying to don't destroy the Manager, but that doesn't affect the button.

    When you change scenes, without an explicit call to not destroy it, the Button will be gone, along with everything else in the previous scene.
     
  3. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    Just use GameObject.FindGameObjectWithTag("<your_custom_tag>") after assigning a custom tag to the ChangeToMainScene object instead of using GameObject.Find. You shouldn't use GameObject.Find anyway.... ever

    The above is assuming you have a ChangeToMainScene object in the new scene you're opening by the way.
     
  4. Dante93

    Dante93

    Joined:
    Jul 12, 2017
    Posts:
    4
    With tags it's still doesn't work ;/

    Code (CSharp):
    1.             changeToMainSceneButton = GameObject.FindGameObjectWithTag ("Button").GetComponent<Button> ();

    Code (CSharp):
    1. NullReferenceException: Object reference not set to an instance of an object
    2. ButtonManager.initializeSceneButtons () (at Assets/ButtonManager.cs:39)
    3. MyScenesManager.ChangeScene () (at Assets/MyScenesManager.cs:33)
    4. ButtonManager.<initializeSceneButtons>m__0 () (at Assets/ButtonManager.cs:28)
    5. UnityEngine.Events.InvokableCall.Invoke () (at C:/buildslave/unity/build/Runtime/Export/UnityEvent.cs:165)
    6. UnityEngine.Events.UnityEvent.Invoke () (at C:/buildslave/unity/build/Runtime/Export/UnityEvent_0.cs:58)
    7. UnityEngine.UI.Button.Press () (at C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/UI/Core/Button.cs:36)
    8. UnityEngine.UI.Button.OnPointerClick (UnityEngine.EventSystems.PointerEventData eventData) (at C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/UI/Core/Button.cs:45)
    9. UnityEngine.EventSystems.ExecuteEvents.Execute (IPointerClickHandler handler, UnityEngine.EventSystems.BaseEventData eventData) (at C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/EventSystem/ExecuteEvents.cs:50)
    10. UnityEngine.EventSystems.ExecuteEvents.Execute[IPointerClickHandler] (UnityEngine.GameObject target, UnityEngine.EventSystems.BaseEventData eventData, UnityEngine.EventSystems.EventFunction`1 functor) (at C:/buildslave/unity/build/Extensions/guisystem/UnityEngine.UI/EventSystem/ExecuteEvents.cs:261)
    11. UnityEngine.EventSystems.EventSystem:Update()
    12.  

    Maybe I will precise my project.
    I've got two scenes. MainScene which app is starting from and HistoryScene.
    I have one object "ScriptManager" with Manager script which I set method DontDestroyOnLoad on it.

    The problem is with button "ChangeToMainScene" that is only in canvas in HistoryScene, there is no such a button in MainScene.
    All of the buttons works correctly in MainScene but in HistoryScene this button, doesnt work.
    It looks like my ScriptManager can find objects(buttons) in MainScene, but not in HistoryScene and I don't know why ;/

    MainScene Hierarchy:

    HistoryScene Hierarchy:

    HistoryScene Hierarchy after click on button which loaded HistoryScene from MainScene:
     
    Last edited: Apr 4, 2018
  5. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    This doesn't make sense. Are you sure that HistoryScene is active when you are calling initializeSceneButtons()? And you actually assigned the Button tag to the ChangeToMainScene GameObject?

    Add this at the top of initializeSceneButtons()

    Code (csharp):
    1.  
    2.         Scene scene = SceneManager.GetActiveScene();
    3.         Debug.Log("Active scene is '" + scene.name + "'.");
    4.  
     
  6. Dante93

    Dante93

    Joined:
    Jul 12, 2017
    Posts:
    4
    Sorry for not responding, but I was really busy in new work.

    So, this is my code after button click to change the scene:

    Code (CSharp):
    1.         Debug.Log ("Scene name to load: " + sceneNameToLoad);
    2.         SceneManager.LoadScene(sceneNameToLoad);
    and added Log of current scene:
    Code (CSharp):
    1.     public void initializeSceneButtons ()
    2.     {
    3.  
    4.         Scene scene = SceneManager.GetActiveScene();
    5.         Debug.Log("Active scene is '" + scene.name + "'.");



    As I can see, SceneManager doesn't load HistoryScene, but it's really strange because it's changing my scene in game but not in code (still active scene is MainScene).


    Hierarchy before click:



    After click:
     
  7. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    https://docs.unity3d.com/ScriptReference/SceneManagement.SceneManager.LoadScene.html

    I'm guessing you're not waiting until the scene has loaded to call initializeSceneButtons() and instead are calling it the same frame you are calling LoadScene.
     
  8. Dante93

    Dante93

    Joined:
    Jul 12, 2017
    Posts:
    4
    Hmm, that's can be a problem, thanks for responding.
    Do You know how I can wait/check until my scene has been loaded?
    Or maybe use
    Application.LoadLevel
    instead?
     
  9. Joe-Censored

    Joe-Censored

    Joined:
    Mar 26, 2013
    Posts:
    11,847
    Application.LoadLevel is marked obsolete. I'm not even sure it is still included.

    The way to check what scene is loaded when you're using SceneManager.LoadScene is the code I put in comment #5, SceneManager.GetActiveScene()