I am working on loading/unloading scenes seamlessly.
I use a transition scene, which is animated so any stutter is not acceptable.
Here are the steps:
// Add transition scene by creating a new empty scene on top.
Scene transition = SceneManager.CreateScene("transition");
// Set it as active.
SceneManager.SetActiveScene(transition);
// Unload the old scene async (called "game").
AsyncOperation asyncUnload = SceneManager.UnloadSceneAsync(SceneManager.GetSceneByName("game"));
// ...
// Once the old scene has finished unloading:
// Load the new scene async (new instance of the same scene called "game").
AsyncOperation asyncLoad = SceneManager.LoadSceneAsync(SceneManager.GetSceneByName("game"));
// ...
// Once the new scene has finished loading, switch it to active.
SceneManager.SetActiveScene(SceneManager.GetSceneByName("game"));
LoadSceneAsync works as expected.
UnloadSceneAsync doesn’t. The game freezes entirely from the moment UnloadSceneAsync is called until the AsyncOperation value isDone is true.
After further testing it seems that the game freeze is proportional to the complexity/size of the scene being unloaded. If the scene doesn’t have much then there’s no stutter.
As a test I destroyed manually all the objects on the scene instead of unloading the scene, and it freezes for the same amount of time.
My guess is that no matter how the scene is unloaded asynchronously, objects are still destroyed all at once regardless.
What helps a lot is to implement your own solution to destroy objects incrementally over many frames, before unloading the scene.
In most scenes, you could run into a lot of serious problems very quickly if you randomly destroyed half the objects while still allowing the other objects to continue running as if nothing were wrong, so I’m not surprised that unloading a scene would destroy all of them in a single frame.
Sure, it’s just that the UnloadSceneAsync name is misleading then. What does it actually do asynchronously? Removing the scene once it’s empty? That’s not a heavy operation.
Deactivating the scene will stop it from receiving updates and other activity. After that you may destroy objects one by one in a coroutine. This is ugly and poor solution, but since objects must be destroyed on the main thread i think there may be no choice
1 Like
That might be helpful, but use caution: Deactivating a large number of game objects can also be an expensive operation, and it won’t stop them from responding to explicit function calls from other parts of your code.
1 Like
You haven’t mentioned what platform you’re seeing this on, so just want to point out that scene async loading/unloading instead blocks in the editor play mode and in WebGL builds. Make sure you’re testing this only in a build which supports async loading.
How do you deactivate a scene? I saw now way to do that, only grab the root GO and iterate a SetActivate(false)
1 Like