Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
8
Question by Atlas · Nov 08, 2010 at 05:26 PM · levelname

How to get names of all available levels

I know that with Application.loadedLevelName I can get the name of the current level. But how do I get the names of all available levels? My interest in doing this is to create a level-select menu that lists all levels by name.

Comment
Add comment · Show 1
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image PsionicTr · Nov 26, 2012 at 10:13 AM 0
Share

Where do you exactly attach that script ?

12 Replies

· Add your reply
  • Sort: 
avatar image
6
Best Answer

Answer by Eric5h5 · Nov 08, 2010 at 06:38 PM

I think you'd have to do that manually, since there are no functions that return all level names.

Comment
Add comment · Show 7 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image numberkruncher · Apr 29, 2012 at 02:23 AM 1
Share

That's a shame, it would be useful to enumerate available level names.

avatar image Bunny83 · Apr 29, 2012 at 03:11 AM 1
Share

@kruncher: Yes it would be useful ;) I'm pretty sure they implement it the other day, but it's just a $$anonymous$$or issue. Until then you could use the script i've just written.

avatar image cecarlsen · Oct 30, 2012 at 08:58 PM 0
Share

Unity crew, oh please implement a runtime method to get the names of the available scenes.

avatar image PsionicTr · Nov 26, 2012 at 10:12 AM 0
Share

where do you attach that script ?

avatar image y0ux · Feb 01, 2013 at 06:17 PM 0
Share

What about, you put all your scenes in one folder and using .Net framework IO functions read the content in that folder and listed as available levels.

Other idea would be the use assets files or X$$anonymous$$L with the description (text and image), location and configuration on each level, parse the info and display it.

But is mandatory you add all the scenes at the building configuration.

Show more comments
avatar image
36

Answer by Bunny83 · Apr 29, 2012 at 03:09 AM

I've just written a little helper that makes it easier to get the names "manually".

 using UnityEngine;
 using System.Collections;
 using System.Collections.Generic;
 
 public class ReadSceneNames : MonoBehaviour
 {
     public string[] scenes;
     #if UNITY_EDITOR
     private static string[] ReadNames()
     {
         List<string> temp = new List<string>();
         foreach (UnityEditor.EditorBuildSettingsScene S in UnityEditor.EditorBuildSettings.scenes)
         {
             if (S.enabled)
             {
                 string name = S.path.Substring(S.path.LastIndexOf('/')+1);
                 name = name.Substring(0,name.Length-6);
                 temp.Add(name);
             }
         }
         return temp.ToArray();
     }
     [UnityEditor.MenuItem("CONTEXT/ReadSceneNames/Update Scene Names")]
     private static void UpdateNames(UnityEditor.MenuCommand command)
     {
         ReadSceneNames context = (ReadSceneNames)command.context;
         context.scenes = ReadNames();
     }
     
     private void Reset()
     {
         scenes = ReadNames();
     }
     #endif
 }

You just have to setup your build settings and add all scenes you want to include and then just press the "Update Scene Names" button. This will store the current active scene names in the public array of the script.

GetSceneNames

Comment
Add comment · Show 7 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image PsionicTr · Nov 26, 2012 at 10:12 AM 0
Share

Where exactly do you attach that script ?

avatar image Bunny83 · Nov 26, 2012 at 10:52 AM 0
Share

It doesn't matter where you attach it. Just attach it on an object in the scene. When you want to use the level names you can easily read the scenes array of that script by referencing this script instance in your script.

$$anonymous$$eep in $$anonymous$$d to press the Update Scene Names before you create a build / run the game.

You could also make the scenes array static so it can accessed more easily from other scripts.

avatar image PsionicTr · Nov 26, 2012 at 11:45 AM 0
Share

Well I though so also so I just attached it to one of the game objects but when I press update the array remains empty. Any ideas ?

avatar image PsionicTr · Nov 26, 2012 at 11:47 AM 0
Share

I currently have 2 scenes in my assets folder though when I press the UpdateScene Names it does not update the array it still remains 0

avatar image Bunny83 · Nov 26, 2012 at 10:41 PM 0
Share

@psionictr:

