{"id":288,"date":"2016-05-09T09:08:06","date_gmt":"2016-05-09T07:08:06","guid":{"rendered":"http:\/\/davikingcode.com\/blog\/?p=288"},"modified":"2019-10-04T10:11:34","modified_gmt":"2019-10-04T08:11:34","slug":"retrieving-the-names-of-your-scenes-at-runtime-with-unity","status":"publish","type":"post","link":"https:\/\/davikingcode.com\/blog\/retrieving-the-names-of-your-scenes-at-runtime-with-unity\/","title":{"rendered":"Retrieving the names of your scenes at runtime with Unity"},"content":{"rendered":"<p><em>Edit: <a href=\"https:\/\/gist.github.com\/JohannesMP\/ec7d3f0bcf167dab3d0d3bb480e0e07b\">this script<\/a> is awesome, and if you combine it with a ScriptableObject you&#8217;re ready to go!<\/em><\/p>\n<p>Retrieving the names of your scenes at runtime with Unity is\u00a0a common problem. The API of Unity doesn&#8217;t provide an\u00a0easy way do to so. With the quite recent <a href=\"http:\/\/docs.unity3d.com\/ScriptReference\/SceneManagement.SceneManager.html\">SceneManager<\/a>, I thought Unity had finally provided something to get information about your scenes you have added in the <a href=\"http:\/\/docs.unity3d.com\/Manual\/BuildSettings.html\">Build Settings<\/a>. No way !<\/p>\n<p>I faced this problem when implementing a little configuration GUI, where the user has the possibility to indicate the order the scenes will be played. Yes, I could have\u00a0hard-coded this, but it&#8217;s not the\u00a0elegant way in my opinion. Thus, I made some investigations to get once for all the names of my scenes.<\/p>\n<p><!--more--><\/p>\n<h2>Editor Build Settings<\/h2>\n<p>First of all, I needed the names of my scenes, and the only place I found them was inside the\u00a0<code>Editor Build Settings<\/code> which is\u00a0<strong>not documented by Unity\u00a0<\/strong>. <em>Oh gosh, it starts badly.<\/em> This class provides a static property to get the\u00a0information about the\u00a0<strong>scenes available<\/strong>\u00a0<strong>in your Build Settings<\/strong> (enabled\u00a0<strong>AND<\/strong>\u00a0disabled).\u00a0Then, simply loop into the array and get the name of your scenes in the same order they have been added to the Build Settings !<\/p>\n<pre><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">EditorBuildSettingsScene[] scenes = EditorBuildSettings.scenes ;\nfor( int i = 0 ; i &amp;amp;amp;amp;lt; scenes.Length ; ++i)\n{\n     if( scenes[i].enabled )\n          Debug.Log(&amp;amp;amp;amp;amp;amp;nbsp;\"Scene #\" + i + \" : \" + scenes[i].path + \" is enabled\"&amp;amp;amp;amp;amp;amp;nbsp;);\n     else\n          Debug.LogWarning( \"Scene #\" + i + \" : \" + scenes[i].path + \" is not enabled\" );\n}<\/pre>\n<p>Oh, you thought you would\u00a0be able to copy-paste this code directly in your script ? I am sorry, it&#8217;s not that\u00a0easy, I\u00a0would not have written this post for only 6\u00a0lines of code ! \ud83d\ude09<\/p>\n<p>As you may have noticed, the class is called\u00a0<strong>Editor<\/strong>BuildSettingsScene, then, it belongs to\u00a0the\u00a0<code>UnityEditor<\/code> namespace, and, as you surely know, the classes in this namespace can&#8217;t be used in a standalone build.<\/p>\n<p>In the editor, we can easily display this list using the <a href=\"http:\/\/docs.unity3d.com\/ScriptReference\/MenuItem.html\">MenuItem<\/a>\u00a0attribute like this :<\/p>\n<pre><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">using UnityEngine;\nusing UnityEditor;\n\npublic class GetScenesNamesFromEditor\n{\n    [MenuItem( \"Scenes Names\/Save Scenes Names\" )]\n    private static void GetScenesNames()\n    {\n        EditorBuildSettingsScene[] scenes = EditorBuildSettings.scenes;\n        for ( int i = 0 ; i &amp;amp;amp;amp;lt; scenes.Length ; ++i )\n        {\n            if( scenes[i].enabled )\n                Debug.Log( \"Scene #\" + i + \" : \" + scenes[i].path + \" is enabled\" );\n            else\n               Debug.LogWarning( \"Scene #\" + i + \" : \" + scenes[i].path + \" is not enabled\" );\n        }\n    }\n}<\/pre>\n<p>Now, you will tell me &#8220;<em>That doesn&#8217;t solve the problem of retrieving the names of my scenes in my game, I can only call this function in my editor !<\/em>&#8221; , yes, indeed ! Since we can&#8217;t use\u00a0directly this function in our game, let&#8217;s use them indirectly !\u00a0How\u00a0? One word : <strong>Serialization<\/strong> !<\/p>\n<h2>Serializing a Scriptable Object<\/h2>\n<p>Let&#8217;s start by defining what is serialization \u00a0:<\/p>\n<blockquote><p>Serialization is the process of converting an object into a given format \u00a0in order to store this object\u00a0(into a file, inside a database, &#8230;)\u00a0or transmit it\u00a0across a network connection link. Its main purpose is to save the state of an object in order to be able to recreate it when needed, eventually\u00a0in another program context. The reverse process is called deserialization.<\/p><\/blockquote>\n<p style=\"text-align: right;\"><em>Source :<\/em> <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/mt656716.aspx\">MSDN<\/a> &amp; <a href=\"https:\/\/en.wikipedia.org\/wiki\/Serialization\">Wikipedia<\/a><\/p>\n<p style=\"text-align: left;\">You surely have guessed what I want to do here :<\/p>\n<ol>\n<li style=\"text-align: left;\">Save the names of my scenes from the\u00a0editor<\/li>\n<li style=\"text-align: left;\">Retrieve them at runtime<\/li>\n<\/ol>\n<p>There are so many ways to do this, how about using a database ? No, I am joking, here, around ten strings must be saved. I can\u00a0use a XML, JSON, YAML file or even a simple text file with one scene name per line, but I wanted to take a look at Unity&#8217;s scriptable objects.<\/p>\n<blockquote><p>ScriptableObject is a class that allows you to store large quantities of shared data independent from script instances.<\/p><\/blockquote>\n<p style=\"text-align: right;\">Source : <a href=\"http:\/\/docs.unity3d.com\/Manual\/class-ScriptableObject.html\">Unity Manual<\/a><\/p>\n<p>Most often, scriptable objects are used as assets which are only meant to store data. Nice, it&#8217;s our case here\u00a0!So let&#8217;s define our data structure, containing only a simple array of strings. Feel free to add another array if you want to know whether the scenes are\u00a0enabled or not.<\/p>\n<pre><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">using UnityEngine;\n\npublic class ScenesList : ScriptableObject\n{\n     public string[] scenesNames;\n}<\/pre>\n<p>Now, we will be able to create a new ScriptableObject using the\u00a0<a href=\"http:\/\/docs.unity3d.com\/ScriptReference\/ScriptableObject.CreateInstance.html\">ScriptableObject.CreateInstance<\/a>, the only way to instantiate such object (the <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/fa0ab757.aspx\">new operator<\/a>\u00a0doesn&#8217;t work). Then, we will fill the array of the scriptable object and store it in a place we will be able to retrieve it later to deserialize it.<\/p>\n<p>Scriptable object have been designed to be\u00a0easily serialized and deserialized\u00a0under the form of assets. Thus, we will use the static functions provided in the\u00a0<a href=\"http:\/\/docs.unity3d.com\/ScriptReference\/AssetDatabase.html\">AssetDatabase<\/a>\u00a0class.<\/p>\n<pre><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">[MenuItem( \"Scenes Names\/Save Scenes Names\" )]\n private static void SaveScenesNames()\n {\n     EditorBuildSettingsScene[] scenes = EditorBuildSettings.scenes;\n\n     \/\/ First, try to load the list if already exists\n     ScenesList list = (ScenesList) AssetDatabase.LoadAssetAtPath(\"Assets\/Resources\/ScenesList.asset\", typeof(ScenesList)) ;\n\n     \/\/ If doesn't exist, create it !\n     if( list == null )\n     {\n         list = ScriptableObject.CreateInstance&amp;amp;amp;amp;lt;ScenesList&amp;amp;amp;amp;gt;() ;\n         AssetDatabase.CreateAsset( list, \"Assets\/Resources\/ScenesList.asset\" );\n     }\n\n     \/\/ Fill the array\n     list.scenesNames = new string[scenes.Length];\n     for ( int i = 0 ; i &amp;amp;amp;amp;lt; scenes.Length ; ++i )\n     {\n         list.scenesNames[i] = scenes[i].path ;\n     }\n\n     \/\/ Writes all unsaved asset changes to disk\n     AssetDatabase.SaveAssets();\n }<\/pre>\n<p>If you want to only save the enabled scenes, use a temporary List (in the System.Collections.Generic\u00a0namespace)\u00a0:<\/p>\n<pre><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">[MenuItem( \"Scenes Names\/Save Scenes Names\" )]\n private static void SaveScenesNames()\n {\n     EditorBuildSettingsScene[] scenes = EditorBuildSettings.scenes;\n     List&amp;amp;amp;amp;lt;string&amp;amp;amp;amp;gt; scenesNames = new List&amp;amp;amp;amp;lt;string&amp;amp;amp;amp;gt;();\n     \/\/ First, try to load the list if already exists\n     ScenesList list = (ScenesList) AssetDatabase.LoadAssetAtPath(\"Assets\/Resources\/ScenesList.asset\", typeof(ScenesList)) ;\n\n     \/\/ If doesn't exist, create it !\n     if( list == null )\n     {\n         list = ScriptableObject.CreateInstance&amp;amp;amp;amp;lt;ScenesList&amp;amp;amp;amp;gt;() ;\n         AssetDatabase.CreateAsset( list, \"Assets\/Resources\/ScenesList.asset\" );\n     }\n\n     \/\/ Fill the array\n     for ( int i = 0 ; i &amp;amp;amp;amp;lt; scenes.Length ; ++i )\n     {\n         if( scenes[i].enabled )\n             scenesNames.Add( scenes[i].path );\n     }\n     asset.scenesNames = scenesNames.ToArray();\n     \/\/ Writes all unsaved asset changes to disk\n     AssetDatabase.SaveAssets();\n }<\/pre>\n<h2>Retrieving the names of the scenes<\/h2>\n<p>In the last script, I decided to store the list inside my Resources folder\u00a0to\u00a0easily retrieve it using a single line of code in any of my scripts :<\/p>\n<pre><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">ScenesList list&amp;amp;amp;amp;amp;amp;nbsp;= Resources.Load&amp;amp;amp;amp;amp;amp;lt;ScenesList&amp;amp;amp;amp;amp;amp;gt;( \"ScenesList\" );<\/pre>\n<p>However, you could have stored the asset in an other folder, then, declared a public\u00a0ScenesList in the script needing the list of scenes&#8217; names, and dragged &amp; dropped the created asset in the inspector.<\/p>\n<pre><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">public class RetrieveScenesNames : MonoBehaviour\n{\n    public ScenesList list ;\n\n    private void Start()\n    {\n        \/\/ Here I suppose you have saved the List in your Resources folder\n        if( list&amp;amp;amp;amp;amp;amp;nbsp;== null )\n            list = Resources.Load&amp;amp;amp;amp;lt;ScenesList&amp;amp;amp;amp;gt;( \"ScenesList\" );\n\n        for( int i = 0 ; i &amp;amp;amp;amp;lt; list.scenesNames.Length ; ++ i )\n        {\n            Debug.Log( list.scenesNames[i] );\n        }\n    }\n}<\/pre>\n<p>And &#8230; voil\u00e0 ! You have the names of your scenes at runtime ! Or the path of your scenes to be more precise. If you want only the name, I suggest you to use the magic of the <a href=\"https:\/\/msdn.microsoft.com\/en-us\/library\/hs600312(v=vs.110).aspx\">Regular\u00a0expressions<\/a> (in the <code>System.Text.RegularExpressions<\/code> namespace) . Use it when you store the data or when you use it :<\/p>\n<pre><pre class=\"brush: csharp; title: ; notranslate\" title=\"\">private void Start()\n{\n    Regex regex = new Regex( @\"([^\/]*\/)*([\\w\\d\\-]*)\\.unity\" ) ;\n    for( int i = 0 ; i &amp;amp;amp;amp;lt; list.scenesNames.Length ; ++i )\n    {\n        \/\/ Will replace the full path by the second capturing group\n        \/\/ corresponding to the name of the scene\n        Debug.Log( regex.Replace( list.scenesNames[i], \"$2\" ) );\n    }\n}<\/pre>\n<h2>Warning<\/h2>\n<p>With the last script used\u00a0to store into the scriptable object, keep in mind that the information won&#8217;t be dynamically updated if you make modifications of your scenes in the Build Settings or if you rename your scenes. You will have to call the\u00a0<code>SaveScenesNames<\/code> using the Menu item.<\/p>\n<p>If you don&#8217;t want to do this by hand, you could listen for the event\u00a0<code>EditorApplication.playmodeStateChanged<\/code>\u00a0and save the names of the scenes when you click on the Play Button of the\u00a0editor.\u00a0Take a look <a href=\"http:\/\/answers.unity3d.com\/questions\/447701\/event-for-unity-editor-pause-and-playstop-events.html\">here<\/a> for an example of how to use it.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Edit: this script is awesome, and if you combine it with a ScriptableObject you&#8217;re ready to go! Retrieving the names of your scenes at runtime with Unity is\u00a0a common problem. The API of Unity doesn&#8217;t provide an\u00a0easy way do to so. With the quite recent SceneManager, I thought Unity had finally provided something to get &hellip; <a href=\"https:\/\/davikingcode.com\/blog\/retrieving-the-names-of-your-scenes-at-runtime-with-unity\/\" class=\"more-link\">Continue reading <span class=\"screen-reader-text\">Retrieving the names of your scenes at runtime with Unity<\/span><\/a><\/p>\n","protected":false},"author":3,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_discordance_state":"","_discordance_checked":true},"categories":[15],"tags":[5],"_links":{"self":[{"href":"https:\/\/davikingcode.com\/blog\/wp-json\/wp\/v2\/posts\/288"}],"collection":[{"href":"https:\/\/davikingcode.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/davikingcode.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/davikingcode.com\/blog\/wp-json\/wp\/v2\/users\/3"}],"replies":[{"embeddable":true,"href":"https:\/\/davikingcode.com\/blog\/wp-json\/wp\/v2\/comments?post=288"}],"version-history":[{"count":24,"href":"https:\/\/davikingcode.com\/blog\/wp-json\/wp\/v2\/posts\/288\/revisions"}],"predecessor-version":[{"id":1149,"href":"https:\/\/davikingcode.com\/blog\/wp-json\/wp\/v2\/posts\/288\/revisions\/1149"}],"wp:attachment":[{"href":"https:\/\/davikingcode.com\/blog\/wp-json\/wp\/v2\/media?parent=288"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/davikingcode.com\/blog\/wp-json\/wp\/v2\/categories?post=288"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/davikingcode.com\/blog\/wp-json\/wp\/v2\/tags?post=288"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}