UnityのLayerをEnumにしてくれるEditor拡張を作った


GameObjectのTag管理を楽にしたくて調べてたら、これをみつけました。

[UnityEditorInternal.InternalEditorUtilityを使う - けいごのなんとか](http://anchan828.hatenablog.jp/entry/2013/02/20/042650)

Tagを扱いやすくするクラスの自動生成…なんと甘美な響き…！！
結構前の記事ではありますがUnity5.6.3とかでも動作してくれるので、すごく助かります。

…ここでTagだけでなくLayerも扱いやすくできれば…どうせならEnumに…と思いまして、上記の記事のクラス自動生成を見よう見まねでLayerからEnumスクリプトの自動生成を作ってみました。

```csharp:LayerEnumCreator.cs
using UnityEngine;
using UnityEditor;
using System.Linq;
using UnityEditorInternal;
using System.Collections.Generic;
using System;
using System.IO;

namespace Momiji
{
    [InitializeOnLoad]
    public class LayerEnumCreator
    {
        private const string LAYER_ENUM_HASH_KEY = "Layer_Enum_Hash";

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

            EditorApplication.delayCall += BuildlayerName;
        }

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

            EditorApplication.delayCall += BuildlayerName;
        }

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

            builder = WriteTagManagerClass(builder);


            string text = builder.ToString().Replace(",}", "}");
            string assetPath = Application.dataPath + EditorExtensionConst.SAVE_FILE_POINT + "LayerEnum.cs";

            Directory.CreateDirectory(Application.dataPath + EditorExtensionConst.SAVE_FILE_POINT);

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

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

        static System.Text.StringBuilder WriteTagManagerClass(System.Text.StringBuilder builder)
        {
            List<string> layerNames = InternalEditorUtility.layers.ToList();
            WriteLayerEnum(builder, layerNames);
            return builder;
        }

        static void WriteLayerEnum(System.Text.StringBuilder builder, List<string> layerNames)
        {
            builder.AppendLine("/// <summary>");
            builder.AppendFormat("/// Access Layer Number Enum").AppendLine();
            builder.AppendLine("/// </summary>");
            builder.Append("public enum LayerEnum").AppendLine();
            builder.AppendLine("{");
            layerNames.ForEach((layerName, i) =>
            {
                var comma = (i == layerNames.Count() - 1) ? "" : ",";
                if (i >= 3)
                {
                    i += 1;
                    if (i >= 6)
                    {
                        i += 2;
                    }
                }
                builder.Append("\t").AppendFormat(@"{0} = {1}", layerName.SymbolReplace(), i + comma).AppendLine();
            });
            builder.AppendLine("};");
        }
    }
}
```


UnityのEditorの方でLayerの3, 6, 7は入力ができず空白なのでenumに含めず、スキップする処理にしてますが…あまり気に入ってないです…
あと、実はこれだけでは動かないです。クラス拡張も行なっているので…

```csharp:ClassExtension.cs
using UnityEngine;
using System.Linq;
using System.Collections.Generic;
using System;

public static class ClassExtension
{
    public static string SymbolReplace(this string name)
    {
        string[] invalidChar = new string[] {" ", "　", "!", "\"", "#", "$", "%", "&", "\'", "(", ")", "-", "=", "^", "~", "¥", "|", "[", "{", "@", "`", "]", "}", ":", "*", ";", "+", "/", "?", ".", ">", ",", "<"};
		invalidChar.ToList ().ForEach (s => name = name.Replace (s, string.Empty));
		return name;
    }
    
    public static void ForEach<T> (this IEnumerable<T> collection, Action<T, int> action)
	{
		int i = 0;
		foreach (T t in collection) {
			action (t, i++);
		}
	}
}

```

この拡張を加えれば動くと思います。
ただ、注意点なのはLayerは8から入力できますが、8を入力せず9を入力すると番号がズレるため、その辺は ご自分でよしなにお願いします。
初めての自動生成スクリプト(見よう見まね)なのでツッコミ所があれば突っ込んでいただければと思います。

デフォルトの結果だとこうなります。

```csharp:LayerEnum.cs
public class LayerEnum
{
	/// <summary>
	/// Access Layer Number Enum
	/// </summary>
	public enum Layer {
		Default = 0,
		TransparentFX = 1,
		IgnoreRaycast = 2,
		Water = 4,
		UI = 5
	};
}
```

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