avoiding multiple event systems / audio listeners, etc. with additive scene loading

I’m using

asyncload = SceneManager.LoadSceneAsync(levelname, LoadSceneMode.Additive);

to load levels while showing a loading animation, then unloading the menu scene when it’s done. I also have a central “Init” scene that never gets unloaded with my globally persistent stuff (Steam stuff, SaveSystem, etc.) - This all works fine… except…

There is a main camera and event system in both the main menu and the levels. So I get tons of messages about having 2 audio listeners in the scene and 2 event systems. That gets eventually cleared out, but I am tracking a few errors I can’t explain and one cause I can imagine is that things get assigned to the 2nd event system that then gets destroyed.

Anyway - how do I prevent this when I use additive loading and have different scenes like this?

I NEED the two main cameras (the menu camera is obviously set up differently than the in-game camera) and the eventsystem anyway is added by Unity if I don’t have one.

I can’t use Singletons or other solutions like that because if I did, this would happen:

  • Main Menu loads (with main menu camera)
  • Player selects level to play
  • Level loads (with its own in-game camera, which must have the audiolistener attached so I get proper 3D sounds)
  • In-game camera detects there’s already another camera and destroys itself
  • Async load completes, Main Menu scene unloads, taking the main menu camera with it
  • No camera left in the scene…

The intended behaviour is that the OLD camera goes away - which it does. There’s just a couple frames where I have both. For the camera (and audiolistener) that’s merely an inconvenience (and a bunch of unnecessary debug messages). But for the eventsystem, I fear it is the cause of one elusive bug I can’t figure out.

2 Likes

Did you find any solutions?

My solution was to tell additive loading to f* off and restructure my game without it.

1 Like

Sounds like a bit of an overkill solution to a simple problem. I just use an ever present, additive scene that holds the event system (and other stuff), that gets loaded when the game is booted and remains there entire time.

Also I believe you only get the warnings when two active event systems or audio listeners are present. You can just disable the one not needed before the new one comes in as well.

Yeah but remember that you will need to be attaching the audio listener to the camera each time the scene is loaded to get the 3d effect

There are two ways you can do this.

  1. You happen to have multiple Main Cameras (tagged as main and is just a unity camera). You’ll need a Scene Management System, this management system can be responsible for Binding and Unbinding event system / audio listeners to the ‘current’ main camera when you load a new scene.
  2. You are using 1 Single Main camera that is persistent through all scenes. To see different camera views, you use Cinemachine.

Hope this helps a bit

Hi, I thought I’ve found a solution for this not so uncommon situation, but unfortunately, it seems Unity is not liking it:

I’ve a prefab with all the stuff like XR Origin (which contains a camera), XR Input modules, and so on, on a prefab which is present in all the scenes.

This prefab has a script attached to it with DontDestroyOnLoad().
If the Instance of the script already exists, it Destroy() the gameObject.

The solution virtually works (If I load another additive scene with the same prefab, it will get destroyed).

But since, I suppose, Destroy() is only called after the current Update() loop ends, Unity will complains about the “two AudioListeners are present, etc.” making the scene throwing errors, and becoming unresponsive/not working properly.

Any other solution rather than manually disableing game objects on additive scenes (which is error prone)?

Step1: Add this line to Monobehaviour class then drag scene’s EventSystem and Camera here. The EventSystem and Camera are gameobjects created by default whenever create new scene.

public EventSystem sceneEventSystem; 
public GameObject mainCamera;

Step2: Before load additive scene, deactivate mainCamera and sceneEventSystem. When mainCamera is deactivate, Unity will auto use camera of Additive scene. When sceneEventSystem is disable, there is only one EventSystem of Additive Scene currently hearing. At this time Unity NO LONGER continuously generate warning about multiple event systems

mainCamera.SetActive(false);
sceneEventSystem.gameObject.SetActive(false);        
AsyncOperation asyncLoad = SceneManager.LoadSceneAsync("AdditiveSceneName", LoadSceneMode.Additive);
            while (!asyncLoad.isDone) await Task.Yield();

//Other conditional code here

   AsyncOperation asyncUnload = SceneManager.UnloadSceneAsync("FTTGame");
   while (!asyncUnload.isDone) await Task.Yield();

           mainCamera.SetActive(true);
           sceneEventSystem.gameObject.SetActive(true);

Or only have one camera/event system, and just DontDestroyOnLoad both. Though easier to attach the latter to the former.

Can use this to instantiate it when entering play mode: Unity - Scripting API: RuntimeInitializeOnLoadMethodAttribute

If you’re using Cinemachine then you’re only going to have one camera anyway.

1 Like

Good point, yes. Using Cinemachine and having the camera on the always-loaded-dontdestroy scene would probably work.