How to pass information from one Scene to another...

Hey all,
My non-work goal at work today is to find out how to pass information from one Scene to another. My research led me to the following ways;

The way suggested by the documentaion

// Make this game object and all its transform children
// survive when loading a new scene.
function Awake () {
DontDestroyOnLoad (this);
}
// user this in the new scene to find what you saved from the last scene
var thatPersistingObject: GameObject; 
function Awake() 
{ 
  thatPersistingObject = GameObject.Find("ObjectName"); 
}

Problems seem to include textures and array data not being saved and having problems accessing anything from the game object.

The easy way

class CGlobals { 
    static public int money = 0; 
    static public bool paused = false; 

    static void Startup(){ 
        Debug.Log("Your stuff is my stuff and my stuff is my stuff"); 
    } 
}

All you have to do is add the keyword static and the variable will persist from one scene to another? I think I am missing something.

http://www.unifycommunity.com/wiki/index.php?title=AManagerClass seems to be mostly the same thing.

Can anyone confirm the problems with DontDestroyOnLoad and/or explain the static / AManagerClass to me (Or is it just as simple as adding the keyword static)?

Thanks,
Sammual

I use DontDestroyOnLoad and it works fine for me. The way I use it is I have a GameManager script that is loaded at the very beginning of the game, it handles everything from monitering the game progress and state, to activating and disabling game objects, hud stuff in the game, and updating/saving the game globals.

I believe static variables are only good for active objects in the scene, so you would have to carry them over in order to use them.

What I do is use DontDestroyOnLoad on everything I want to carry over, for example I build all my hud stuff in the start scene, and on those guiTexture objects, I add the DontDestroyOnLoad script, and all of those objects carry over to the game scene where they can be actived/deactivated or updated.

Works really well for me.

Hope that helps you out.

-Raiden

1 Like

That does help me out, thank you.

Any chance I could get a small sample with the following?
2 Scenes, one that sets up a game object and then a second that uses that object in some way.

Sammual

Hi Sammual, I would attach something, but I don’t have any server space (thats on my list of todo’s).

I can tell you in code though basically how to get this started.

The current project I am working on, my very first scene is designed to handle the opening logos, but I also have my most valuable object in that scene and its GameManager.

This object has a script that holds references to everything in my game, including the main menu. The reason I did it this way is simply because I find it easier to reference one script throughout the game when I want to influence game decisions, such as “all my lives are gone”, or “the user has decided to go back to the main menu”, and many more things, those are just 2 examples.

So here’s a small take of GameManager , keep in mind, I program in javascript not c#:

// Start.scene
// Desc: Empty game object that has the 2 following scripts attached
// GameManager.js
//  DontDestroyObject.js

// GameManager.js
// game setup values
var menuMusic : AudioClip;
var gameMusic : Audioclip;
var maxScenes : int = 26;
var highScore : int = 1000;
var gameScore : int = 0;
var gameLevel : int = 1;

// gui setup values
var coverTexture : Texture2D;
var logoTextures  : Texture2D;
var menuTexture : Texture2D;
var coverFade     : GameObject;
var pauseGame     : GameObject;
var life1         : GameObject;
var life2         : GameObject;
var life3         : GameObject;
var levelText     : GameObject;
var scoreText     : GameObject;
var timerText     : GameObject;
var gameWonText   : GameObject;
var GWDelay  : float = 3.0; // Game Won text delay time
var levelUpText : GameObject;
var LUDelay  : float = 3.0; // Level Up text delay time
var readyGameText : GameObject;
var RGTDelay : float = 3.0; // Ready Game text delay time
var gameOverText  : GameObject;
var GODelay  : float = 3.0; // Game Over text delay

// game control values
private var gameReady    : boolean = false; // should we show the "Ready" text
private var gameWait     : boolean = true;  // run condition of all object loops, suspend them for other game states to process
private var gameWon      : boolean = false; //diddo
private var gamePause    : int = -1; // are we at a paused state (-1 is neither paused or unpaused, 0 is unpaused, 1 is paused)
private var gameQuit     : boolean = false; // should we quit the game? 
private var gameMenu     : boolean = true;  // should we go back to menu?
private var gameInst     : boolean = false; // should we go back to instructions?
private var gameStats    : boolean = false; // should we display the game craft stats?
private var gameRestart  : boolean = false; // should we restart the game 
private var levelCleared : boolean = false; // did we clear the level?
private var displayStats  : boolean = false; // are we shoing the stats screen?

I’ll stop here and explain some, I know that not all games will be like this, but you can see in my GameManger script, I am making references to alot of game objects, and variables. With the exception of a Texture and some control variables, all of these don’t have anything to do with the Start scene, they are mainly used in the other game scenes, but again my reason for this is to have one place to control the game from, it just makes it easier to manage and keep up with how the game should flow.

Now the neat part is adding the DontDestroyObject script which simply goes like:

function Awake() {
  DontDestroyOnLoad(this);
}

Easy enough, and now when I load my Menu.scene, my GameManager object will be accessible in that scene, and when I load my Game scene, my GameManager object is accessible from there too.

So since my Start.scene holds all my menu/game hud stuff(textures, texts, etc.) I also to put the DontDestroyObject on those game objects and carry them over to the other scenes where I can access them to update them however I need to.

Took me a while to get my head wrapped around it all, but once you understand how you can share objects between scenes like this, it really makes a difference in your programming, you can be really creative.

Finally, one last note on GameManager, in any of my other game scripts, when I need to update say the “gameLevel” global that is defined in GameManager, in my other script, I start by getting a reference to GameManager:

private var manager : GameManager;

function Start() {
  manager = gameObject.FindObjectOfType(GameManager);
}

Now you have full control of GameManager in that script and can update values, change game control state booleans, whatever.

