Unity杂文——宏管理脚本

原文地址

简介

这是一个管理Unity宏设置的脚本工具,能快速的增删改查项目的脚本。
下面是效果图:

image.png

代码

依赖的代码

<details>
<summary> ResCatalog </summary>

/// <summary>
/// 资源路径
/// </summary>
public static class ResCatalog
{
    public const string DefaultRes = "Library/unity default resources";
    public const string Temporary = "Assets/_Temporary";
    public const string Library = "Assets/_Library";
}

</details>

<details>
<summary> BuildTargetUtility </summary>

/// <summary>
/// 构建的辅助工具
/// </summary>
public class BuildTargetUtility
{
    /// <summary>
    /// 获取对应平台的组
    /// </summary>
    /// <param name="p"></param>
    /// <returns></returns>
    public static BuildTargetGroup PlatformToGroup(RuntimePlatform p)
    {
        return p switch
        {
            RuntimePlatform.OSXEditor => BuildTargetGroup.Standalone,
            RuntimePlatform.OSXPlayer => BuildTargetGroup.Standalone,
            RuntimePlatform.WindowsPlayer => BuildTargetGroup.Standalone,
            RuntimePlatform.WindowsEditor => BuildTargetGroup.Standalone,
            RuntimePlatform.IPhonePlayer => BuildTargetGroup.iOS,
            RuntimePlatform.Android => BuildTargetGroup.Android,
            RuntimePlatform.LinuxPlayer => BuildTargetGroup.Standalone,
            RuntimePlatform.LinuxEditor => BuildTargetGroup.Standalone,
            RuntimePlatform.WebGLPlayer => BuildTargetGroup.WebGL,
            RuntimePlatform.PS4 => BuildTargetGroup.PS4,
            RuntimePlatform.XboxOne => BuildTargetGroup.XboxOne,
            RuntimePlatform.tvOS => BuildTargetGroup.tvOS,
            RuntimePlatform.Switch => BuildTargetGroup.Switch,
            _ => BuildTargetGroup.Unknown
        };
    }
}

</details>

<details>
<summary> AssetLibrary </summary>

/// <summary>
/// 资源的Library
/// </summary>
public static class AssetLibrary
{
    /// <summary>
    /// 判断文件是否存在
    /// </summary>
    /// <param name="path"></param>
    /// <param name="temporary"></param>
    /// <returns></returns>
    public static bool Exists(string path, bool temporary)
    {
        return File.Exists(GetPath(path, temporary));
    }

    /// <summary>
    /// 获取文件的地址
    /// </summary>
    /// <param name="path">文件名字</param>
    /// <param name="temporary">是否是临时文件</param>
    /// <returns></returns>
    public static string GetPath(string path, bool temporary)
    {
        return Path.Combine(temporary ? ResCatalog.Temporary : ResCatalog.Library, path);
    }

    /// <summary>
    /// 保存文件
    /// </summary>
    /// <param name="path">文件地址</param>
    /// <param name="text">文件内容</param>
    /// <param name="temporary">是否是临时文件</param>
    public static void Save(string path, string text, bool temporary)
    {
        WriteAllText(path, text, temporary);
    }

    /// <summary>
    /// 保存文件
    /// </summary>
    /// <param name="path">文件地址</param>
    /// <param name="bytes">写入的字节</param>
    /// <param name="temporary">是否是临时资源</param>
    public static void Save(string path, byte[] bytes, bool temporary)
    {
        WriteAllBytes(path, bytes, temporary);
    }

    /// <summary>
    /// 获取文件内的所有内容
    /// </summary>
    /// <param name="path">文件地址</param>
    /// <param name="temporary">是否是临时文件</param>
    /// <returns></returns>
    public static string GetString(string path, bool temporary)
    {
        return File.ReadAllText(GetPath(path, temporary));
    }

    /// <summary>
    /// 获取文件的所有字节
    /// </summary>
    /// <param name="path">文件地址</param>
    /// <param name="temporary">是否是临时资源</param>
    /// <returns></returns>
    public static byte[] GetBytes(string path, bool temporary)
    {
        return File.ReadAllBytes(GetPath(path, temporary));
    }

    /// <summary>
    /// 写入所有的字节
    /// </summary>
    /// <param name="path">文件路径</param>
    /// <param name="bytes">写入字节</param>
    /// <param name="temporary">是否是临时资源</param>
    private static void WriteAllBytes(string path, byte[] bytes, bool temporary)
    {
        var realPath = GetPath(path, temporary);
        PathUtils.MakeDirectory(realPath);
        File.WriteAllBytes(realPath, bytes);
    }
    /// <summary>
    /// 写入所有的文本内容
    /// </summary>
    /// <param name="path">文件路径</param>
    /// <param name="text">写入字符串</param>
    /// <param name="temporary">是否是临时资源</param>
    private static void WriteAllText(string path, string text, bool temporary)
    {
        var realPath = GetPath(path, temporary);
        PathUtils.MakeDirectory(realPath);
        File.WriteAllText(realPath, text);
    }
}

</details>

<details>
<summary> SymbolsUtility </summary>

/// <summary>
/// 宏的辅助工具
/// </summary>
public static class SymbolsUtility
{
    /// <summary>
    /// 设置宏
    /// </summary>
    /// <param name="symbols"></param>
    public static void SetSymbols(params string[] symbols)
    {
        var result = string.Join(";", symbols);
        PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Standalone, result);
        PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.iOS, result);
        PlayerSettings.SetScriptingDefineSymbolsForGroup(BuildTargetGroup.Android, result);
    }

    /// <summary>
    /// 获取所有的宏
    /// </summary>
    /// <returns></returns>
    public static string[] GetSymbols()
    {
        var group = BuildTargetUtility.PlatformToGroup(Application.platform);
        var symbols = PlayerSettings.GetScriptingDefineSymbolsForGroup(group);
        return symbols.Split(';');
    }

    /// <summary>
    /// 增加宏
    /// </summary>
    /// <param name="symbols">宏的组</param>
    public static void AddSymbols(params string[] symbols)
    {
        SetSymbols(GetSymbols().Union(symbols).ToArray());
    }

    /// <summary>
    /// 移除宏
    /// </summary>
    /// <param name="symbols">宏的组</param>
    public static void RemoveSymbols(params string[] symbols)
    {
        SetSymbols(GetSymbols().Except(symbols).ToArray());
    }

    /// <summary>
    /// 判断是否拥有宏
    /// </summary>
    /// <param name="symbol">宏的名字</param>
    /// <returns></returns>
    public static bool HasSymbols(string symbol)
    {
        return -1 != Array.IndexOf(GetSymbols(), symbol);
    }
}

</details>

管理工具代码

internal class SymbolsManager : EditorWindow
{

    /// <summary>
    /// 宏的配置
    /// </summary>
    public class SymbolsConfig
    {
        /// <summary>
        /// 宏的名字
        /// </summary>
        public string name;
        /// <summary>
        /// 是否使用
        /// </summary>
        [NonSerialized]
        public bool used;
    }

    /// <summary>
    /// 宏的组
    /// </summary>
    public class SymbolsGroup
    {
        /// <summary>
        /// 组的名字
        /// </summary>
        public string name;
        /// <summary>
        /// 组的宏列表
        /// </summary>
        public List<SymbolsConfig> list;
        /// <summary>
        /// 用于显示的List
        /// </summary>
        [NonSerialized]
        public ReorderableList reorderableList;
        /// <summary>
        /// 是否已经删除
        /// </summary>
        [NonSerialized]
        public bool deleted;
    }

    /// <summary>
    /// 组的列表
    /// </summary>
    private List<SymbolsGroup> m_Groups;

    /// <summary>
    /// 宏管理窗口
    /// </summary>
    [MenuItem("Tools/SymbolsManager", false)]
    private static void OpenWindow()
    {
        var window = GetWindow<SymbolsManager>("SymbolsManager");
        window.minSize = new Vector2(350, 100);
    }

    private void OnEnable()
    {
        var path = GetSettingsFileName();
        if (AssetLibrary.Exists(path, false))
        {
            var text = AssetLibrary.GetString(path, false);
            JsonUtils.ToObject(text, out m_Groups);
            foreach (var group in m_Groups)
            {
                if (null == group.list)
                {
                    group.list = new List<SymbolsConfig>();
                }
                else
                {
                    foreach (var config in group.list)
                    {
                        config.used = SymbolsUtility.HasSymbols(config.name);
                    }
                }
            }
        }

        m_Groups ??= new List<SymbolsGroup>();
    }

    /// <summary>
    /// 绘制面板
    /// </summary>
    private void OnGUI()
    {
        for (var i = 0; i < m_Groups.Count;)
        {
            var group = m_Groups[i];
            GUILayout.BeginVertical(EditorStyles.helpBox);
            {
                if (null == group.reorderableList)
                {
                    group.list ??= new List<SymbolsConfig>();

                    group.reorderableList = new ReorderableList(group.list, typeof(SymbolsConfig))
                    {
                        drawHeaderCallback = rect =>
                        {
                            var textRt = rect;
                            textRt.width /= 2f;
                            group.name = EditorGUI.TextField(textRt, group.name, EditorStyles.boldLabel);

                            var btnRt = rect;
                            btnRt.x = btnRt.xMax - Styles.closeButton.lineHeight;
                            if (GUI.Button(btnRt, GUIContent.none, Styles.closeButton))
                            {
                                if (EditorUtility.DisplayDialog(
                                    "提示", "是否确认删除?", "确认", "取消"))
                                {
                                    group.deleted = true;
                                }
                            }
                        },
                        drawElementCallback = (rect, index, active, focused) =>
                        {
                            var item = group.list[index];

                            var textRect = new Rect(
                                rect.position + Vector2.up * 2,
                                new Vector2(rect.width - 100, EditorGUIUtility.singleLineHeight));
                            item.name = GUI.TextField(textRect, item.name)?.Trim();
                            const int btnWidth = 80;
                            var oldColor = GUI.color;
                            GUI.color = SymbolsUtility.HasSymbols(item.name) ? Color.green : Color.red;
                            var btnRect = new Rect(
                                rect.position + Vector2.up + Vector2.right * (rect.width - btnWidth),
                                new Vector2(btnWidth, EditorGUIUtility.singleLineHeight));
                            item.used = GUI.Toggle(btnRect, item.used,
                                item.used ? Styles.used : Styles.unused,
                                EditorStyles.toolbarButton);

                            GUI.color = oldColor;
                        },
                        elementHeight = 22,
                    };
                }

                group.reorderableList.DoLayoutList();

                GUILayout.BeginHorizontal();
                GUILayout.FlexibleSpace();
                if (GUILayout.Button(Styles.apply, GUILayout.Height(30), GUILayout.Width(100)))
                {
                    foreach (var config in group.list)
                    {
                        if (config.used)
                        {
                            SymbolsUtility.AddSymbols(config.name);
                        }
                        else
                        {
                            SymbolsUtility.RemoveSymbols(config.name);
                        }
                    }

                    AssetDatabase.SaveAssets();
                    AssetDatabase.Refresh();
                }

                GUILayout.FlexibleSpace();
                GUILayout.EndHorizontal();
                GUILayout.Space(5);
            }
            GUILayout.EndVertical();

            if (group.deleted)
            {
                m_Groups.RemoveAt(i);
            }
            else
            {
                ++i;
            }
        }

        //
        GUILayout.BeginHorizontal();
        GUILayout.FlexibleSpace();
        if (GUILayout.Button(Styles.addGroup, GUILayout.Height(30), GUILayout.Width(200)))
        {
            m_Groups.Add(new SymbolsGroup
            {
                name = Styles.customName,
                list = new List<SymbolsConfig>()
            });
        }

        GUILayout.FlexibleSpace();
        GUILayout.EndHorizontal();


        var e = Event.current;
        if (e.keyCode == KeyCode.S && e.type == EventType.KeyUp)
        {
            e.Use();
            Save();
        }
    }

    /// <summary>
    /// 销毁的时候保存
    /// </summary>
    private void OnDisable()
    {
        Save();
    }

    /// <summary>
    /// 保存
    /// </summary>
    private void Save()
    {
        JsonResolver.NotSerializeDefault = true;

        var text = JsonUtils.ToPrettyString(m_Groups);
        AssetLibrary.Save(GetSettingsFileName(), text, false);

        JsonResolver.NotSerializeDefault = false;
    }

    /// <summary>
    /// 序列化Json文件的名字,采用 “类名Settings.json”格式
    /// </summary>
    /// <returns></returns>
    private string GetSettingsFileName()
    {
        return $"{GetType().Name}Settings.json";
    }


    #region 显示风格Style

    /// <summary>
    /// 编辑器的风格
    /// </summary>
    private static class Styles
    {
        /// <summary>
        /// 已经使用
        /// </summary>
        public static GUIContent used;
        /// <summary>
        /// 未使用
        /// </summary>
        public static GUIContent unused;
        /// <summary>
        /// 应用
        /// </summary>
        public static GUIContent apply;
        /// <summary>
        /// 新增分组
        /// </summary>
        public static GUIContent addGroup;
        /// <summary>
        /// 自定义名称(点击修改)
        /// </summary>
        public static string customName;
        /// <summary>
        /// WinBtnClose
        /// </summary>
        public static GUIStyle closeButton;

        static Styles()
        {
            used = new GUIContent("已使用");
            unused = new GUIContent("未使用");
            apply = new GUIContent("应用");
            addGroup = new GUIContent("新增分组");
            customName = "自定义名称(点击修改)";
            closeButton = new GUIStyle("WinBtnClose");
        }
    }

    #endregion

}
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 202,529评论 5 475
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,015评论 2 379
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 149,409评论 0 335
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,385评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,387评论 5 364
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,466评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,880评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,528评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,727评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,528评论 2 319
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,602评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,302评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,873评论 3 306
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,890评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,132评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,777评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,310评论 2 342

推荐阅读更多精彩内容