When Application.LoadLevel() is called, should the remaining code within the method affect the old scene, or the scene loaded by the call

So to completely understand my question I’ll break it down into setup to paint the scene and then ask the question after.

Setup for the question

I have 2 scenes:

  • MainMenu
  • Level1

On the MainMenu scene I have a GameObject with a script attached “GameController” that has DontDestroyOnLoad set. I also have a “MenuController” script attached to a UI Canvas.

Here is the code for MenuController:

public class MenuController : MonoBehaviour
{
	public GameObject loadingImage;
	public Slider numPlayersSelector;
	public Text numPlayerDisplay;
	private GameController gc;

	public void startGame()
	{
		loadingImage.SetActive( true );
		gc = GameObject.FindWithTag( "GameController" ).GetComponent<GameController>();
		gc.setupGame( (int)numPlayersSelector.value, "Level1" );
	}
}

startGame() is triggered when the “Start” button is pressed on the MainMenu scene.

And the relevant code for GameController:

public class GameController : MonoBehaviour
{
	public void setupGame( int newNumPlayers, string mapName )
	{
		numPlayers = newNumPlayers;

		Application.LoadLevel( mapName );

		Vector3 spawnPos = new Vector3( 3, 0, 0 );
		for( int i = 1; i <= numPlayers; i++ )
		{
			GameObject newPlayerShip = (GameObject)Instantiate( testShipPrefab , spawnPos, Quaternion.identity );
			spawnPos.x += 2;
		}
	}
}

Question

When the “Start” button is pressed, triggering the call to MenuController::startGame() which then triggers a call to GameController::setupGame(), should the code that occurs after the Application.LoadLevel( mapName ) (In this case, the player ship Instantiate calls) occur on the previous MainMenu scene, or the Level1 scene?

I’m noticing that the Instantiate call is instantiating the prefabs onto the MainMenu scene, as opposed to the Level1 scene even though the Application.LoadLevel call was before the Instantiate call, so by my logic the Instantiated objects should’ve been added to Level1.

My theory is that any method called in a particular scene (In this case the MainMenu scene) will perform all its operations on the MainMenu scene, even if you call Application.LoadLevel at some point during the scene. Once the method call ends, the new scene will be loaded and all new method calls will take affect on that scene.

Can anyone confirm or deny this either way? I see that you can work around this with OnLevelLoaded calls, so I could just move my instantiate code out into that and end the method call at Application.LoadLevel(), but I just want to make sure this isn’t a bug.

I can’t find documentation about when is the level actually loaded, but I’m pretty sure it’s not at the exact moment you call Application.LoadLevel. When loading a new scene with LoadLevel all game objects on the current scene are destroyed, so if LoadLevel loads the new scene before the next line of code, the script itself won’t exists (since the game object that owns the script should have been deleted by then).

Unity probably waits until the end of the current frame to avoid this problems.

I guess something similar is done for game objects that are not destroyed or when using other LoadLevel methods.

Anyway, if you want something to happen in one scene, do it in that scene. If you need something from the previous scene there are ways to do it:

  • You can store data in PlayerPrefs and it will be available on the next scene
  • You can set an object to not be destroyed when loading a new scene, and store the data in some script.

But note that those are ways to send data between scenes, not code.