You have to add the scenes to your build array first. Only the scenes which are "ticked" in the build list are even included in your game. Just Press "File --> Build Settings" and drag and drop the scenes which should be part of your game into the "Scenes in build" list.

Show more comments
avatar image
5

Answer by Beijerinc · Oct 20, 2013 at 01:44 PM

I've written a solution, inspired by the lack of viable answer in this thread. Feel free to use it:

 using System;
 using System.Collections.Generic;
 using System.IO;
 using UnityEngine;
 using Debug = UnityEngine.Debug;
 
 namespace Assets.Scenes.Scripts
 {
     /// <summary>
     /// A context that is always available in the game. It provides global game features and information.
     /// </summary>
     public static class Game
     {
         #region Properties
         /// <summary>
         /// The folder the levels file is located when the game is hosted in the editor.
         /// </summary>
         private const string EDITOR_LEVELS_FILE_DIRECTORY = "Assets/Scenes/";
         /// <summary>
         /// The folder the levels file is located when the game has been deployed.
         /// </summary>
         private const string BUILD_LEVELS_FILE_DIRECTORY = "";
         /// <summary>
         /// The filename and extension of the file that contains the available levels.
         /// </summary>
         private const string LEVEL_FILE_NAME = "Levels.ini";
 
         /// <summary>
         /// The name of the world object. The world object and all of it's children are notified of game events.
         /// </summary>
         private const string WORLD_OBJECT = "World";
         /// <summary>
         /// The name of the game paused event.
         /// </summary>
         private const string ON_GAME_PAUSED_EVENT = "OnGamePaused";
         /// <summary>
         /// The name of the game resumed event.
         /// </summary>
         private const string ON_GAME_RESUMED_EVENT = "OnGameResumed";
 
         /// <summary>
         /// Indicates if the levels file has been updated this run. If so, it is not updated again. This only applies to the game when it is hosted
         /// in the editor.
         /// </summary>
         private static bool _hasUpdatedLevelsFile;
         /// <summary>
         /// The names of all levels in the game.
         /// </summary>
         private static string[] _levels;
 
         /// <summary>
         /// The previous Time.timeScale. This value is used to resume the game at the same pace it was paused at.
         /// </summary>
         private static float _previousTimeScale;
         /// <summary>
         /// Indicates if the game is currently paused.
         /// </summary>
         private static bool _isGamePaused;
 
         /// <summary>
         /// Gets the names of all levels in the game.
         /// </summary>
         public static string[] Levels
         {
             get
             {
                 if (_levels == null)
                 {
                     string directory;
 
                     // The directory depends on the environment. In the editor, relative paths can be used.
                     if (Application.isEditor)
                     {
                         directory = EDITOR_LEVELS_FILE_DIRECTORY;
                     }
                     else
                     {
                         string dataPath = Application.dataPath;
 
                         Debug.Log( string.Format("Data path detected at '{0}'.", dataPath) );
 
                         directory = Path.Combine(dataPath ?? string.Empty, BUILD_LEVELS_FILE_DIRECTORY);
                     }
 
                     _levels = ReadLevelsFile(directory);
 
                     Debug.Log( string.Format( "Discovered level names: {0}.", string.Join( ", ", _levels ) ) );
                 }
 
                 return _levels;
             }
         }
 
         /// <summary>
         /// Gets a value that indicates if the game is currently paused.
         /// </summary>
         public static bool IsGamePaused
         {
             get { return _isGamePaused; }
         }
         #endregion
 
         #region Constructors & Destructors
         /// <summary>
         /// Initializes the Game.
         /// </summary>
         static Game()
         {
             // Get an initial previous time scale so that we won't accidentally resume with a scale of 0.
             _previousTimeScale = Time.timeScale;
         }
         #endregion
 
         #region Game Management
         /// <summary>
         /// Pauses the game. The game paused event is fired for all game objects in the world object.
         /// </summary>
         public static void Pause()
         {
             Debug.Log("Game pausing.");
 
             // Pause the game and indicate that the game is actually paused.
             _previousTimeScale = Time.timeScale;
             Time.timeScale = 0.0f;
             _isGamePaused = true;
 
             // Give every game object in the world the chance to react to the game pausing.
             foreach (GameObject @object in GameObject.FindGameObjectsWithTag(WORLD_OBJECT))
             {
                 @object.BroadcastMessage(ON_GAME_PAUSED_EVENT, SendMessageOptions.DontRequireReceiver);
             }
 
             Debug.Log(String.Format("Game paused on Time.TimeScale = {0}.", Time.timeScale));
         }
 
         /// <summary>
         /// Resumes the game. The game resumed event is fired for all game objects in the world object.
         /// </summary>
         public static void Resume()
         {
             Debug.Log( "Game resuming." );
 
             // Indicate that the game is unpaused. Should anyone check this value, it would be in the game resume event, which is called just before the game is
             // actually resumed.
             _isGamePaused = false;
 
             // Give every game object in the world the chance to react to the game pausing.
             foreach (GameObject @object in GameObject.FindGameObjectsWithTag(WORLD_OBJECT))
             {
                 @object.BroadcastMessage(ON_GAME_RESUMED_EVENT, SendMessageOptions.DontRequireReceiver);
             }
 
             // Unpause the game.
             Time.timeScale = _previousTimeScale;
 
             Debug.Log(String.Format("Game resumed on Time.TimeScale = {0}.", Time.timeScale));
         }
         #endregion
 
         #region Level Management
 #if UNITY_EDITOR
         /// <summary>
         /// This method is called when post-processing a build, which occurs after a build has been made. This method updates the levels file in the build directory.
         /// </summary>
         /// <param name="target"></param>
         /// <param name="pathToBuiltProject"></param>
         [UnityEditor.Callbacks.PostProcessBuild]
         public static void PostProcessBuild(UnityEditor.BuildTarget target, string pathToBuiltProject)
         {
             const string DATA_FOLDER = "{0}_Data";
 
             Debug.Log(string.Format("Post-processing build '{0}' at '{1}'.", target, pathToBuiltProject));
 
             // The file name is integrated in some folder/file names of the built game. It may be needed to create references to these dynamic folders/files.
             string fileName = Path.GetFileNameWithoutExtension( pathToBuiltProject );
             // The build directory is the build path, without file name and extension and appended with the custom path.
             string buildDirectory = Path.Combine( Path.Combine( Path.GetDirectoryName( pathToBuiltProject ) ?? string.Empty,
                                                                 string.Format( DATA_FOLDER, fileName ) ),
                                                   BUILD_LEVELS_FILE_DIRECTORY );
 
             Debug.Log(string.Format("Detected levels file directory '{0}'.", buildDirectory));
 
             WriteLevelsFile(buildDirectory);
 
             Debug.Log("Post-processed build.");
         }
 
         /// <summary>
         /// This method is called when post-processing a scene, which occurs in either the editor when running a scene or at build time when building a scene. This
         /// method updates the levels file, if applicable.
         /// </summary>
         [UnityEditor.Callbacks.PostProcessScene]
         public static void PostProcessScene()
         {
             Debug.Log( "Post-processing scene." );
 
             if ( !_hasUpdatedLevelsFile )
             {
                 // Only write a levels file if we're in the editor. If not, the PostProcessBuild method will do this, because the PostProcessScene is called for all scenes.
                 if ( Application.isEditor )
                 {
                     Debug.Log( string.Format( "Detected editor, writing levels file to '{0}'.", EDITOR_LEVELS_FILE_DIRECTORY ) );
 
                     WriteLevelsFile( EDITOR_LEVELS_FILE_DIRECTORY );
                     _hasUpdatedLevelsFile = true;
                 }
             }
             else
             {
                 Debug.Log( "Already updated levels file." );
             }
 
             Debug.Log( "Post-processed scene." );
         }
 
         /// <summary>
         /// Writes or creates the levels file by collecting all levels configured in the build and (re-)writing the levels file at the provided directory.
         /// </summary>
         /// <param name="directory">The directory to write the levels file to.</param>
         private static void WriteLevelsFile(string directory)
         {
             List<string> levelNames = new List<string>();
 
             // Collect the names of all levels in the build settings.
             foreach (UnityEditor.EditorBuildSettingsScene buildSettingsScene in UnityEditor.EditorBuildSettings.scenes)
             {
                 if (buildSettingsScene.enabled)
                 {
                     string name = buildSettingsScene.path.Substring(buildSettingsScene.path.LastIndexOf(Path.AltDirectorySeparatorChar) + 1);
                     name = name.Substring(0, name.Length - 6);
 
                     levelNames.Add( name );
 
                     Debug.Log(string.Format("Detected level at '{0}' with name '{1}'.", buildSettingsScene.path, name));
                 }
             }
 
             string path = Path.Combine(directory, LEVEL_FILE_NAME);
 
             Debug.Log( string.Format("Writing levels file to '{0}'.", path) );
 
             // Write the names of all levels to a file, so that it can be retrieved when running.
             using (FileStream stream = File.Open(path, FileMode.Create, FileAccess.Write))
             {
                 using (StreamWriter writer = new StreamWriter(stream))
                 {
                     foreach (string levelName in levelNames)
                     {
                         writer.WriteLine( levelName );
                     }
                 }
             }
         }
 #endif
 
         /// <summary>
         /// Reads the levels file from the provided directory.
         /// </summary>
         /// <param name="directory">The directory that contains the levels file.</param>
         /// <returns>The discovered levels.</returns>
         private static string[] ReadLevelsFile(string directory)
         {
             string path = Path.Combine(directory, LEVEL_FILE_NAME);
 
             Debug.Log(string.Format("Reading levels file from '{0}'.", path));
 
             List<string> levelNames = new List<string>();
 
             if (File.Exists(path))
             {
                 // Read the names of all levels from the levels file.
                 using (FileStream stream = File.Open(path, FileMode.Open, FileAccess.Read))
                 {
                     using (StreamReader reader = new StreamReader(stream))
                     {
                         // Possibly use ReadToEnd and string.Split(fileContent, Environment.NewLine).
                         while (!reader.EndOfStream)
                         {
                             levelNames.Add(reader.ReadLine());
                         }
                     }
                 }
             }
             else
             {
                 Debug.LogWarning("Levels file does not exist, no level names available at run-time.");
             }
 
             return levelNames.ToArray();
         }
         #endregion
     }
 }

