Search Unity

Sending data from one scene to the next

Discussion in 'Scripting' started by cybervinus, Jan 6, 2012.

  1. cybervinus

    cybervinus

    Joined:
    May 14, 2009
    Posts:
    12
    There are many ways of storing data that persists through scene changes in Unity. For example, using Singletons, static variables and DontDestroyOnLoad. However, each of these solutions is ugly in its own right; Using a Singleton breaks down as soon as you require more than one of an object, or if you need to remove that object from your game entirely. DontDestroyOnLoad means your first scene has a ton of scripts in it, because putting them elsewhere means they could be duped. Finally, static variables can be hard to find if they're abstracted inside a class hierarchy, or too easy to modify if they're public with no indication of what changed them.

    Most importantly, none of these methods actually send data to the new scene being loaded, they just store it and take it on good faith that their copies will be destroyed once the data has been received. I'd like to find a way to actually send data from one scene to the next - store it before scene load, dispatch it to whatever objects it was meant to be sent to once the scene has loaded, then destroy all copies of the data once it has been sent or throw an exception if the receiver doesn't exist.

    Any ideas?
     
  2. cybervinus

    cybervinus

    Joined:
    May 14, 2009
    Posts:
    12
    For anyone interested in not making hideous design decisions with DontDestroyOnLoad and Singletons, I came up with a solution that abstracts all the nasty stuff from the developer and makes sure that there are no un-accounted for global objects after a scene change is performed and messages passed. Here's how it works:

    When a developer wants to pass some information from one scene to the next, for example, passing the player's score to a level completion screen, they use my SceneMessenger MonoBehavior.

    The SceneMessenger uses DontDestroyOnLoad to persist through a level change, and is used to store any messages that are to be passed on to the next scene.

    Shortly before a level change, a SceneMessenger is created to hold outgoing messages stored in it (I created a static instantiate function to hide away the fact that you also need to create a parent GameObject for it to sit in).

    As the SceneMessenger persists through a level change, it can make use of the OnLevelWasLoaded MonoBehaviour callback, which fires when a level change completes. In this case, OnLevelWasLoaded calls the dispatchMessages function which sends all the stored variables off to their receivers. The receivers are forced to implement an IMessageReceiver interface which guarantees the presence of a receiveMessage callback function. Messages intended to be sent to receivers that don't implement the interface cannot be stored, and cause an error message to appear in the in-game console.

    Once all messages are sent, the SceneMessenger cleans up after itself and destroys its parent GameObject.

    Thus I no longer need to deal with 90% of use cases where i'd need DontDestroyOnLoad, a Singleton, or disgusting miss-use of static variables.
     
  3. glennpow

    glennpow

    Joined:
    Jan 30, 2012
    Posts:
    56
    Could you possibly post your SceneMessenger class code?
    I'm just curious how you handle the setting of delegates to receive messages. Thanks.
     
  4. marinl

    marinl

    Joined:
    Mar 23, 2013
    Posts:
    10
    You can create an object in first scene, attach a sript to it and sen value of variable in this script. For example if you want to send user login script attachet to game object that will survife after second scene load should be:

    Set userLogin in first scene and read in second.

    Complete example can be found in my blog http://unity-tutorials.blogspot.com/. Listing 20 and 21.