Sceneの受け渡しを扱いやすくする自動生成スクリプト



前回に引き続き、自動生成ネタです。
[UnityのLayerをEnumにしてくれるEditor拡張を作った](https://qiita.com/MizoTake/items/1590896d57439ad0e11b)

今回は、SceneをEnumにして扱えたら楽なんじゃないか？と思って作ってみた次第です。
単純にEnumにするのではく、stringの配列も加えています。


```csharp:SceneInfoCreator.cs

using UnityEngine;
using UnityEditor;
using System.Linq;
using UnityEditorInternal;
using System.Collections.Generic;
using System;
using System.IO;
using UnityEngine.SceneManagement;
using UnityEditor.SceneManagement;

[InitializeOnLoad]
public class SceneInfoCreator
{
    private const string SCENE_ENUM_HASH_KEY = "Scene_Info_Hash";

    [MenuItem("Assets/SceneInfoCreator")]
    public static void _sceneNameCreator()
    {
        if (EditorApplication.isPlaying || Application.isPlaying)
            return;

        EditorApplication.delayCall += BuildSceneName;
    }

    static SceneInfoCreator()
    {
        if (EditorApplication.isPlaying || Application.isPlaying)
            return;

        EditorApplication.delayCall += BuildSceneName;
    }

    static void BuildSceneName()
    {
        System.Text.StringBuilder builder = new System.Text.StringBuilder();

        builder = WriteManagerClass(builder);

        string text = builder.ToString().Replace(",}", "}");
        string assetPath = Application.dataPath + "/Scripts/Utility/SceneInfo.cs";

        if (AssetDatabase.LoadAssetAtPath(assetPath.Replace("/Editor/..", ""), typeof(UnityEngine.Object)) != null && EditorPrefs.GetInt(SCENE_ENUM_HASH_KEY, 0) == text.GetHashCode())
            return;

        System.IO.File.WriteAllText(assetPath, text);
        EditorPrefs.SetInt(SCENE_ENUM_HASH_KEY, text.GetHashCode());
        AssetDatabase.Refresh(ImportAssetOptions.ImportRecursive);
        EditorApplication.delayCall -= BuildSceneName;
    }

    static System.Text.StringBuilder WriteManagerClass(System.Text.StringBuilder builder)
    {
        var sceneNames = new List<string>();
        EditorBuildSettings.scenes
                    .Where(_ => _.enabled)
                    .Select(_ => Path.GetFileNameWithoutExtension(Path.Combine(Directory.GetCurrentDirectory(), _.path)))
                    .Where(_ => !string.IsNullOrEmpty(_))
                    .ForEach(_ => sceneNames.Add(_));
        builder.AppendLine("/// <summary>");
        builder.AppendFormat("/// Access Scene Class").AppendLine();
        builder.AppendLine("/// </summary>");
        /// 
        builder.Append("public sealed class SceneInfo {").AppendLine();
        WriteSceneEnum(builder, sceneNames);
        WriteSceneNameArray(builder, sceneNames);
        builder.AppendLine("}");
        return builder;
    }

    static void WriteSceneEnum(System.Text.StringBuilder builder, List<string> sceneNames)
    {
        builder.Append("\t").AppendLine("/// <summary>");
        builder.Append("\t").AppendFormat("/// Access Scene Number Enum").AppendLine();
        builder.Append("\t").AppendLine("/// </summary>");
        builder.Append("\t").Append("public enum SceneEnum {").AppendLine();
        sceneNames.ForEach((sceneName, i) =>
        {
            var comma = (i == sceneNames.Count() - 1) ? "" : ",";
            builder.Append("\t").Append("\t").AppendFormat("{0} = {1}", sceneName.SymbolReplace(), i + comma).AppendLine();
        });
        builder.Append("\t").AppendLine("};");
    }

    static void WriteSceneNameArray(System.Text.StringBuilder builder, List<string> sceneNames)
    {
        builder.Append("\t").AppendLine("/// <summary>");
        builder.Append("\t").AppendFormat("/// Access Scene Name Array").AppendLine();
        builder.Append("\t").AppendLine("/// </summary>");
        builder.Append("\t").Append("public static readonly string[] SceneNames = new string[]{");
        sceneNames.ForEach((sceneName, i) =>
        {
            var comma = (i == sceneNames.Count() - 1) ? "" : ",";
            builder.AppendFormat(@"""{0}""" + comma, sceneName);
        });
        builder.AppendLine("}; ");
    }
}
```

上記の処理を実行した時にBuildSettingsで仮にInit.sceneとTest.sceneを登録した場合、以下のようなスクリプトが生成されます。


```csharp:SceneInfo.cs
/// <summary>
/// Access Scene Class
/// </summary>
public sealed class SceneInfo {
	/// <summary>
	/// Access Scene Number Enum
	/// </summary>
	public enum SceneEnum {
		Init = 0,
		Test = 1
	};
	/// <summary>
	/// Access Scene Name Array
	/// </summary>
	public static readonly string[] SceneNames = new string[]{"Init","Test"}; 
}

```

これの自動生成があるだけでもかなりミスが減らせる気がします。InspectorでもEnum表示してScene選ぶとかできますし、何かと楽になりそうです。

ファイルの保存場所は適宜変えてください。

コピペでうまく動かない人は、前回の記事に書いてある拡張メソッドを追加してみてください。

自作フレームワークに組み込んで改修を続けているのでご興味あれば
https://github.com/MizoTake/MomijiFramework