Search Unity

Preferred pattern for multi-scene objects

Discussion in 'Scripting' started by eneroth3, Dec 11, 2018.

  1. eneroth3

    eneroth3

    Joined:
    Oct 22, 2018
    Posts:
    63
    I have a few objects I'd like to have in all my scenes, e.g. the pause menu. I've seen a few different patterns to handle this but all seem to have different drawbacks, and I'm wondering what is to be preferred, and why.

    The Saving and Loading data live session shows a pseudo singleton pattern, where a gameObject is present in all scenes, is kept when unloading a scene and destroys itself if it there is already such an object from the previous scene. This pattern requires you to add that object with that script to each and every scene, and if you forget you'd get hard to debug errors, as scenes behave differently when run directly in the editor vs when run after another scene. It would work but it just doesn't feel right.

    Another pattern I've scene is to first load a "persistent" scene that loads its GameObjects, set them not to be destroyed when unloading the scene, and then jumps to the first "real" scene. This has the drawback that you must always start at that scene; you can't just run any scene in the editor for testing.

    I've also looked a bit at making an actual singleton class, that creates an instance of itself when loaded and add it to a static variable for other scripts to reference. However, as this isn't a MonoBehavior associated with a specific GameObject in the scene I don't think I can access user input and other events from here. I could be wrong here though, as I'm still quite new to Unity.

    What other patterns are there, and what benefits do they have?
     
  2. What I usually end up choosing is I don't switch scenes on a destructive way so I make my menu and other auxiliary stuff in a separate scene, load everything additionally and remove scenes I don't need and load additionally when I need them "manually".
    I really don't like the DontDestroyOnLoad pattern and method. After two of these you will lose yourself in it and just can't follow when what should not be destroyable and why and how long...
    Work with small scenes and load/destroy them yourself as needed. This works for me at least. (not to mention you can go full seamless scene switching if you want easily).
     
  3. lordofduct

    lordofduct

    Joined:
    Oct 3, 2011
    Posts:
    8,537
    The big thing is that what is to be preferred can vary from project to project, work flow to work flow, etc.

    The various drawbacks and benefits can be useful or not depending on the project you're in.

    ...

    For example the last 2 games I made (they're in a series, a 3rd one is currently be developed) have various UI elements that are necessary in each scene.

    PauseMenu
    MessageBox
    InventoryDisplay
    etc.

    Thing is the look & feel of these can change. We have 3 characters in the game and as you change scenes you might take control of another character and their UI changes (for example we have a little girl you play as temporarily, and when you open the pause menu all the text looks like it was written by a child).

    Also we have extra game modes and secret areas that also have custom UI. Such as an 'Overtime' mode that has you freely moving around the mansion in our game looking for items to build a weapon to defeat a giant monster hunting you down. The PauseMenu here has a map in it showing the locations of said items which isn't shown in any of the other pause menus.

    This means requiring someone to place the appropriate UI elements needed for each scene into that scene is useful since it allows for the most customization from scene to scene.

    ...

    Of course there are some things that need to be in each scene that don't really change. Such as our 'InputEventSystem'. Note that the Unity UI system requires an 'EventSystem' to exist in the scene for it to work (a sort of pseudo-singleton). BUT we wrote a special version of it since we use our own Input system and don't really directly use the unity 'Input' class (unity's input has horrible controller support). So to get the UI to work we have our own 'EventSystem' that needs to exist in every scene.

    Since this one is pretty much ubiquitous, in my 'SceneManager' after loading a scene I just check if an 'EventSystem' exists, and if it doesn't I spawn one. Ensuring that one exists even if someone forgot to place one in.

    Note that since I check if one exists first, technically speaking we could use this as a way to allow custom stuff in each scene still. We could force ensure a 'PauseMenu' exists in each scene based off some 'default prefab' in our GameSettings if one doesn't already exist. We just never really implemented this since well... we haven't needed it yet. All our UI are prefabbed out.

    ...

    Of course in our 3rd game we'll probably need something more robust. This being because you can swap between characters on the fly. Unlike previous games where swapping characters was a controlled thing (specific events in the game caused it)... in Ep3 we plan to allow the player to swap characters at any moment. As a result I'll need to be swapping out UI elements on the fly.

    When that time comes I'll probably be looking for a more robust approach than I currently have.

    Probably go with a ScriptableObject that creates a "UI Package" with references to the prefabs for each necessary UI element. A 'UI Package' is then associated with each player. So then when a scene loads I check which character you are, spawn the appropriate UI from said package and start play. If you swap character I delete all UI, get the UI package for the new character, and spawn that.

    ...

    If I wanted an end-all be-all system, it'd probably be some abstraction of this "UI Package" since it'd allow for easy defining of different UIs. Then each scene just gets associated with the package. If it's a "level" it gets the "level ui package", if it's something else like a "menu scene" it gets a "menu scene ui package".

    But that's a whole lot of setup that I just haven't done because well... I haven't needed it.

    Because honestly, just dropping the prefab into the scene for the UI I want for that scene just works for now. It's fast. Our project isn't at the scale where the package is necessary. Sure I've done some changes which caused me to need to go from scene to scene and drop new stuff in it... but we have maybe 50 scenes max... it took all of 10 minutes. And since we're a team of 2, it wasn't an inconvenience.

    If I was on a larger team, or in a much larger project. Well... I'd probably start thinking about doing it.

    Which as stated... now that we're to episode 3... we're pretty much nearly to that point now due to the requirements of the project.

    ...

    TLDR;

    Do what works for your project best.
     
    eneroth3 likes this.
  4. eneroth3

    eneroth3

    Joined:
    Oct 22, 2018
    Posts:
    63
    Thanks for the input!

    I think I'll make an all-scenes prefab, and put these scripts there. If I forget to add it to one scene it should be quite noticeable what is wrong.