I know OnLevelWasLoaded() doesnt work when you load only one scene, since it isnt taken as new scene, but, the problem lies even with loading Scene Additive:
using UnityEngine;
using UnityEngine.SceneManagement;
public class GameManager : MonoBehaviour
{
void Start()
{
SceneManager.LoadScene("Scene_2", LoadSceneMode.Additive);
}
void OnLevelWasLoaded(int level)
{
Debug.Log("Something loaded");
}
}
The OnLevelWasLoaded() is not called, I tried as you see with Debug.Log and breakpoint. The second scene is normally loaded additive, and appears in Hierarchy, which I can see.
Where could be a problem? Is OnLevelWasLoaded() not working in Editor?
It is correct that OnLevelWasLoaded is not called for scenes loaded additively.
Unless this has regressed since 5.2 it is not something that will be fixed. In 5.2 you could call Application.LoadLevelAddtive and this did not call OnLevelWasLoaded as far I know.
In 5.4 we have added some new events to SceneManager. SceneManager.sceneLoaded, SceneManager.sceneUnloaded and SceneManager.activeSceneChanged. These will also be called for scene loaded additively.
I am not sure I understand what the problem is. OnLevelWasLoaded did not regress in any way and 5.4 beta is available to every one even Personal Edition users.
what im talking about is the delay between rolling out scene manager and
SceneManager.sceneLoaded, SceneManager.sceneUnloaded and SceneManager.activeSceneChanged
events.
what im doing right now is throwing a special object that raises event to game manager onEnable, basically notifying that scene has loaded from withing the scene, very hacky.
Any way, yes SceneManager shipped with some, in hindsight obvious, features missing. We are working hard on adding these features and fixing the bugs and workflow issues that have been reported. Most bug fixes are being back ported to 5.3 and shipped in the patches but new features are not back ported as we don’t want to introduce new features in patches, so for features you will have to use the beta releases.
hm, i just switched to 5.4beta and tried SceneManager.sceneLoaded, but it seems it gets called before the scene is actually loaded…
I have a ManagerScene that has a GameObject with the following MonoBehavior on it:
using UnityEngine;
using UnityEngine.SceneManagement;
using System.Collections;
public class LoadLevel : MonoBehaviour {
public static string currentLevel = "lvl1";
void Awake () {
SceneManager.sceneLoaded += SceneLoaded;
SceneManager.activeSceneChanged += InitializeNextScene;
if (SceneManager.sceneCount < 2)
{
SceneManager.LoadScene(currentLevel, LoadSceneMode.Additive);
}
//StartCoroutine(SetActive(currentLevel));
}
void SceneLoaded(Scene scene, LoadSceneMode m)
{
Debug.Log("Scene loaded: " + scene.name + " in mode: " + m); //scene.name is lvl1, as expected
Debug.Log(Time.frameCount + "Active Scene: " + SceneManager.GetActiveScene().name);
//ManagerScene is active, as expected
SceneManager.SetActiveScene(scene);
Debug.Log("is scene loaded: " + scene.isLoaded);
//this prints that scene is *not* loaded; isn't the whole point of
//SceneManager.sceneLoaded that it gets called after the scene is loaded?
Debug.Log("Active Scene: " + SceneManager.GetActiveScene().name);
//this still prints that ManagerScene is active
var go = GameObject.CreatePrimitive(PrimitiveType.Cube);
go.name = "testCube"; //testcube ends up in ManagerScene, not lvl1
}
static void InitializeNextScene(Scene old, Scene justActivated)
{
Debug.Log(Time.frameCount + "scene activated " + old.name + " " + justActivated.name);
}
//IEnumerator SetActive(string scene) //this worked fine
//{
// yield return null;
// SceneManager.SetActiveScene(SceneManager.GetSceneByName(scene));
// Debug.Log("Active Scene: " + SceneManager.GetActiveScene().name);
// var go = GameObject.CreatePrimitive(PrimitiveType.Cube);
// go.name = "testCube";
//}
}
Yes loading != activated
so you better move object creation to the end of your activation coroutine
as a proposal to unity team, would be awesome if you would do this coroutine wrapper yourself and give us a callback on when its done.
like
SceneManager.ActivateScene(Scene scene, Action Callback)
so that under the hood it does all the activation. just make like “scene activator” that just stores which ones have to be activated and does that next frame, then makes a callback.
Even tho you receive onloaded notification you still need to wait one frame before you are allowed to activate the scene.
What i do for my levels system i have selected “active scene” for a level,
i thought the reason you can’t activate the scene right after telling unity to load it is that it takes one from to load. and reacting to SceneManager.sceneLoaded would notify me once it’s done loading, so i would then be able to activate.
if sceneLoaded gets called when the scene starts loading, that seems a bit worthless, since my code caused the load of the new scene anyway, so i’m already “notified”, and can just put whatever i would do in response to sceneLoaded right after the call to SceneManager.LoadScene instead.
So what is the practical difference between the following 2 scene states, and does isLoaded mean the same thing as the scene being active? When is one state preferred over the other?
SceneManager.sceneLoaded calls its delegates, but scene.isLoaded == false
SceneManager.activeSceneChanged calls its delegates, and scene.isLoaded == true
Loaded != active. Only one scene can be active at a time, that scene will be used to sample lighting settings and to instantiate objects in.
Basically you can think of all the loaded scenes as background and active as foreground.
Also remember that order is important, and if you load your managers scene after the one that is dependent on managers, it wont be able to locate it (that was true last time i had this issue),
so i think of scenes as scopes in code, the lower the order of the scene the lower the scope.
That may have been changed.