The game pausing logic has nothing to do with it, but it fills in another hole in Unity.

Comment
Add comment · Show 10 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image hephaestus_sc2 · Oct 25, 2013 at 03:18 AM 0
Share

Excuse me for bneing naive, but how do you actually go about using this script in unity? Is it attached to a gameobject... or?

avatar image cecarlsen · Oct 25, 2013 at 07:39 AM 0
Share

[UnityEditor.Callbacks.PostProcessScene] nice trick!

avatar image Beijerinc · Oct 25, 2013 at 07:43 AM 0
Share

Simply make sure Unity knows about this class by including it in your Unity C# project. It's a static class, so it cannot/should not be attached to a GameObject. It is always available to all other scripts in Unity. Also, you may want to change the paths at the top of the file to suit your situation. By default it outputs the levels file to /Assets/Scenes/Levels.ini while in the Unity editor, and the /{gamename}_Data/Levels.ini when you create a build.

avatar image fjalla · Dec 21, 2013 at 05:29 PM 0
Share

wow. looks like it does the job. thanks! but how do you use it? I mean read the level names. read the .ini file?

avatar image Beijerinc · Dec 21, 2013 at 09:47 PM 0
Share

Just use the public static string[] Levels property (Game.Levels) and it will automatically load the levels file if it has not already done so.

