• Unity拓展编辑器 一键导出图集工具


            在项目开发过程中我们必不可少的会将美术给的资源打包成图集来降低drawcall,减少包内存。

            为了方便的生成图集,以及生成图片路径配置来方便通过图片名称快速定位所在的图集以及图片位置。

    怎样实现一键导出图集扩展工具?

    1. 在工程目录设置一个存放UI图片资源的root目录
    2. 想要打包成同一图集的图片资源放在该目录下的同一文件夹下
    3. 创建 SpriteAtlasUtils 扩展编辑器脚本

    代码实现思路

    1. 检查是否存在同名图片
    2. 生成 sprite 信息数据字典(名称,图集名,图集路径,图片路径)
    3. 通过 sprite 信息数据生成图集
    4. 生成 SpriteConfig 配置信息(用来通过图片名称查找所在图集路径|图片路径)

    先看效果

     

     

     

    关键代码:

    1. 获取root文件夹下的所有文件夹
    2. 获取某个文件夹下的所有图片资源guid(资源唯一标识)
    3. 通过唯一标识获取资源路径
    1. // 获取图片资源root下的所有文件夹
    2. string[] allPath = Directory.GetDirectories(SpriteRootPath);
    3. // 筛选出是sprite图片
    4. string[] guids = AssetDatabase.FindAssets("t:Sprite",new []{allPath[i]});
    5. // guid 转成资源路径
    6. string spritePath = AssetDatabase.GUIDToAssetPath(guids[j]);
    7. // 加载sprite资源
    8. Sprite sp = AssetDatabase.LoadAssetAtPath(spritePath);

    创建图集

    1. // 创建图集
    2. SpriteAtlas atlas = new SpriteAtlas();
    3. // 添加图集所有图片
    4. atlas.Add(sprite);
    5. // 创建图集资源
    6. AssetDatabase.CreateAsset(atlas,path);

    由于项目使用的是lua热更新所已导出的SpriteConfig是lua脚本,导出文件的难度也不大,废话不多说,直接看下面完整代码吧

    1. using System.Collections.Generic;
    2. using System.IO;
    3. using System.Linq;
    4. using System.Text;
    5. using UnityEditor;
    6. using UnityEditor.U2D;
    7. using UnityEngine;
    8. using UnityEngine.U2D;
    9. namespace Editor.UI.Atlas
    10. {
    11. public static class SpriteAtlasUtils
    12. {
    13. public class SpriteData
    14. {
    15. public string name;
    16. public string path;
    17. public string atlasName;
    18. public Sprite sprite;
    19. }
    20. private const string SpriteRootPath = "Assets/UI/Sprite/";
    21. private const string SpriteAtlasRootPath = "Assets/UI/Atlas";
    22. private const string SpriteConfigPath = "Assets/Scripts/Lua/Configs/SpriteConfig.lua";
    23. private const string
    24. SpriteConfigTemplate = "Assets/Scripts/CS/Core/UI/LuaTemplate/SpriteConfigTemplate.txt"; // 模板文件
    25. [MenuItem("My菜单/导出图集")]
    26. private static void Execute()
    27. {
    28. float total = 5;
    29. float temp = 0;
    30. ShowProgress("检查是否重名", ++temp, total);
    31. if (CheckTheSameName())
    32. {
    33. EditorUtility.ClearProgressBar();
    34. return;
    35. }
    36. ShowProgress("生成图集数据", ++temp, total);
    37. Dictionary<string, List> spriteDic = GenerateSpriteData();
    38. ShowProgress("生成图集", ++temp, total);
    39. GenerateSpriteAtlas(spriteDic);
    40. ShowProgress("生成配置数据", ++temp, total);
    41. GenerateSpriteConfig(spriteDic);
    42. ShowProgress("生成图集结束", ++temp, total);
    43. EditorUtility.DisplayDialog("导出图集", $"图集导出成功,总共导出 {spriteDic.Count} 张图集", "OK");
    44. EditorUtility.ClearProgressBar();
    45. }
    46. [MenuItem("My菜单/清空图集")]
    47. private static void Clear()
    48. {
    49. var guids = AssetDatabase.FindAssets("", new[] {SpriteAtlasRootPath});
    50. for (int i = 0; i < guids.Length; i++)
    51. {
    52. AssetDatabase.DeleteAsset(AssetDatabase.GUIDToAssetPath(guids[i]));
    53. }
    54. AssetDatabase.Refresh();
    55. }
    56. // 生成图集数据
    57. private static Dictionary<string,List> GenerateSpriteData()
    58. {
    59. // 获取图片资源root下的所有文件夹
    60. string[] allPath = Directory.GetDirectories(SpriteRootPath);
    61. Dictionary<string,List> atlasDic = new Dictionary<string, List>();
    62. for (int i = 0; i < allPath.Length; i++)
    63. {
    64. string atlasName = Path.GetFileNameWithoutExtension(allPath[i]);
    65. // 筛选出是sprite图片
    66. string[] guids = AssetDatabase.FindAssets("t:Sprite",new []{allPath[i]});
    67. List spriteDatas = new List();
    68. for (int j = 0; j < guids.Length; j++)
    69. {
    70. // guid 转成资源路径
    71. string spritePath = AssetDatabase.GUIDToAssetPath(guids[j]);
    72. // 加载sprite资源
    73. Sprite sp = AssetDatabase.LoadAssetAtPath(spritePath);
    74. SpriteData data = new SpriteData();
    75. data.name = Path.GetFileNameWithoutExtension(spritePath);
    76. data.path = spritePath;
    77. data.sprite = sp;
    78. data.atlasName = atlasName;
    79. spriteDatas.Add(data);
    80. }
    81. atlasDic.Add(atlasName,spriteDatas);
    82. }
    83. return atlasDic;
    84. }
    85. // 生成图集
    86. private static void GenerateSpriteAtlas(Dictionary<string,List> spriteDic)
    87. {
    88. foreach (var datas in spriteDic)
    89. {
    90. // 创建图集
    91. SpriteAtlas atlas = new SpriteAtlas();
    92. // 添加图集所有图片
    93. atlas.Add(datas.Value.Select(t=> t.sprite).ToArray());
    94. string path = SpriteAtlasRootPath + "/" + datas.Key + ".spriteatlas";
    95. if (!Directory.Exists(SpriteAtlasRootPath))
    96. {
    97. Directory.CreateDirectory(SpriteAtlasRootPath);
    98. }
    99. // 创建图集资源
    100. AssetDatabase.CreateAsset(atlas,path);
    101. }
    102. // 刷新文件
    103. AssetDatabase.Refresh();
    104. }
    105. // 检查是否重名
    106. private static bool CheckTheSameName()
    107. {
    108. Dictionary<string, List<string>> pathDic = new Dictionary<string, List<string>>();
    109. List<string> theSameKeys = new List<string>();
    110. // 获取所有图片文件夹
    111. string[] allPath = Directory.GetDirectories(SpriteRootPath);
    112. for (int i = 0; i < allPath.Length; i++)
    113. {
    114. // 获取文件夹下的所有资源唯一标识id
    115. string[] guids = AssetDatabase.FindAssets("t:Sprite",new []{allPath[i]});
    116. for (int j = 0; j < guids.Length; j++)
    117. {
    118. // 通过资源guid获得资源路径
    119. string spritePath = AssetDatabase.GUIDToAssetPath(guids[j]);
    120. string spName = Path.GetFileNameWithoutExtension(spritePath);
    121. List<string> pathList = null;
    122. if (pathDic.TryGetValue(spName,out pathList))
    123. {
    124. if (!theSameKeys.Contains(spName))
    125. {
    126. theSameKeys.Add(spName);
    127. }
    128. }
    129. else
    130. {
    131. pathList = new List<string>();
    132. pathDic.Add(spName,pathList);
    133. }
    134. pathList.Add(spritePath);
    135. }
    136. }
    137. if (theSameKeys.Count > 0)
    138. {
    139. string msg = "";
    140. for (int i = 0; i < theSameKeys.Count; i++)
    141. {
    142. List<string> pList = pathDic[theSameKeys[i]];
    143. for (int j = 0; j < pList.Count; j++)
    144. {
    145. msg = msg + pList[j] + "\n";
    146. }
    147. }
    148. if (EditorUtility.DisplayDialog("出现同名sprite", msg, "确定"))
    149. {
    150. }
    151. return true;
    152. }
    153. return false;
    154. }
    155. // 生成配置
    156. private static void GenerateSpriteConfig(Dictionary<string, List> spriteDic)
    157. {
    158. StreamReader streamReader = File.OpenText(SpriteConfigTemplate);
    159. string template = streamReader.ReadToEnd();
    160. streamReader.Close();
    161. StreamWriter streamWriter = File.CreateText(SpriteConfigPath);
    162. StringBuilder atlasPathStr = new StringBuilder();
    163. StringBuilder spritePathStr = new StringBuilder();
    164. StringBuilder spriteAtlasPathStr = new StringBuilder();
    165. foreach (var info in spriteDic)
    166. {
    167. string atlasName = info.Key;
    168. string atlasPath = SpriteAtlasRootPath + atlasName;
    169. atlasPathStr.AppendLine(string.Format("\t{0} = '{1}';", atlasName,atlasPath));
    170. for (int i = 0; i < info.Value.Count; i++)
    171. {
    172. spritePathStr.AppendLine(string.Format("\t['{0}'] = '{1}';",info.Value[i].name ,info.Value[i].path));
    173. spriteAtlasPathStr.AppendLine(string.Format("\t['{0}'] = {1};",info.Value[i].name,"M.AtlasPath." + atlasName));
    174. }
    175. }
    176. template = template.Replace("$ATLASPATH$", atlasPathStr.ToString())
    177. .Replace("$SPRITEPATH$", spritePathStr.ToString())
    178. .Replace("$SPRITEATLASPATH$", spriteAtlasPathStr.ToString());
    179. streamWriter.WriteLine(template);
    180. streamWriter.Close();
    181. }
    182. // 显示进度
    183. private static void ShowProgress(string info,float tmp,float total)
    184. {
    185. EditorUtility.DisplayProgressBar("生成图集", info, tmp / total);
    186. }
    187. }
    188. }

  • 相关阅读:
    nodeJs 基础
    洛谷_P3388
    C#语言进阶(二)—事件 第二篇(.net标准事件模型)
    一台服务器,一个新世界
    python-wordcloud词云
    限流神器之-Guava RateLimiter 实战
    无光照渲染shader-二次元
    批量删除docker过期停止的容器(全)
    美国信用卡返现率优化到3%-5%,AI优化算法的应用
    07 nginx 的 worker process 的调试
  • 原文地址:https://blog.csdn.net/weixin_41316824/article/details/126884914