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.
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.
I think you'd have to do that manually, since there are no functions that return all level names.
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.
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 *= 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*);_
_ }*_
* bw.Close();*
* file.Close();*
* // Ensure the assets are all realoaded and the cache cleared.*
* UnityEditor.AssetDatabase.Refresh();*
* }*
* #endif*
}
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
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++);
}
}
It seems EditorBuildSettings has vanished from the API in the latest versions (at least I can’t find it and I get errors when trying to access it). This will give you a list of all the scenes in the Assets/Scenes folder:
using System.IO;
string[] paths = Directory.GetFiles("Assets/Scenes", "*.unity", SearchOption.AllDirectories);
Unity has a way to do this now, but it’s not immediately obvious because half of what you need is in SceneManager and the other half is in SceneUtility.
public void PrintSceneNames()
{
for (int i = 0; i < SceneManager.sceneCountInBuildSettings; i++)
{
var path = SceneUtility.GetScenePathByBuildIndex(i);
var sceneName = Path.GetFileNameWithoutExtension(path);
Debug.Log(sceneName);
}
}
not entirely related, but i wanted to get it for using a unity tool to quickly change scenes without navigating, so below is that script.
using UnityEditor;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class SceneTool : EditorWindow
{
private int m_iActiveScenesInBuild = 0;
private List<string> m_ListOfScenes;
private List<string> m_ListOfScenePaths;
[MenuItem("Tools/Scene Tool")]
private static void ShowWindow()
{
SceneTool tool = EditorWindow.GetWindow<SceneTool>();
tool.title = "Scene Tool";
}
private void OnGUI()
{
if (true == GUILayout.Button("Refresh"))
{
GatherSceneInfo();
}
EditorGUILayout.Space();
for(int i = 0; i < m_iActiveScenesInBuild; i++)
{
if (true == GUILayout.Button(m_ListOfScenes*))*
-
{*
-
EditorApplication.SaveScene(EditorApplication.currentScene);*
EditorApplication.OpenScene(m_ListOfScenePaths*);
_ }_
_ }_
_ }*_
* private void GatherSceneInfo()*
* {*
* #if UNITY_EDITOR*
* m_iActiveScenesInBuild = 0;
_ EditorBuildSettingsScene scenes = EditorBuildSettings.scenes;_
m_ListOfScenes = new List();
m_ListOfScenePaths = new List();
_ int iLevelCount = scenes.Length;_
_ for(int iLevels = 0; iLevels < iLevelCount; iLevels++)_
_ {_
_ EditorBuildSettingsScene scene = scenes[iLevels];_
_ if (true == scene.enabled)_
_ {_
_ string sPath = scene.path;_
m_ListOfScenePaths.Add(sPath);*
* string sName = scene.path.Substring(scene.path.LastIndexOf(‘/’)+1);*
* sName = sName.Substring(0, sName.Length-6);*
* m_ListOfScenes.Add(sName);
m_iActiveScenesInBuild++;
_ }_
_ }_
_ #endif*_
* }*
}
I’ve found a way to do this without having to run anything in the editor first, it is quite hacky but it works.
public class SceneData
{
public string Name { get; set; }
public int BuildIndex { get; set; }
}
public static class Statics
{
public static List<SceneData> AvailableScenes = new List<SceneData>();
}
void FindAvailableScenes()
{
if(Statics.AvailableScenes.Count > 0)
{
// Finding available scenes is a one-off operation
return;
}
var totalScenes = SceneManager.sceneCountInBuildSettings;
for(int i = 0; i < totalScenes; i++)
{
if(i == SceneManager.GetActiveScene().buildIndex)
{
// No need to load current scene again
continue;
}
var async = SceneManager.LoadSceneAsync(i, LoadSceneMode.Additive);
async.allowSceneActivation = false;
var scene = SceneManager.GetSceneAt(i);
var sceneData = new SceneData { Name = scene.name, BuildIndex = scene.buildIndex };
Statics.AvailableScenes.Add(sceneData);
}
}
I put this in the first scene that gets loaded in my build and then switch to a different scene once this has completed. It works because when you start loading a scene additive and asynchronously the name of the scene seems to become available before the rest of the scene has actually loaded.
[Based in the answer from Bunny83]
I suggest to put this in a file inside an Editor folder (only if you want to use it in just Editor mode).
Also, this is perfect candidate to a static class (or Singleton).
In fact, I didn’t needed the contextual menus and stuff, so I’ve reduced the code a bit. Perhaps it could be useful for some people as they could use it from anywhere:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public static class ReadSceneNames
{
public static List<string> GetAllSceneNames()
{
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;
}
}
It works fine except for when I try to publish my game. When I try to build my game, I get compiler errors that say…
The name ‘UnityEditor.EditorBuildSettingsScene’ does not denote a valid type (‘not found’). Did you mean ‘System.ComponentModel.EditorBrowsableAttribute’?
I come from the future. And I bring good news, you can use Application.levelCount to get the max numer of levels, so for example if you want to load random level you can do this:
using UnityEngine;
using System.Collections;
public class ExampleClass : MonoBehaviour {
void Example() {
Application.LoadLevel(Random.Range(0, Application.levelCount));
}
}
Example from here: Unity - Scripting API: Application.levelCount
If you need the exact filename you can use an editor script like this one instead:
foreach (EditorBuildSettingsScene scene in EditorBuildSettings.scenes) {
Debug.Log (scene.path);
}
Just remember to add the levels to the build settings (File > Build Settings)