This is related to the multiple scene development that I’ve described before. One of the problems I had was whenever I was working on a scene and had to test, I had to locate the Main scene, load it, then hit play. After testing, I have to load the scene that I was working on again. Sometimes I forget what scene that was. As you can imagine, this is really frustrating and can eat up time.

Fortunately with Unity, you can make scripts that can run in the editor. I made a script that loads the Main scene, and run it. When the game is stopped, the script loads the previous scene that I was working on. The script can be executed via a menu item or by pressing Alt + Shift + Z.

Here it is:

[InitializeOnLoad] public static class RunUtils { static RunUtils() { EditorApplication.playmodeStateChanged += LoadLastOpenedScene; } // pref IDs private const string LAST_OPENED_SCENE = "Game.LastOpenedScene"; private const string PLAYED_USING_RUN_UTILS = "Game.PlayedUsingRunUtils"; // bool states private static bool aboutToRun = false; [MenuItem("Game/Run Game #&z")] public static void Run() { SceneSetup[] setups = EditorSceneManager.GetSceneManagerSetup(); if (setups.Length > 0) { EditorPrefs.SetString(LAST_OPENED_SCENE, setups[0].path); } EditorPrefs.SetBool(PLAYED_USING_RUN_UTILS, true); aboutToRun = true; // Refresh first to cause compilation and include new assets AssetDatabase.Refresh(); EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo(); EditorSceneManager.OpenScene("Assets/Game/Scenes/Main.unity"); EditorApplication.isPlaying = true; } private static void LoadLastOpenedScene() { if (EditorApplication.isPlaying || EditorApplication.isCompiling) { // changed to playing or compiling // no need to do anything return; } if (!EditorPrefs.GetBool(PLAYED_USING_RUN_UTILS)) { // this means that normal play mode might have been used return; } // We added this check because this method is still invoked while EditorApplication.isPlaying is false // We only load the last opened scene when the aboutToRun flag is "consumed" if (aboutToRun) { aboutToRun = false; return; } // at this point, the scene has stopped playing // so we load the last opened scene string lastScene = EditorPrefs.GetString(LAST_OPENED_SCENE); if (!string.IsNullOrEmpty(lastScene)) { EditorSceneManager.OpenScene(lastScene); } EditorPrefs.SetBool(PLAYED_USING_RUN_UTILS, false); // reset flag } }

This is a fun little script. The key here is to register a delegate to the event EditorApplication.playmodeStateChanged which is called whenever the editor’s play state is changed (play, paused, or stopped). By using EditorPrefs, we can save some variables like LAST_OPENED_SCENE and PLAYED_USING_RUN_UTILS which we can access whenever the delegate is invoked. I used EditorPrefs rather than normal variables because I can’t guarantee how the editor keeps variables. I’m not sure if the values of variables are still around like say after recompilation.

Note also here that I call AssetDatabase.Refresh() before running the scene. This is because I prefer to turn off auto refresh (you can do this in Preferences). It’s annoying when the editor keeps compiling when your game is already too big. But without calling AssetDatabase.Refresh(), I might also forget to refresh the editor before running the game. By doing it this way, I ensure recompilation whenever I run the game and there was updated code.

Enjoy!