For example, let’s give an extra life, so we need to update gameLives in GameManager

//... in your other game scenes function
manager.GetComponent(GameManager).gameLives += 1;
//....

Then you can take it another step and update the GUIText that displays your lives(remember I built a GUIText object back in the Start scene, and applied DontDestroyObject to it).

This part explains “static” on my GUIText, here is the code for it:

static var levelText : GUIText;

function Awake() {
	levelText = gameObject.GetComponent(GUIText);
}

static function ShowLevel(level : int) {	
	levelText.text = "Level : " + level.ToString();
}

Keep in mind a static function requires static variables, also remember you have to have in instance of this in order to call the function. So since this has a static variable and function, and… you have access to it because even though this object was built in the Start.scene, but you added DontDestroyObject to it, which carried it over to the Game.scene, you have full control over it and once you have increased your “gameLevel” in GameManager, you can update your text level display in the game by simply calling:

... in your other game scenes function
// you've updated your gameLevel, now update your display
var newLevel = manager.GetComponent(GameManager).gameLives;
GUITextLevel.ShowLevel(newLevel);
// ....

I hope that makes sense, as you can see your referencing GUITextLevel which is the script name of the GUIText object that shows your current level on the screen. Since it’s all static, you don’t have to access it through FindObjectOfType();

Thats all there is to it! I’m no expert though, so if any other programmers would like to comment on my process, or inform me of better ways of doing what I’m doing, I’m always open for suggestions.

Hope that helps you understand better.

-Raiden

Raiden, your explanation has helped me understand how to handle static/global variables and functions both in the same scene and across multiple scenes, so thank you very much!

Thanks :slight_smile: I’m glad I could help out.

If anyone is interested, I’ve worked up a small example project that you can study if you need to. It’s not an actual game, but it does show you how to pass objects from scene to scene, and makes use of static variables and functions.

Just shoot me a PM with your email, and I’ll send it to you.

-Raiden

may be you can use a singleton :

using UnityEngine;
using System.Collections;


public class GlobalVariable
{
    public string myGlobalVariable1, myGlobalVariable2;

   

    #region Init / Gestion du singleton

    private static GlobalVariable instance;
    public static GlobalVariable Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new GlobalVariable();
            }

            return instance;
        }
    }

    #endregion

}

and Call it :

GlobalVariable.Instance.myGlobalVariable1 = "toto";
GlobalVariable.Instance.myGlobalVariable2 = "tutu";
1 Like

Just found this topic and wanted to thank you, Raiden, for a very helpful post!

Made so much sense that even I understood it :smile:

I found it useful too. Thank you Raiden.

Raiden, thank you!

You explanation was amazing and helps a ton. Now to go back and rework my HUD structure…again. A great game can be ruined by a poor interface.

  • Ryan

I just posted these very same questions. And of course I found this afterward :slight_smile: Thanks this was a huge help !!

How do you test a single scene in Unity if your Manager object is only loaded through the game start scene?

In other words, I often test the level I’m working on without going through all the menus etc, so the Manager object would never load.

I guess I need to change this practice at some point though (this is my first Unity game).

Anyways just curious if anybody uses a workaround for that, or just always tests their game from a “normal launch”. Of course, if your manager only holds certain variables you might still be able to test an individual scene without those.

This where the Singleton plan comes in handy.

I’m checking out the singleton scripts on the Wiki. I’ve set up a game manager object already, but as I stated, I’m afraid it my hamper my ability to test single levels at some point.

I could just add some hotkeys that will allow me to jump to any level I want after I get to the main menu, but…I dunno.

I’m trying to understand exactly what a singleton is, especially one that you don’t attach to a component. I’m not an expert programmer (I’m using JS by the way). Can anyone explain fundamentally how a singleton works?

I do this in JS by simply adding booleans for skipping parts of the scenes such as the menu scene, and also checks for skipping to different levels to test.

All this is done in the GameManager.js script, and works well for me.

-Raiden

Cool, thanks. Ya, this seems to be working for me too. Thank you.

Well , right before i read this , i got an idea (still implementing it)

The idea is to use PlayerPrefs , and store an int ( 1 for true , 0 for false ) then call it from your other scenes right in Start() or Awake()

i will use this for activating music on all my scenes , while the button to switch it on and off is in the menu

Hope this is helpful :slight_smile:

If you are attempting to create a SceneManager Object with a SceneManager Script attached and this SceneManager Object is DontDestroyOnLoad, I suggest creating a New Empty Object with a New Script that will act as a ClickHandler.

The Click Handler will be in each Scene and is what you will attach to your Button. In the ClickHandler script you will want to create a field for the SceneManager, then in the Start() get/set the SceneManager instance. I named my SceneManager LevelManager instead and this is the code I used and attached to my ClickHandler which I attached to my button in the scene.

using UnityEngine;

public class ClickHandler : MonoBehaviour
{
    private LevelManager levelManager;
 
    void Start ()
    {
        levelManager = LevelManager.instance;
    }

#region ButtonCalls

    public void StartGame()
    {
        levelManager.StartSavedGame();
    }

    public void GoToNextLevel ()
    {
        levelManager.StartNextLevel();
    }

    public void RetryLevel()
    {
        levelManager.RetryLevel();
    }

#endregion
}

I also have a LevelManager empty object in each scene and it is DontDestroyOnLoad. This is the block of code inside the LevelManager Script attached to the LevelManager Object for DontDestroyOnLoad.

void Awake()
    {
        if (instance != null)
        {
            Destroy(gameObject);
        }
        else
        {
            instance = this;
            GameObject.DontDestroyOnLoad(gameObject);
        }
    }

Who knows better than this, eveyone knows things is trying to confuse people…suuuuuper…