Search Unity

How do you pass run parameters into a scene when loading? (for a puzzle game with lots of puzzles)

Discussion in 'Scripting' started by gmfbrown, Nov 19, 2021.

  1. gmfbrown

    gmfbrown

    Joined:
    Jan 9, 2019
    Posts:
    25
    I'm trying to make a puzzle game with a large number of small puzzles (for comparisons, think Baba is You or Cut the Rope or something like that). Since there are so many puzzles, and they all have some underlying structure, I don't want to create a new scene for each puzzle. Instead I want to create a single scene that denotes a puzzle in general, and pass in run parameters to make sure the appropriate puzzle gets loaded.

    But I don't know how to do that.

    To load scenes in Unity I've been using SceneManager.LoadScene(). That function has two input parameters. The first parameter can either be a string called SceneName or an int called SceneBuildIndex. Either way, that parameter would be used to identify the scene itself. The other parameter is called mode, and it has some weird data type I'm not familiar with, and I don't understand what it's for. Am I supposed to use that mode parameter to somehow indicate which puzzle is supposed to load? If so, how?

    Alternatively, I know that, when instantiating a prefab, there's a thing you can do where you set the active status of the game object False, then instantiate the prefab, then call some public functions to pass in the parameters. Do scenes work in a similar way? If so, how?

    Or is there a completely different way to do this? If so, what?

    Or do I have to give up on run parameters for scenes altogether and just create a new scene for each puzzle?
     
  2. spiney199

    spiney199

    Joined:
    Feb 11, 2021
    Posts:
    7,927
    The weird data type you see when loading a scene by use of SceneManager.LoadScene() is an enum that denotes what mode to load the scene with. The first is Singular, in which it loads the scene and unloads all other scenes, leaving you with just the one scene loaded. The other is Additive, which loads and adds the scene to any other loaded scenes.

    It's common to take the additive scene approach, and to break down parts of your game like UI, the player, levels, into scenes and load them additively. You can see this in my current project:
    upload_2021-11-19_19-25-24.png

    Side note: DontDestroyOnLoad is a special scene that survives singular scene loads. I'd say it's useful when you have singular objects (usually manager objects) you want to survive scene loads, or are working on a small project that might not need a dedicated manager scene hanging around (like my ProfileManagerScene).

    So in the case of your game, I would suggest breaking down all your puzzles into separate scenes. It will make editing each individual puzzle a lot less bothersome in my opinion.

    You'd also have a manager scene which handles the loading and unloading of any puzzles. Would be up to you if that scene also includes any UI elements. That will probably depend on the size of our project. It also makes a good way to maintain data permanency if, for example, you're tracking details about your players performance.

    To specifically answer your question, there are no overloads for SceneManager.LoadScene() that will do what you want, as it's purpose is for loading scenes and nothing else. If you want scenes to define multiple puzzles, then you'd have to devise some manner in which it knows what parts of itself to load when it's loaded in components Awake/Start/OnEnable callbacks.

    Alternatively, following the manager scene approach, you can wait for the scene to additively load, then call some function of that scene to get it to load a specific permutation. Perhaps by having a specific submanager for each of your puzzle scenes.

    Hopefully this gives you some idea of where to start.
     
    Bunny83 and Kurt-Dekker like this.
  3. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,742
    I'm with Spiney: this sounds like the perfect job for additive scene loading.

    Additive scene loading is one possible solution:

    https://forum.unity.com/threads/right-way-for-performance-divide-scene.1023673/#post-6630961
    https://forum.unity.com/threads/right-way-for-performance-divide-scene.1023673/#post-6754330

    https://forum.unity.com/threads/problem-with-canvas-ui-prefabs.1039075/#post-6726169

    A multi-scene loader thingy:

    https://pastebin.com/Vecczt5Q

    My typical Scene Loader:

    https://gist.github.com/kurtdekker/862da3bc22ee13aff61a7606ece6fdd3

    Other notes on additive scene loading:

    https://forum.unity.com/threads/removing-duplicates-on-load-scene.956568/#post-6233406

    Timing of scene loading:

    https://forum.unity.com/threads/fun...ject-in-the-second-scene.993141/#post-6449718

    Also, if something exists only in one scene, DO NOT MAKE A PREFAB out of it. It's a waste of time and needlessly splits your work between two files, the prefab and the scene, leading to many possible errors and edge cases.

    Two similar examples of checking if everything is ready to go:

    https://forum.unity.com/threads/daily-events-and-content-changes.1108202/#post-7143713

    https://forum.unity.com/threads/uni...on-before-other-scripts.1153739/#post-7401794

    As for having a persistent "what puzzle do I want right now?" approach, that's best handled with a GameManager. Here's some approaches:

    ULTRA-simple static solution to a GameManager:

    https://forum.unity.com/threads/i-need-to-save-the-score-when-the-scene-resets.1168766/#post-7488068

    https://gist.github.com/kurtdekker/50faa0d78cd978375b2fe465d55b282b

    OR for a more-complex "lives as a MonoBehaviour" solution...

    Simple Singleton (UnitySingleton):

    Some super-simple Singleton examples to take and modify:

    Simple Unity3D Singleton (no predefined data):

    https://gist.github.com/kurtdekker/775bb97614047072f7004d6fb9ccce30

    Unity3D Singleton with a Prefab (or a ScriptableObject) used for predefined data:

    https://gist.github.com/kurtdekker/2f07be6f6a844cf82110fc42a774a625

    These are pure-code solutions, do not put anything into any scene, just access it via .Instance!

    If it is a GameManager, when the game is over, make a function in that singleton that Destroys itself so the next time you access it you get a fresh one, something like:

    Code (csharp):
    1. public void DestroyThyself()
    2. {
    3.    Destroy(gameObject);
    4.    Instance = null;    // because destroy doesn't happen until end of frame
    5. }
     
    brainwipe likes this.