0
\$\begingroup\$

I recreated the problem in a new project to check and test the problem, but I don't understand it.

Two scenes:

First scene

A GameObject with this script that simply jumps to the second scene.

script1_S1.cs

void Update() {
    if (Input.GetKeyDown(KeyCode.A)) SceneManager.LoadScene("Scene2", LoadSceneMode.Single);
}

Second scene

Two GameObjects with two different scripts.

The first script can go back to scene1 or invoke an event.

script1_S2.cs

public delegate void OnMyEvent ();
public static event OnMyEvent onMyEvent;

void Update() {
    if (Input.GetKeyDown(KeyCode.A)) SceneManager.LoadScene("Scene1", LoadSceneMode.Single);
    if (Input.GetKeyDown(KeyCode.S)) onMyEvent?.Invoke();
}

The second script registers the event and loads the rootVisualElement of the UIDocument included as a component in the same GameObject of this script.

script2_S2.cs

private void Awake() {
    ScriptCube1.onMyEvent += () => { Log(); };
}

public void Log() {
    gameObject.GetComponent<UIDocument>().rootVisualElement.style.display = DisplayStyle.Flex;
    Debug.Log("Cliccked");
}

Steps to reproduce the error

If from the first scene I press A I go to the second. In the second one I press S and the console prints Clickcked, and everything works fine. But if I go back to scene 1, and again to scene 2, if I hit S, I get this error: MissingReferenceException: The object of type '...' has been destroyed but you are still trying to access it..

SceneManager.LoadScene Shouldn't it load the scene as if it were the first time? What am I missing?

Thank you.


After writing all the question I have a doubt. But maybe the problem is that the event has not been deregistered? the error is on the gameObject as if it didn't exist anymore. With SceneManager.LoadScene("Scene1", LoadSceneMode.Single); shouldn't it unregister all events in Scene2? Should I unregister all events? or do I have to use SceneManager.UnloadScene explicitly?

\$\endgroup\$
7
  • 1
    \$\begingroup\$ I'm not 100% sure in this but the event is more like a pointer to the function you are trying to call. While logically it is the same function (Log()), the second time you are loading scene2, onMyEvent has now two reference to Log() since you never removed the listener. The first one still points to the now already destroyed old scene, as the error says. I don't think UnloadScene helps, since the scene does not know where your events are actually pointing at \$\endgroup\$
    – Zibelas
    Jul 29, 2023 at 19:37
  • \$\begingroup\$ @Zibelas It is sure that the event is not destroyed. If I leave only the log command Debug.Log("Clicked"); at the second loading of the scene2 the console prints Clicked twice. The solution I found is this; in script1_S2.cs destroy the event with the GameObject: private void OnDestroy() { onMyEvent = null; } \$\endgroup\$
    – Baro
    Jul 29, 2023 at 20:44
  • \$\begingroup\$ The event is not destroyed, it is about what the underlying function that gets registered on it. And while setting it to null will work, cleaner would be to remove the listener to just the exact function. While this makes no difference in this case, if you ever register more than one function to the same event, you might not want/ need remove all of them \$\endgroup\$
    – Zibelas
    Jul 29, 2023 at 20:46
  • \$\begingroup\$ If you solved your problem, be sure to post the solution as an Answer below. \$\endgroup\$
    – DMGregory
    Jul 29, 2023 at 20:47
  • 2
    \$\begingroup\$ The static should be the culprit, thats why when you reload the same scene, you still have data on it from the time before since it is the same onMyEvent as last time. \$\endgroup\$
    – Zibelas
    Jul 29, 2023 at 21:04

1 Answer 1

1
\$\begingroup\$

It all comes down to the static. It makes the life both easier and harder. Since onMyEvent is static, there is only one of it. That means, even if you destroy the scene and reload it, you get the same onMyEvent with all the values assigned from the last scene back.

Since you are assigning a function to it on Awake, you point now twice to the Log function. This can cause errors since to what we originally pointed might got already destroyed.

The clean way would be to remove the listener/ subscription in the OnDestroy of the scene or set the event null if you are sure there are no side effects (since there can always be the option that other scripts are as well adding their listeners to it). Another option is to remove the static modifier, a new scene would create a new, empty version of the event.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .