Search Unity

Right way for performance, divide scene?

Discussion in 'Scripting' started by leegod, Dec 17, 2020.

  1. leegod

    leegod

    Joined:
    May 5, 2010
    Posts:
    2,476
    My game have Lobby scene (bunch of 2d UIs), Adventure mode (3d hexagon field), Battle mode (3d field).

    In this case, what is good for performance? (targeting for Nintendo switch, middle~high mobile device)

    1. Divide scene?

    2. Load them all in one scene and just turn on/off (activate mother gameobject) when needed.

    3. Instantiate needed mother gameobject that contains all needed child gameobjects for one scene (adventure, battle) and destroy it when finishes.

    4. other way?

    Thanks.
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,745
    I always favor breaking the scenes up and loading additively.

    - reduces overall memory consumption

    - lets multiple team members trample on each other less often

    - ensures clean "reset" of all objects in a fresh loaded scene

    I'm working on a game now where we each have our own "content" level, the level we're working on.

    the content scene has all the lighting baked in.

    Just press play and that level has one script that additively loads:

    - music scene (just an audiosource on autoplay)
    - the player scene (With controls and camera)
    - UI overlay (score)
    - pause button (could have been merged with UI overlay) <--- the only one with an EventSystem.

    It's glorious. First thing the additive loader does is load a black "Loading" screen prefab while it additively loads all the others. We don't do the loading screen as a scene because scenes always load the NEXT frame, so we would get a flash of our level when we first load it, but now it's black until all is loaded.

    Super slick, no fuss no muss.

    If we want to extend in the future, all we need to do is download a fresh scene asset bundle and it's done.

    Here's what we're doing:

    https://pastebin.com/Vecczt5Q

    Here's a related post I wrote as well about it:

    https://forum.unity.com/threads/removing-duplicates-on-load-scene.956568/#post-6233406
     
    Last edited: Dec 17, 2020
  3. FlightOfOne

    FlightOfOne

    Joined:
    Aug 1, 2014
    Posts:
    668
    @Kurt-Dekker

    Finally had some time to go through your links. Thank you!

    How do you deal with unloading these scenes? Do you unload every subscene or are they handled differently as needed?

    For example, my current set up is like this:

    Management Scene (This runs all the time, never unloaded)
    -Keeps the game manager
    -Audio Manager
    -Pause menu (only active in play scenes)
    -VFX manage etc.. all the global managers are here.

    Start menu scene
    -Level for start menu, has the start menu manager
    -Loads a map scene

    Map Scenes
    These are mainly terrains and static objects in the terrain. These maps are shared between levels.

    Gameplay Scenes
    -Loads a map scene

    I'd love to know what your thoughts are. Should I be splitting them up more? Another concern is which is going to be the active scene because I don't want to spawn (e.g. bullets) things in just any scene.


    Thanks!
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,745
    Glad you asked... going this route definitely requires slightly-higher awareness of what scene is what.

    In no particular order, responding to you questions,

    - When the game or level is over, I try to go to a fresh "end level" scene (not additively!) and clear everything else out (except overall ongoing game manager obviously, as a singleton)

    - when the game gets paused I stop time and bring up a pause scene that sorts above all else, then unload it and restart the time. OR if you quit, I just go straight to the gameover scene, which loads only itself and maybe UI (or else mainmenu)

    - I usually make the content scene (what constitutes the level) be the active scene. This lets it have custom lighting.

    - When I spawn things like bullets (or enemies), I often parent them to a bullet manager GameObject, which probably lives in the player scene. You can always change which scene a GameObject is in, if you really care.

    - when the player dies and respawns I usually unload his scene, then load it afresh. That scene has enough logic in it to look around for waypoints that might have been triggered as a result of making it to a certain point in the level, or else falls back on the default content initial spawn point

    Overall your strategy above seems reasonable. The devils are often in the details, and keeping things separate makes it easier to organize things differently as your needs or priorities change during development.

    ALSO: put in lots of Debug.Log() spew that says stuff like "UNABLE TO FIND PLAYER SPAWN!" so you can quickly diagnose errors during testing.

    The one thing I haven't solved yet is warnings about having multiple audio listeners at once. Depending on how long it actually takes to async load a scene, various platforms may spuriously produce this warning for a couple of frames. However, I've never seen a customer-facing issue about it.

    The other thing to watch out for is to NEVER have zero cameras. On certain platforms like Android, this will result in a garish flash of garbage graphics. I often put a camera in my main level-loading scene and turn it off after a few frames. That's easy to test by inserting a Debug.Break() when you start a new game and then single-stepping Unity to make sure there is always a camera each frame.
     
  5. FlightOfOne

    FlightOfOne

    Joined:
    Aug 1, 2014
    Posts:
    668
    Sorry for the late reply. Thank you so much for taking the time for this detailed reply! I think I really like this method, especially because its clean and neat. Single responsibility scenes, I love it! :)

    For the audio listener you seeing the debug logs for few frames shouldn't be an issue. Also, you can (and should. Also have something settings menu to turn it back on for any troubleshooting) disable (
    Debug.logger.logEnabled = false
    ) debug logs entirely on builds.
     
    Kurt-Dekker likes this.