I’m working on smooth transitions when switching between scenes. For this, I want to load a scene additively, transition, and then remove the old scene. I am loading a scene and then setting it active as such:
However, this does not work if the two scenes I am switching between have the same name. Specifically, I might want to transition from and to the same scene (ie a scene that is able to load various pieces of content). After calling SceneManager.LoadSceneAsync(name, LoadSceneMode.Additive), how can I get the specific Scene object that has been loaded as opposed to having to get it via its non-unique string name?
To provide more context, here is the full example I’m working on. To handle the transitions, I have exactly one SceneController component in each scene which defines the async operations TransitionIn and TransitionOut.
public async UniTask SwitchScene(string name)
{
var oldScene = SceneManager.GetActiveScene();
var oldSceneController = FindObjectOfType<SceneController>();
await SceneManager.LoadSceneAsync(name, LoadSceneMode.Additive);
SceneManager.SetActiveScene(SceneManager.GetSceneByName(name));
var newSceneController = GetComponentInActiveScene<SceneController>(); // a method that I wrote
await UniTask.WhenAll(
oldSceneController.TransitionOut(),
newSceneController.TransitionIn()
);
await SceneManager.UnloadSceneAsync(oldScene);
}
I am using C# async/await with UniTask in this example, but in terms of the API this should not matter.
Hi MalvMay!
Thanks for your answer, though this does not work for me - I’m not talking about two different scenes assets with incidentally the same name.
Imagine I have only one Scene asset, in Assets/MyScene.asset
Then I want to:
It’s not my area of expertise but could you hook into the sceneLoaded event to know the scene and that it has been loaded, then perform further actions?
Ah the sceneLoaded event might help, I will try. Kind of a hacky solution since I have to make sure that no scene is loaded in the meantime and to unregister the first time the event fires… but it might work.
Encountered the same problem while trying to use additive scenes as patches for a large streaming world.
I resorted to prefabs instead, but it is kind of strange that SceneManager.LoadSceneAsync doesn’t return scene handle on completion.
You might want to use Addressables as Addressables.LoadSceneAsync returns AsyncOperationHandle and SceneInstance has Scene property.
When you call SceneManager.LoadSceneAsync, the scene handle is immediately created (though not valid yet), so you can get it using SceneManager.GetSceneAt(SceneManager.sceneCount - 1) right after you call LoadSceneAsync, event before you yield the AsyncOperation. (Also, the newly created scene will always be the last scene in the scene list)
So, no need to wait for the scene to be loaded to get it, and you can always get the correct scene to operate.
Here’s a simple example script: (the context is a Coroutine function)
var loadOp = SceneManager.LoadSceneAsync("SomeScene", LoadSceneMode.Additive);
// scene not loaded, but already created! Even before you yield the loadOp
var newScene = SceneManager.GetSceneAt(SceneManager.sceneCount - 1);
yield return loadOp;
// now the newScene is loaded, you can do something...
var rootObjs = newScene.GetRootGameObjects();