Search Unity

Is there any function that gets called when a newly loaded level is ready?

Discussion in 'Scripting' started by Marscaleb, Jan 27, 2015.

  1. Marscaleb

    Marscaleb

    Joined:
    Jan 7, 2014
    Posts:
    1,037
    I need a method to indicate when a newly loaded scene is ready, and "OnLevelWasLoaded" is not accurate enough.

    I created a system for making screen-wipes for scene transitions; I have a variety of custom effects that paint the screen black, and then un-paint it when the new scene loads. Because I often have the game "paused" during these effects, they use unscaled delta time (otherwise they would be just as frozen as the game.)

    But when I load a new level, the wipe-in effect suddenly runs super fast, often looking like it cleared through 80% of its effect in one single frame.
    The wipe-in effect is called and initiated at the very end of my OnLevelWasLoaded function. So clearly, that function gets called before the new level is actually ready. There are still a number of things that need to get set up in the new scene. At the very least, the start functions have not been called, but honestly I wonder if there is even more that gets executed between the call to OnLevelWasLoaded and when the first viable frame in the new level finishes.

    Now I can try to get around this problem by invoking the call to start the wipe in, say by a tenth of a second. But then I will run into precision issues with different devices. A slow machine would still have the same exact problem because the command was issued before everything was ready.

    So my first thought is: is there some additional function that gets called just a wee bit later in the the cycle, perhaps something that gets called when everything in the new scene is actually ready?

    My second thought is: maybe, just maybe, all that delay I am experiencing is all in one single frame, and all I need is to call this function on the very next update. To that end, is there some built-in functionality that will execute a function on the next update, rather than a set amount of time? (I suppose I could add a new bool and check for it on every update, but that seems kind of wasteful for something that will rarely get called.)
     
  2. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    You could put your transition call on a GameObject in the new scene, call it in Start and set the execution order for that script type to be later than normal.

    To your other question - use a coroutine that yields a single frame

    Code (csharp):
    1.  
    2. void OnLevelWasLoaded()
    3. {
    4.     StartCoroutine(Wait());
    5. }
    6.  
    7. IEnumerator Wait()
    8. {
    9.     yield return null;
    10.     DoStuff();
    11. }
    12. [code]
     
  3. Eric5h5

    Eric5h5

    Volunteer Moderator Moderator

    Joined:
    Jul 19, 2006
    Posts:
    32,401
    OnLevelWasLoaded is perfectly accurate; it works exactly the way the docs says it works. Your issue sounds like Time.deltaTime was exceptionally high for one frame because of the time it took to load the level. So KelsoMRK's suggestion to wait a frame sounds good.

    --Eric
     
    angrypenguin likes this.
  4. Marscaleb

    Marscaleb

    Joined:
    Jan 7, 2014
    Posts:
    1,037
    Okay, I tried the coroutine option and it worked fantastically!

    Thanks for the suggestion!
     
  5. angrypenguin

    angrypenguin

    Joined:
    Dec 29, 2011
    Posts:
    15,619
    For this exact reason I clamp my Time.deltaTime value before using it for any load-time animations. So instead of just using Time.deltaTime I use Mathf.Min(Time.deltaTime, 0.33f), where the "0.33f" part is some number about twice as long as I expect my normal frames to take - that way you've got enough headroom that the animation won't go into slow motion if you hit a slow patch, but any single frame that hangs won't eat the whole animation.