前言:

项目需要,1.需提供给美术合图集工具,2.图集更新功能,使得新图集内的子图不必重新拖拽定位

解决思路:

1.unity调用外部TexturePacker命令行工具执行合图,unity根据TP生成的数据对图集切割出多个sprite

2.图集内的子图拖拽定位时,资源内产生对应的GUID及FileID。因此新图集更新对应的GUID与FileID即可,但是API没找到相应的接口,因此从资源本身下手通过txt方式打开,强制替换相应的ID

参考文档:

https://blog.csdn.net/pdw_jsp/article/details/83623150?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522159900871219725264608797%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fblog.%2522%257D&request_id=159900871219725264608797&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~blog~first_rank_v2~rank_blog_v1-4-83623150.pc_v2_rank_blog_v1&utm_term=TexturePacker+%E4%B8%80%E9%94%AE%E6%89%93%E5%8C%85&spm=1018.2118.3001.4187

https://www.xuanyusong.com/archives/4207

效果:

源码:

下面三个文件,放置于工程Assets\Editor即可

using System;
using System.Collections.Generic;
using UnityEngine;
using System.IO;
using UnityEditor;
using System.Text;
using System.Diagnostics;
using System.Linq;
using System.Xml;
using System.Collections;
using LuaFramework;public class TexturePackerBuild : Editor
{private const string BuildDir = "Assets/TexturePacker/打包该图集";/// <summary>/// TexturePacker.exe ###https://www.codeandweb.com/texturepacker/documentation/texture-settings/// </summary>private const string Paramet = " --sheet {0}.png --data {1}.xml --format sparrow --trim-mode CropKeepPos --pack-mode Best --algorithm MaxRects --max-size 4096 --size-constraints POT --disable-rotation {2}";/// <summary>/// 输出目录/// </summary>private const string OutPutDirRoot = "Assets/TPSpriteBuild/";private static string tpDir = "";private static string argument = "";[MenuItem(BuildDir, false)]public static void BuildOneTP(){if (Directory.Exists(OutPutDirRoot) == false){Directory.CreateDirectory(OutPutDirRoot);}var assetPaths = Selection.assetGUIDs.Select(AssetDatabase.GUIDToAssetPath).ToList();List<string> filePathList = new List<string>();foreach (var assetPath in assetPaths){if (AssetDatabase.IsValidFolder(assetPath)){string[] filesPath = Directory.GetFiles(assetPath);foreach (var filePath in filesPath){if (filePathList.Contains(filePath) == false){filePathList.Add(filePath);}else{UnityEngine.Debug.LogErrorFormat("检测到相同文件 {0}", assetPath);}}}else{filePathList.Add(assetPath);}}Dictionary<string, FileData> fileDic = new Dictionary<string, FileData>();foreach (var path in filePathList){var dir = Path.GetFileName(Path.GetDirectoryName(path));var fileName = Path.GetFileName(path);UnityEngine.Debug.LogFormat("_TP dirName {0} _TP fileName {1} _TP fullPath {2}", dir, fileName, path);if (fileDic.ContainsKey(dir) == false){FileData fileData = new FileData();fileData.filesList = new List<string>();fileDic[dir] = fileData;fileDic[dir].dirName = dir;}fileDic[dir].filesList.Add(path);}foreach (var data in fileDic){TexturePackerBuild tpBuild = new TexturePackerBuild();tpBuild.Build(data.Value);}}public void Build(FileData data){StringBuilder sb = new StringBuilder("");GetImageName(data.filesList, ref sb);string sheetName = OutPutDirRoot + data.dirName;argument = string.Format(Paramet, sheetName, sheetName, sb.ToString());tpDir = PlayerPrefs.GetString("_TPInstallDir", "");RunExternalApp(tpDir, argument);}private StringBuilder GetImageName(List<string> fileName, ref StringBuilder sb){foreach (var file in fileName){string extenstion = Path.GetExtension(file);if (extenstion == ".png"){sb.Append(file);sb.Append("  ");}}return sb;}private void RunExternalApp(string command, string argument){UnityEngine.Debug.Log("TPSprite Recover");ClearOtherFiles();ProcessStartInfo start = new ProcessStartInfo(command);start.Arguments = argument;start.CreateNoWindow = false;start.ErrorDialog = true;start.UseShellExecute = false;start.RedirectStandardOutput = true;start.RedirectStandardError = true;start.RedirectStandardInput = true;start.StandardOutputEncoding = System.Text.UTF8Encoding.UTF8;start.StandardErrorEncoding = System.Text.UTF8Encoding.UTF8;try{Process p = Process.Start(start);p.WaitForExit();p.Close();AssetDatabase.Refresh();bool isNullFile; // 判断输出目录下文件是否为空string outPngPath;BuildTexturePacker(out isNullFile,out outPngPath);if (isNullFile == false){tpDir = command;PlayerPrefs.SetString("_TPInstallDir", command);SelectAtlasUpdataWindow(outPngPath);}else{// 输出文件为空,猜测exe使用不正确,重新导入exeOnError("输出目录下未检测到图片,请重新导入");}}catch (Exception ex){OnError(ex.Message);}}/// <summary>/// 清理输出目录下原始图/// </summary>private void ClearOtherFiles(){string[] fileName = Directory.GetFiles(OutPutDirRoot);if (fileName != null && fileName.Length > 0){for (int i = 0; i < fileName.Length; i++){string extenstion = Path.GetExtension(fileName[i]);if (extenstion == ".png" || extenstion == ".xml"){File.Delete(fileName[i]);}}}}/// <summary>/// 创建Texture/// </summary>/// <param name="isNull"></param>/// <param name="outPngPath"></param>public void BuildTexturePacker(out bool isNull, out string outPngPath){isNull = true; outPngPath = "";string[] imagePath = Directory.GetFiles(OutPutDirRoot);foreach (string path in imagePath){if (Path.GetExtension(path) == ".png" || Path.GetExtension(path) == ".PNG"){Texture2D texture = AssetDatabase.LoadAssetAtPath<Texture2D>(path);string rootPath = OutPutDirRoot + texture.name;string pngPath = rootPath + "/" + texture.name + "_" + DateTime.Now.ToString("hh_mm_ss") + ".png";outPngPath = pngPath;isNull = false;if (Directory.Exists(rootPath) == false){Directory.CreateDirectory(rootPath);}File.Copy(OutPutDirRoot + texture.name + ".png", pngPath);AssetDatabase.Refresh();FileStream fs = new FileStream(OutPutDirRoot + texture.name + ".xml", FileMode.Open);StreamReader sr = new StreamReader(fs);string jText = sr.ReadToEnd();fs.Close();sr.Close();WriteMeta(jText, pngPath);}}ClearOtherFiles();AssetDatabase.Refresh();}void SelectAtlasUpdataWindow(string pngPath){TPSelectFileWindow win = new TPSelectFileWindow();win.Popup(pngPath, UpdataAssetRes);}void UpdataAssetRes(string opPath, Texture pendingTex){var srcObj = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(opPath);TPFindReplaceRes tpFindRep = new TPFindReplaceRes();tpFindRep.OnTPReplaceAssetData(pendingTex, srcObj);}//写信息到SpritesSheet里void WriteMeta(string jText, string path){UnityEngine.Debug.Log("WriteMeta " + path);XmlDocument xml = new XmlDocument();xml.LoadXml(jText);XmlNodeList elemList = xml.GetElementsByTagName("SubTexture");Texture2D texture = AssetDatabase.LoadAssetAtPath<Texture2D>(path);string impPath = AssetDatabase.GetAssetPath(texture);TextureImporter asetImp = TextureImporter.GetAtPath(impPath) as TextureImporter;SpriteMetaData[] metaData = new SpriteMetaData[elemList.Count];for (int i = 0, size = elemList.Count; i < size; i++){XmlElement node = (XmlElement)elemList.Item(i);Rect rect = new Rect();rect.x = int.Parse(node.GetAttribute("x"));rect.y = texture.height - int.Parse(node.GetAttribute("y")) - int.Parse(node.GetAttribute("height"));rect.width = int.Parse(node.GetAttribute("width"));rect.height = int.Parse(node.GetAttribute("height"));metaData[i].rect = rect;metaData[i].pivot = new Vector2(0.5f, 0.5f);metaData[i].name = node.GetAttribute("name");}asetImp.spritesheet = metaData;asetImp.textureType = TextureImporterType.Sprite;asetImp.spriteImportMode = SpriteImportMode.Multiple;asetImp.mipmapEnabled = false;asetImp.SaveAndReimport();}private string OpenTPEXE(){string path = EditorUtility.OpenFilePanel("请定位TexturePacker.exe程序,用于后续操作", "", "exe");return path;}private void OnError(string err){UnityEngine.Debug.LogError("TPBuild Err:" + err);EditorUtility.DisplayDialog("请重新定位TexturePacker.exe程序!", "Err:" + err, "确定");var path = OpenTPEXE();if (path.Length != 0){RunExternalApp(path, argument);}}public class FileData{public string dirName;public List<string> filesList;}
}
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;/// <summary>
/// 编辑器主界面
/// </summary>
public class TPSelectFileWindow : EditorWindow {private Action<string, Texture> _callBack;private string _opPath;private Texture _selectTex;public void Popup(string opPath, Action<string, Texture> cb){_callBack = cb;_opPath = opPath;var isSeek = EditorUtility.DisplayDialog("等待执行...", "是否更新原有的图集, 目前仅支持更新单个图集", "确定", "取消");if (isSeek == true){TPSelectFileWindow window = EditorWindow.GetWindow(typeof(TPSelectFileWindow), true, "等待执行...") as TPSelectFileWindow;window.minSize = new Vector2(450, 300);window.Show();}else{if (_callBack != null){_callBack.Invoke(_opPath, _selectTex);}_callBack = null;}}private void OnGUI(){ShowEditorGUI();}private void ShowEditorGUI(){_selectTex = EditorGUILayout.ObjectField("添加原绑定的Texture", _selectTex, typeof(Texture), true) as Texture;if (_selectTex != null && string.IsNullOrEmpty(_selectTex.name) == false){EditorGUILayout.TextField(AssetDatabase.GetAssetOrScenePath(_selectTex));}if (GUILayout.Button("关闭窗口并继续执行")){//关闭窗口this.Close();}}private void OnDestroy(){    if (_callBack != null){_callBack.Invoke(_opPath, _selectTex);}_callBack = null;_selectTex = null;}
}
using UnityEngine;
using UnityEngine.UI;
using UnityEditor;
using System.Collections;
using System.IO;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Collections.Generic;public class TPFindReplaceRes {Dictionary<string, AssetData> assetDic;string srcGUID;string tarGUID;/// <summary>/// 更新Asset数据/// </summary>/// <param name="srcObj">检索已定位过的OBJ,操作后可废弃</param>/// <param name="tarObj">等待更新数据干净的OBJ</param>public void OnTPReplaceAssetData(Object srcObj, Object tarObj) {AssetDatabase.Refresh();EditorSettings.serializationMode = SerializationMode.ForceText;string srcPath = AssetDatabase.GetAssetPath(srcObj);string tarPath = AssetDatabase.GetAssetPath(tarObj);if (string.IsNullOrEmpty(tarPath) || string.IsNullOrEmpty(srcPath)){Debug.Log("srcObj = null || tarObj = null");return;}Debug.LogFormat("srcPath:{0} , tarPath:{1}", srcPath, tarPath);srcGUID = AssetDatabase.AssetPathToGUID(srcPath);tarGUID = AssetDatabase.AssetPathToGUID(tarPath);OnCreateMetaData(srcPath, tarPath);var withoutExtensions = new List<string>() { ".prefab", ".unity", ".mat", ".asset" };string[] files = Directory.GetFiles(Application.dataPath, "*.*", SearchOption.AllDirectories).Where(s => withoutExtensions.Contains(Path.GetExtension(s).ToLower())).ToArray();int startIndex = 0;EditorApplication.update = delegate () {string file = files[startIndex];bool isCancel = EditorUtility.DisplayCancelableProgressBar("匹配资源中", file, (float)startIndex / (float)files.Length);if (Regex.IsMatch(File.ReadAllText(file), srcGUID)){OnUpdateData(file);var obj = AssetDatabase.LoadAssetAtPath<UnityEngine.Object>(GetRelativeAssetsPath(file));Debug.Log("替换的对象 " + file, obj);}startIndex++;if (isCancel || startIndex >= files.Length){EditorUtility.ClearProgressBar();EditorApplication.update = null;startIndex = 0;Debug.Log("更新数据结束");}};}void OnCreateMetaData(string srcPath, string tarPath){string srcMeta = AssetDatabase.GetTextMetaFilePathFromAssetPath(srcPath);string tarMeta = AssetDatabase.GetTextMetaFilePathFromAssetPath(tarPath);string[] srcFile = File.ReadAllLines(srcMeta);string[] tarFile = File.ReadAllLines(tarMeta);List<string> smList = new List<string>();List<string> tempList = new List<string>();TextureImporter srcImp = TextureImporter.GetAtPath(srcPath) as TextureImporter;TextureImporter tarImp = TextureImporter.GetAtPath(tarPath) as TextureImporter;foreach (var spMD in tarImp.spritesheet){tempList.Add(spMD.name);}foreach (var spMD in srcImp.spritesheet){if (tempList.Contains(spMD.name)){smList.Add(spMD.name);//Debug.Log("匹配SpriteSheetMeta " + spMeta.name);}}assetDic = new Dictionary<string, AssetData>();foreach (var key in smList){AssetData data = new AssetData();data.name = key;assetDic.Add(key, data);foreach (var srcStr in srcFile){if (srcStr.IndexOf(key) >= 0){var str = srcStr.Trim();var spMetaId = str.Substring(0, str.IndexOf(":"));//Debug.LogFormat("src ==> {0} {1}", key, spMetaId);if (string.IsNullOrEmpty(assetDic[key].src)){assetDic[key].src = spMetaId;}}}foreach (var tarStr in tarFile){if (tarStr.IndexOf(key) >= 0){var str = tarStr.Trim();var spMetaId = str.Substring(0, str.IndexOf(":"));//Debug.LogFormat("tar ==> {0} {1}", key, spMetaId);if (string.IsNullOrEmpty(assetDic[key].tar)){assetDic[key].tar = spMetaId;}}}if (string.IsNullOrEmpty(assetDic[key].src) || string.IsNullOrEmpty(assetDic[key].tar)){assetDic.Remove(key);}}//foreach (var meta in assetDic)//{//    var data = meta.Value;//    Debug.LogFormat("meta ==> name:{0} src:{1} tar:{2}", data.name, data.src, data.tar);//}}void OnUpdateData(string file){var allInfo = File.ReadAllLines(file);for (int i = 0; i < allInfo.Length; i++){var str = allInfo[i];if (str.IndexOf(srcGUID) >= 0){if (str.IndexOf("guid") >= 0){// 替换旧的GUIDstr = str.Replace(srcGUID, tarGUID);// 替换旧的fileIDif (str.IndexOf("fileID") >= 0){foreach (var meta in assetDic){if (str.IndexOf(meta.Value.src) >= 0){str = str.Replace(meta.Value.src, meta.Value.tar);}}}}allInfo[i] = str;}}File.WriteAllLines(file, allInfo);}static string GetRelativeAssetsPath(string path) {return "Assets" + Path.GetFullPath(path).Replace(Path.GetFullPath(Application.dataPath), "").Replace('\\', '/');}public class AssetData{public string name;public string src;public string tar;}
}

Unity 合图插件 ==》【支持原图集更新】相关推荐

