- Home /
Retrieve list of available scenes from within compiled game
Hi,
Unity offers the ability to select scenes to build in the build settings, these scenes are also assigned an integer in the order they where added. This way you can load scenes by using:
Application.LoadLevel ("0");
or by using the name i.e.:
Application.LoadLevel ("scenename");
Now I'm trying to create a minigame launcher. All minigames are stored in a directory 'Minigames', the minigames have their own scene. They are build together with the launcher by enabling the scenes in the build settings.
I would like to retrieve a list of all the other scenes that have been build on runtime so I can display a list of all available minigames (scenes) to launch.
I've searched other topics but most of them recommend using the class EditorApplication, since I want to access this information on runtime it won't be possible to use that class.
Does anyone have an idea how to do this?
Answer by Flightkick · Jun 20, 2015 at 01:25 PM
Okay so I've finally found a way to do this.
First I use the [PostProcessScene] attribute somewhere in a static method, I use a bool to ensure the logic will only be executed once. This piece of code is also surrounded by conditional tags i.e.
#if UNITY_EDITOR
Now in this method I scan my Minigame directory for subdirectories (each subdirectory contains a minigame), then I try to find a json file containing the relative path to the .untiy scene. All minigames need to specify their main scene in this json file, this is because I only want to know the main scenes of the minigame, you don’t have to do this if you want information for all scenes. I combine the .unity relative path with the directory I'm scanning in so I have the absolute path to the unity project defined in the json configuration file
Then use the EditorBuildSettings class to retrieve the scene id's and paths, I loop through them and check if the paths equal the paths retrieved from the json files and if the scenes are enabled in the buildsettings. If they match up I've got a correctly configured minigame.
I've created an object which holds all information about the minigame (name, scene id, path to scene, etc.), a collection of these objects will be serialized to the resources folder as a json file (but with a .txt extension). Since this happens when the first scene is being post-processed this means the json file written to the resources folder will also be included when the build starts.
When the game actually starts I only have to load the json file from the resources as a TextAsset (this is why it’s given a .txt extension). Then I deserialize the file back into a list containing the minigame information. So now I do have a list of the compiled scenes (filtered to only main scenes). Now I can access all scene information by my minigame information class.
Answer by Arcanor · Jun 20, 2015 at 03:32 PM
You could also do something like this, if you don't want to keep track of things prior to making your build.
using UnityEngine;
using System.IO;
...
string folderName = Application.dataPath + "/Scenes";
var dirInfo = new DirectoryInfo(folderName);
var allFileInfos = dirInfo.GetFiles("*.unity", SearchOption.AllDirectories);
foreach (var fileInfo in allFileInfos)
{
Debug.Log("Found a scene file: " + @fileInfo.FullName);
}
Given the question I asked initially yes that would be a nice way to approach this. However, as I was implementing this I also noticed that I had to keep track of the scenes prior to building the project. Therefor I am checking both the $$anonymous$$igame config json and the buildsettings (I forgot to mention the change in my requirement).
Thanks for your addition to my answer.
Answer by azad3h · May 03, 2017 at 12:34 PM
I had the same problem and ended up using a ScriptableObject to save the data using an Editor Script, following the instructions in this blog. I had to modify the solution in the blog also, as the contents of the instance of the ScriptableObject wouldn't save on the file system but only within the unity editor's cache. If you use this solution, make sure to modify the editor script as follows:
// First, try to load the list if already exists
// ... related code ...
// If doesn't exist, create it!
// ... related code ...
AssetDatabase.StartAssetEditing();
// Fill the array or whatever attribute of the ScriptableObject
AssetDatabase.StopAssetEditing();
// Writes all unsaved asset changes to disk
EditorUtility.SetDirty(list);
AssetDatabase.SaveAssets();
BTW, I tried the answer by @Arcanor too. It works within the unity editor but not in the deployed build (on Android). Is there some additional setting required for it to work in the deployed build? It would have been a cleaner solution if it worked.
Answer by aweFalafelApps · Oct 04, 2019 at 03:45 AM
Old I know, but it matched my search, so I'm posting my solution. This seems to be possible at runtime now using SceneUtility.GetScenePathByBuildIndex
What I did:
var sceneNames = new List<string>();
var regex = new Regex(@"([^/]*/)*([\w\d\-]*)\.unity");
for (int i = 0; i < SceneManager.sceneCountInBuildSettings; i++)
{
var path = SceneUtility.GetScenePathByBuildIndex(i);
var name = regex.Replace(path, "$2");
sceneNames.Add(name);
}
You can also use System.IO.Path.GetFileNameWithoutExtension instead of the regex.