LoginSignup
4
4

More than 5 years have passed since last update.

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

Last updated at Posted at 2017-08-03

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

UnityEditorInternal.InternalEditorUtilityを使う - けいごのなんとか

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

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

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に含めず、スキップする処理にしてますが…あまり気に入ってないです…
あと、実はこれだけでは動かないです。クラス拡張も行なっているので…

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を入力すると番号がズレるため、その辺は ご自分でよしなにお願いします。
初めての自動生成スクリプト(見よう見まね)なのでツッコミ所があれば突っ込んでいただければと思います。

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

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

4
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
4