  1. vue如何使用原生js写动画效果_原生js写一个无缝轮播图插件(支持vue)

    轮播图插件(Broadcast.js) 前言:写这个插件的原因 前段时间准备用vue加上网易云的nodejs接口,模拟网易云音乐移动端.因为想自己写一遍所有的代码以及加固自己的flex布局,所以没有使 ...

  2. html怎么引轮播图插件,原生js写一个无缝轮播图插件(支持vue)

    轮播图插件(Broadcast.js) 前言:写这个插件的原因 前段时间准备用vue加上网易云的nodejs接口,模拟网易云音乐移动端.因为想自己写一遍所有的代码以及加固自己的flex布局,所以没有使 ...

  3. 利用Unity自带的合图切割功能将合图切割成子图

    转载的,牛人无处不在,我还太渺小 虽然目前网上具有切割合图功能的工具不少,但大部分都是自动切割或者根据plist之类的合图文件切割的, 这种切割往往不可自己微调或者很难维调,导致效果不理想. 今天逛贴 ...

  4. html5移动端轮播图特效,支持移动端的纯js轮播图插件awesome-slider

    awesome-slider是一款支持移动端的纯js轮播图插件.该轮播图插件支持任何HTML标签,可以自定义分页标签和Loading效果,支持在前端框架如react中使用. 使用方法 安装: /* y ...

  5. 11.11 大促背后的秘密——智能合图

    刚刚过去的"11.11京东全球好物节"累计下单金额超2044亿元.继今年年中"618十六周年庆"累计下单金额创下2015亿元之后,京东在年末11.11再次打造实 ...

  6. html5carousel图片轮播,jQuery响应式轮播图插件VM Carousel

    插件描述:VM Carousel是一款jQuery响应式轮播图插件.该jquery轮播图插件支持自动播放模式,支持动态改变图片尺寸,支持居中模式,以及无限循环等. 使用方法 在页面中引入jquery. ...

  7. HTML5超炫全屏焦点图插件

    在网站开发过程中,特别是前端开发这块,经常会使用到很多图片滑块动画,也就是一些基于jQuery和HTML5的焦点图插件.本文将为大家收集10个超赞的jQuery图片滑块动画,这些现成的jQuery插件 ...

  8. jQuery百叶窗轮播图插件

    下载地址 这款jQuery图片轮播插件提供了多种百叶窗风格的图片切换方式,每一种百叶窗风格都是随机产生的.另外这款jQuery多百叶窗风格切换焦点图插件支持悬浮文字描述,同时也支持自动播放.相信它可以 ...

  9. python动态横道图_jQuery甘特图/日程图/横道图/插件

    基于JQ的一款灵活高效,支持自定义拓展的甘特图/日程图插件 支持月/周/小时等显示方式 支持拖动改变时间 展开与收起 添加/删除,刷新 节假日高亮 clicked,dblClicked,changed ...

最新文章

  1. 口袋操作系统_可以装进口袋的主机要有多小?驰为LarBox迷你主机入手体验
  2. 世界首份博客报纸问世
  3. A 子类继承父类,子类的构造函数会覆盖父类的构造函数
  4. SQLite、MySQL和PostgreSQL 三种关系数据库比较
  5. 一周最新示例代码回顾 (4/2–4/8)
  6. dubbo服务执行过程源码分析
  7. 分享一下淘宝iData技术嘉年华的几点感触
  8. easyUI的时间控件
  9. C#调用谷歌翻译API
  10. 网络图怎么画?简单专业的网络图绘制方法
  11. git push报错: Push rejected
  12. Elasticsearch 解决集群 Yellow 与 Red 的问题
  13. springboot与mybatis整合
  14. 武汉大学《GNSS、INS和激光雷达的紧密耦合预积分,用于城市环境中的车辆导航》
  15. 千牛计算机使用方法,如何在电脑千牛中打开移动旺店
  16. 【正点原子STM32连载】第四章 STM32初体验 摘自【正点原子】MiniPro STM32H750 开发指南_V1.1
  17. css超链接中的下划线设置
  18. iloc和loc的区别
  19. 杰理之杰理音箱方案选型【篇】
  20. 快鲸智慧社区系统三大重点功能盘点

热门文章

  1. shell中的kill命令
  2. 二叉树的层次遍历(C++)
  3. c语言getline函数什么意思,getline函数(精华版)详解
  4. LeetCode - 合并两个有序链表
  5. 我想带你去浪漫的土耳其(PythonMatlab实现)
  6. visio堆叠正方形形成框图
  7. ChatGPT爆火:AI崛起,这些职场人的机遇到了?
  8. 纯代码计算不等高cell
  9. Docker学习 一
  10. HTML-设置横向滚动条