Show more comments
avatar image
3

Answer by dishmop · Feb 12, 2016 at 01:52 PM

Hi,

I've made some mods to Bunny83's solution so that it works with non-editor builds on mac and pc and also on web player (should also work on mobile builds, but haven't tested that).

Usage instructions are in the comments at the top of the file (though feel free to comment if anything is unclear).

 // This is a modification of a file posted by "Bunny83" - available here:
 // http://answers.unity3d.com/questions/33263/how-to-get-names-of-all-available-levels.html
 // 
 // However, this version works even in non editor builds (but you must have run it in the editor at some point first). 
 // 
 // Usage
 // ------
 // Place this component in one game object somewhere in your scene.
 // When it starts up in the editor, it will fill the "scenes" array with the names of all your scenes in the build settings
 // it will also save them as a binary file in your Resources folder in assets
 //
 // When you start this up in non editor mode it will load in the file from your resources folder (this uses the resource managemnet system
 // Rather than the raw file IO so should also work on web player builds).., and fills the scene array that way
 //
 // You can force these functions to be called from the editor by right clicking the component in the inspector
 //
 // To access the filenames from anywhere in your code, use somethign like
 // string sceneName = ReadSceneNames.singleton.scenes[2];
 
 
 
 using UnityEngine;
 using System.Collections;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.IO;
 
 
 public class ReadSceneNames : MonoBehaviour
 {
     public static ReadSceneNames singleton = null;
     public string sceneFilename = "LevelNames";
     public string[] scenes;
     
     
 #if UNITY_EDITOR
 
     void Start(){
         Reset ();
     }
 
 #else
 
     void Start(){
         LoadLevelNames();
     }
     
 #endif
 
     void Awake(){
         if (singleton != null) Debug.LogError ("Error assigning singleton - Have you got two components of this type in the scene?");
         singleton = this;
     }
     
     void OnDestroy(){
         singleton = null;
     }    
 
     
     string BuildLoadFilename(){
         return "LevelNames/" + sceneFilename;
     }
     
     
     void LoadLevelNames(){
         TextAsset levelNamesAsset = Resources.Load(BuildLoadFilename()) as TextAsset;
         if (levelNamesAsset != null){
             Stream s = new MemoryStream(levelNamesAsset.bytes);
             BinaryReader br = new BinaryReader(s);
             int numLevels = br.ReadInt32();
             if (numLevels > 0){
                 scenes = new string[numLevels];
                 for (int i = 0; i < numLevels; ++i){
                     scenes[i] = br.ReadString();
                 }
             }
         }
     }
         
     
 #if UNITY_EDITOR    
     private static string[] ReadNames()
     {
         List<string> temp = new List<string>();
         foreach (UnityEditor.EditorBuildSettingsScene S in UnityEditor.EditorBuildSettings.scenes)
         {
             if (S.enabled)
             {
                 string name = S.path.Substring(S.path.LastIndexOf('/')+1);
                 name = name.Substring(0,name.Length-6);
                 temp.Add(name);
             }
         }
         return temp.ToArray();
     }
     
     [UnityEditor.MenuItem("CONTEXT/ReadSceneNames/Update Scene Names")]
     private static void UpdateNames(UnityEditor.MenuCommand command)
     {
         ReadSceneNames context = (ReadSceneNames)command.context;
         context.scenes = ReadNames();
         context.SaveNameFile();
         
     }
     
     [UnityEditor.MenuItem("CONTEXT/ReadSceneNames/Force Reload")]
     private static void ForceReload(UnityEditor.MenuCommand command)
     {
         ReadSceneNames context = (ReadSceneNames)command.context;
         context.LoadLevelNames();
         
     }
     
     
     private void Reset()
     {
         scenes = ReadNames();
         SaveNameFile();
     }
 
     void CreateResourceDirs(){
         if (!System.IO.Directory.Exists(Application.dataPath + "/Resources")){
             System.IO.Directory.CreateDirectory(Application.dataPath + "/Resources");
         }
         if (!System.IO.Directory.Exists(Application.dataPath + "/Resources/LevelNames")){
             System.IO.Directory.CreateDirectory(Application.dataPath + "/Resources/LevelNames");
         }
     }
     
     string BuildSaveFilename(){
         return Application.dataPath + "/Resources/LevelNames/" + sceneFilename + ".bytes";
     }
         
     void SaveNameFile(){
         CreateResourceDirs();
         Debug.Log ("Saving level names..." + BuildSaveFilename());
         
         FileStream file = File.Create(BuildSaveFilename());
         BinaryWriter bw = new BinaryWriter(file);
         
         bw.Write(scenes.Count ());
         for (int i = 0; i < scenes.Count(); ++i){
             bw.Write(scenes[i]);
         }
         
         bw.Close();
         file.Close();
         
         // Ensure the assets are all realoaded and the cache cleared.
         UnityEditor.AssetDatabase.Refresh();
     }
     
     
     #endif
 }


Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image baroquedub · Mar 18, 2016 at 12:02 AM 0
Share

Really awesome. Thanks for making this such an easy solution to implement. Deserves to be voted best answer!

avatar image
1

Answer by tarahugger · Aug 21, 2014 at 06:37 AM

I put something together for my purposes based on Beijerinc's code. For those of you using Full Inspector 2.4+ - this creates/updates a ScriptableObject rather than a txt file. You can attach your own properties to a level, and changes made in play or edit mode are persisted. Its not pretty but might be useful for ideas.

Looks like this in inspector

alt text

GameEvents.cs


 using UnityEditor;
 using UnityEngine;
 using Debug = UnityEngine.Debug;
 
 [InitializeOnLoad]
 public static class GameEvents
 {
     private static bool _isInPlayMode;
     private static bool _isInEditMode;
     private static bool _preloadStarted;
 
     static GameEvents()
     {
         EditorApplication.playmodeStateChanged += PlaymodeStateChanged;
     }
 
     public delegate void PlayModeStateDelegate();
     public static event PlayModeStateDelegate OnStartPlay;
     public static event PlayModeStateDelegate OnEndPlay;
     public static event PlayModeStateDelegate OnStartEdit;
     public static event PlayModeStateDelegate OnEndEdit;
 
     private static void PlaymodeStateChanged()
     {
         if (Application.isEditor && !Application.isPlaying && !_isInPlayMode)
         {
             if (_isInEditMode)
             {
                 _preloadStarted = true;
                 _isInEditMode = false;
 
                 //Debug.Log("Entered Edit Mode");
 
                 if (OnStartEdit != null)
                     OnStartEdit.Invoke();
             }
             else
             {
                 //Debug.Log("Exit Edit Mode");
 
                 if (OnEndEdit != null)
                     OnEndEdit.Invoke();
             }
         }
 
         if (Application.isEditor && _isInPlayMode)
         {
             _isInPlayMode = false;
             _isInEditMode = true;
 
             //Debug.Log("Exited Play Mode");
 
             if (OnEndPlay != null)
                 OnEndPlay.Invoke();
         }
         else
         {
             if (!Application.isPlaying) return;
             if (!_isInPlayMode)
             {
                 //Debug.Log("Entered Play Mode");
 
                 if (OnStartPlay != null)
                     OnStartPlay.Invoke();
             }
             _isInPlayMode = true;
         }
     }
 }
 

SceneManager.cs


     using System.IO;
     using FullInspector;
     using UnityEditor;
     using UnityEngine;
     using System.Collections.Generic;
     using System.Linq;
     
     [InitializeOnLoad]
     public class SceneManager
     {
         private const string EDITOR_LEVELS_FILE_DIRECTORY = "Assets/_Scenes/";
         private const string BUILD_LEVELS_FILE_DIRECTORY = "";
         private const string LEVEL_FILE_NAME = "Scenes";
         private static string pathToAsset;
     
         private static SceneCollection cachedAsset;
         private static string serializedState;
         private static int hash;
         private static bool objectChanged;
     
         static SceneManager()
         {
             GameEvents.OnEndPlay += GameEventsOnOnEndPlay;
             GameEvents.OnStartPlay += GameEventsOnOnStartPlay;
             GameEvents.OnStartEdit += GameEventsOnOnStartEdit;
         }
     
         private static void GameEventsOnOnStartEdit()
         {
             if (objectChanged)
             {
                 Debug.Log("Loading State..");
                 cachedAsset.RestoreState();
             }
         }
     
         private static void GameEventsOnOnStartPlay()
         {
             //Debug.Log("Caching..");
     
             var sceneNames = GetSceneNames();
             var asset = SceneCollectionAsset;
             asset.Refresh(sceneNames);
             asset.SaveState();
             cachedAsset = asset;
             serializedState = Serialize(asset.MyScenes2);
         }
     
         private static string Serialize(SceneHolder sceneHolder)
         {
             return SerializationHelpers.SerializeToContent<SceneHolder, JsonNetSerializer>(sceneHolder);
         }
     
         private static void GameEventsOnOnEndPlay()
         {
             if (Serialize(cachedAsset.MyScenes2) != serializedState)
             {
                 //Debug.Log("Object has changed, Saving State...");
     
                 cachedAsset.SaveState();
                 objectChanged = true;
             }
             else
             {
                 objectChanged = false;
             }
         }
     
         private static string PathToAsset
         {
             get
             {
                 return Path.Combine(EDITOR_LEVELS_FILE_DIRECTORY, LEVEL_FILE_NAME + ".asset");
             }
         }
     
         private static SceneCollection SceneCollectionAsset
         {
             get
             {
                 return AssetDatabase.LoadMainAssetAtPath(PathToAsset) as SceneCollection ??
                        ScriptableObjectCreator.CreateAsset<SceneCollection>(PathToAsset);
             }
         }
     
         private static List<string> GetSceneNames()
         {
             // Collect the names of all levels in the build settings.
             return (from buildSettingsScene in EditorBuildSettings.scenes
                     where buildSettingsScene.enabled
                     select buildSettingsScene.path.Substring(buildSettingsScene.path.LastIndexOf(Path.AltDirectorySeparatorChar) + 1)
                         into name
                         select name.Substring(0, name.Length - 6)).ToList();
         }
     
         public static class ScriptableObjectCreator
         {
             public static T CreateAsset<T>(string path) where T : ScriptableObject, new()
             {
                 var asset = ScriptableObject.CreateInstance<T>();
     
                 if (string.IsNullOrEmpty(path))
                 {
                     Debug.Log("No path provided");
                     return new T();
                 }
     
                 string assetPathAndName = AssetDatabase.GenerateUniqueAssetPath(path);
                 AssetDatabase.CreateAsset(asset, assetPathAndName);
                 AssetDatabase.SaveAssets();
     
                 return AssetDatabase.LoadMainAssetAtPath(path) as T;
             }
         }
     }
 

SceneObjects.cs


 using System;
 using System.Linq;
 using FullInspector;
 using System.Collections.Generic;
 using UnityEngine;
 
 [Serializable]
 public class Scene
 {
     public int BuildOrder;
     public string Name;
     public string Description;
     public ISceneProperties Properties;
 }
 
 public interface ISceneProperties
 {
 
 }
 
 [Serializable]
 public class MenuScene : ISceneProperties
 {
     public bool Enabled;
 }
 
 [Serializable]
 public class LevelScene : ISceneProperties
 {
     public bool Enabled;
     public string Description;
     //public Level LevelMarker;
 }
 
 [Serializable]
 public class SceneHolder
 {
     [SerializeField]
     public List<Scene> Scenes;
 }
 
 [Serializable]
 public class SceneCollection : BaseScriptableObject<JsonNetSerializer>
 {
     public void Refresh(List<string> sceneNames)
     {
         if (MyScenes2 == null)
             MyScenes2 = new SceneHolder();            
 
         if(MyScenes2.Scenes == null)
             MyScenes2.Scenes = new List<Scene>();
 
         sceneNames.ForEach((sceneName, index) =>
         {
             var scene = MyScenes2.Scenes.FirstOrDefault(s => s.Name == sceneName);
             if (scene != null)
             {
                 // Update
                 scene.BuildOrder = index;
             }
             else
             {
                 // Add
                 MyScenes2.Scenes.Add(new Scene()
                 {
                     Name = sceneName,
                     BuildOrder = index
                 });
             }
         });
 
         MyScenes2.Scenes = MyScenes2.Scenes.OrderBy(scene => scene.BuildOrder).ToList();
 
     }
 
     [SerializeField]
     public SceneHolder MyScenes2;
 
 }


I also use this extension.

 using System;
 using System.Collections.Generic;
 using UnityEngine;
 using System.Collections;
 
 public static class LinqExtensions {
 
     public static void ForEach<T>(this IEnumerable<T> ie, Action<T, int> action)
     {
         var i = 0;
         foreach (var e in ie) action(e, i++);
     }
 
 }



Comment
Add comment · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
  • 1
  • 2
  • 3
  • ›

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

29 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Character Loading Location 2 Answers

Anyway to save which seen the player was on, then load that scene back from another one at a different time? 2 Answers

Level selection from main menu? 4 Answers

Need help with a Main Menu 1 Answer

drag and drop menue system? 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges