Unity杂文——宏管理脚本

  1. 简介
  2. 代码
    1. 依赖的代码
    2. 管理工具代码

原文地址

简介

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

代码

依赖的代码

ResCatalog
/// <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";
}
BuildTargetUtility
/// <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
        };
    }
}
AssetLibrary
/// <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);
    }
}
SymbolsUtility
/// <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);
    }
}

管理工具代码

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

}

转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 841774407@qq.com

×

喜欢就点赞,疼爱就打赏