21

Ok, so I'm working on a small project that has a main menu and 10 levels. From time to time I edit different levels, and want to try them out, however I get a NullPointerException as my levels rely on certain variables from the main menu for the levels to work, which means I have to alter my levels, then load my main menu and play from there.

Is there something that can be done in the Unity Editor to default load a specific scene when you hit Play, and not the scene you're on?

I could obviously resolve this to something like

public bool goToMenu; //set this to true in my levels through inspector

Start()
{
    if (goToMenu)
        //then load main menu
}

but it would be really handy if there was a way to set the default level to load when hitting play mode. I've had a look in Preferences but couldn't find anything.

Thanks!

Tom
  • 2,372
  • 4
  • 25
  • 45
  • 2
    You could take a look at this: http://wiki.unity3d.com/index.php/SceneAutoLoader. I've not used it myself, but it sounds like it may be of some help. – MotoSV Feb 23 '16 at 19:29
  • That is a incredibly outdated approach, do NOT do that. if you MUST tackle this issue, which you should not, just use the "script execution order" trick mentioned below. – Fattie Sep 30 '19 at 13:38
  • YES : EditorSceneManager.playModeStartScene – Alexis Pautrot Apr 25 '20 at 15:37

5 Answers5

27

I made this simple script that loads the scene at index 0 in the build settings when you push Play. I hope someone find it useful.

It detects when the play button is push and load the scene. Then, everything comes back to normal.

Oh! And it automatically executes itself after opening Unity and after compile scripts, so never mind about execute it. Simply put it on a Editor folder and it works.

#if UNITY_EDITOR
using UnityEditor;
using UnityEditor.SceneManagement;

[InitializeOnLoadAttribute]
public static class DefaultSceneLoader
{
    static DefaultSceneLoader(){
        EditorApplication.playModeStateChanged += LoadDefaultScene;
    }

    static void LoadDefaultScene(PlayModeStateChange state){
        if (state == PlayModeStateChange.ExitingEditMode) {
            EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo ();
        }

        if (state == PlayModeStateChange.EnteredPlayMode) {
            EditorSceneManager.LoadScene (0);
        }
    }
}
#endif
3Dynamite
  • 286
  • 3
  • 4
  • Automatic Editor plugin seems to be a proper way to do this. – Programmer Nov 18 '18 at 19:47
  • To make it more specific, this goes into Assets/Editor/something.cs. Because it is 'an Editor plugin'. – user18099 Sep 30 '19 at 20:20
  • 1
    For the future search engine user: This works out of the box in unity 2022.1.x. I did not have to put it into an Editor folder. – rolfrudolfwolf Jun 07 '22 at 20:14
  • This unfortunately still loads the scene you are on and then instantly changes to the first scene. The problem with this approach is that the scene that might be open will throw a lot of errors because it's not supposed to be the first loaded scene. – Dror Oct 04 '22 at 14:35
  • Still working on the 2022.3.2f1 version. Yes, it's first loading the current scene and shows tons of errors because -in most cases- it's not supposed to be the first loaded scene. But after loading the scene, all errors will disappear from the console. – MGY Jul 03 '23 at 13:38
16

The easiest way is to set your 0th scene as the default play mode scene:

[InitializeOnLoad]
public class EditorInit
{
    static EditorInit()
    {
        var pathOfFirstScene = EditorBuildSettings.scenes[0].path;
        var sceneAsset = AssetDatabase.LoadAssetAtPath<SceneAsset>(pathOfFirstScene);
        EditorSceneManager.playModeStartScene = sceneAsset;
        Debug.Log(pathOfFirstScene + " was set as default play mode scene");
    }
}
Z4urce
  • 438
  • 4
  • 14
0

This is the editor script that I wrote that do exactly what you want. https://github.com/CSaratakij/SceneSelector It has the UI to select a specific scene and option to open the first scene in the build setting when enter the playmode. Might be useful for the future visitor.

  • The accepted answer is solving the problem, not necessary to install something more in the project, imho. – MGY Jul 03 '23 at 13:45
0

i use this in Editor Folder:

using UnityEngine;
using UnityEditor;
using UnityEditor.SceneManagement;

[InitializeOnLoad]
public class DefaultSceneLoader : EditorWindow
{

    private const string defaultScenePath = "Assets/Scenes/Preload.unity";

    static DefaultSceneLoader()
    {
        EditorApplication.playModeStateChanged += LoadDefaultScene;
    }

    static void LoadDefaultScene(PlayModeStateChange state)
    {
        if (state == PlayModeStateChange.ExitingEditMode)
        {
            if (EditorSceneManager.GetActiveScene().path != defaultScenePath)
            {
               
                PlayerPrefs.SetString("dsl_lastPath", EditorSceneManager.GetActiveScene().path);
                PlayerPrefs.Save();

                EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo();

                EditorApplication.delayCall += () =>
                {
                    EditorSceneManager.OpenScene(defaultScenePath);
                    EditorApplication.isPlaying = true;
                };

                EditorApplication.isPlaying = false;
            }
        }

        if (state == PlayModeStateChange.EnteredEditMode)
        {
            if (PlayerPrefs.HasKey("dsl_lastPath"))
            {
                EditorSceneManager.OpenScene(PlayerPrefs.GetString("dsl_lastPath"));
            }
        }
    }
}
Ronny Bigler
  • 654
  • 6
  • 12
-1

This is a well-known basic issue in Unity.

There is no good solution unfortunately.

When you click "Play" in a game engine it should of course jump to your preload scene and "Play" from there.

Unfortunately in Unity this does not happen.

Every experienced Unity engineer recommends NOT trying to automate this. But if you must...

/* 
ONLY FOR USE DURING DEVELOPMENT IN THE EDITOR
ONLY FOR USE DURING DEVELOPMENT IN THE EDITOR
ONLY FOR USE DURING DEVELOPMENT IN THE EDITOR

MUST RUN FIRST USING "SCRIPT EXECUTION ORDER" system
MUST RUN FIRST USING "SCRIPT EXECUTION ORDER" system
MUST RUN FIRST USING "SCRIPT EXECUTION ORDER" system

YOU MUST REMOVE THIS SCRIPT BEFORE BUILDING TO PRODUCTION
YOU MUST REMOVE THIS SCRIPT BEFORE BUILDING TO PRODUCTION
YOU MUST REMOVE THIS SCRIPT BEFORE BUILDING TO PRODUCTION
*/

using UnityEngine;
public class DevPreload:MonoBehaviour {

    void Awake() {

        GameObject check = GameObject.Find("__app");
        // "__app" is one of your DDOL gameobject in preload scene
        if (check==null)
            SceneManagement.SceneManager.LoadScene("_preload");
        }
    
    }

The secret is to use

Unity's Script Execution Order system

Simply have that script run before anything and it will do what you want.

HOWEVER - be aware that the Script Execution Order system is an incredibly bad engineering idea which nobody ever uses because it's so flakey.

This "trick" is !!ONLY!! for use during development. Stay sober!

Community
  • 1
  • 1
Fattie
  • 27,874
  • 70
  • 431
  • 719
  • In fact, ignore that last comment - I've only just managed to get back on Unity since I asked this question, and I had a look at your link you included in your answer (I think you asked the same question - great minds think alike!) and I used the code that you included in your question from everyone's response - works like a charm! – Tom Feb 24 '16 at 20:38
  • Curious - is that code in your question from that link "safe"? Would there be any compile errors or build errors internally? – Tom Feb 24 '16 at 20:41
  • Noted, thanks! I'll mark this answer as correct as your code will work too :) – Tom Feb 24 '16 at 21:20
  • While I agree with the whole answer, I'd like to point out that "globals in programming" is not a bad thing when you know what you're doing. And in some practical cases, it is even more elegant to use them than avoiding them at all costs. But that's a bit off topic :) – Masadow Sep 30 '19 at 12:49
  • lol it's funny you mention that incidental issue, @Masadow . Indeed globals have an important role. I'm gonna remove my incidental example there. – Fattie Sep 30 '19 at 13:36