using UnityEngine; using UnityEditor; using System.IO; using System.Xml; using System.Reflection; public class AutoSliceSpriteSheetWithXML : AssetPostprocessor { private void OnPreprocessTexture() { Debug.Log(1); //获取各种路径 string dataPath = Application.dataPath.Substring(0, Application.dataPath.LastIndexOf("/") + 1); string fullPath = dataPath + assetPath; string fileName_without_extension = Path.GetFileNameWithoutExtension(fullPath); string extension = Path.GetExtension(fullPath); string dirPath = Path.GetDirectoryName(fullPath); string xml_fileName = fileName_without_extension + ".xml"; string xml_fullPath = Path.Combine(dirPath, xml_fileName); string text = ""; //检测是否存在同名的.xml文件,不存在则不用处理 if (File.Exists(xml_fullPath)) { using (StreamReader reader = new StreamReader(xml_fullPath)) { //读一行 string line = reader.ReadLine(); while (line != null) { //如果这一行里面有abe这三个字符,就不加入到text中,如果没有就加入 if (line.IndexOf("version") >= 0 || line.IndexOf("adobe") >= 0) { ; } else { text += line + System.Environment.NewLine; } //一行一行读 line = reader.ReadLine(); } } //定义一个写入流,将值写入到里面去 string newPath = Path.Combine(dirPath, "new" + xml_fileName); using (StreamWriter writer = new StreamWriter(newPath)) { writer.Write(text); } Debug.Log(2); //根据XML参数进行自动进行图片切割 XmlDocument doc = new XmlDocument(); //加载xml文件 doc.Load(newPath); //从xml中读取第一个节点,该节点imagePath是对应图片的名字,再次确定查看是否和图片的名字匹配 Debug.Log(doc.FirstChild.ToString()); string target_path = (doc.FirstChild as XmlElement).GetAttribute("imagePath"); if (target_path != fileName_without_extension + extension) { Debug.Log(target_path.ToString()); throw new System.Exception("当前xml不是对应图片的xml..."); } //将导入对象转换为TextureImporter对象,注意,这里最好在前面加上判断是否是贴图文件 var importer = assetImporter as TextureImporter; //将贴图文件的类型修改由默认的单张精灵切片修改为多张精灵切片类型 importer.spriteImportMode = SpriteImportMode.Multiple; //通过反射获取导入图片的长和宽,为什么要获取长和宽,因为unity中以左上角为起点,大部分图集工具中是以左下角为原点,需要转换 object[] args = new object[2]; MethodInfo methodInfo = typeof(TextureImporter).GetMethod("GetWidthAndHeight", BindingFlags.NonPublic | BindingFlags.Instance); methodInfo.Invoke(importer, args); int texture_width = (int)args[0]; int texture_height = (int)args[1]; //获取所有的目标节点 var xml_nodes = doc.FirstChild.ChildNodes; //新建精灵切片数据集合 var spriteMetaDatas = new SpriteMetaData[xml_nodes.Count]; Debug.Log(xml_nodes.Count); //遍历所有节点信息 for (int i = 0; i < xml_nodes.Count; i++) { var node = xml_nodes[i]; XmlElement element = node as XmlElement; //获取节点中所带的信息 string sprite_name = element.GetAttribute("name"); float x = float.Parse(element.GetAttribute("x")); float y = float.Parse(element.GetAttribute("y")); float width = float.Parse(element.GetAttribute("width")); float height = float.Parse(element.GetAttribute("height")); Debug.Log(x); Debug.Log(y); Debug.Log(width); Debug.Log(height); Debug.Log("ok"); //re_y是指反向的y,因为unity处理贴图默认以左上角为原点,大部分图集工具中是以左下角为原点,从而导致y值错误,所以这里重新计算y正确的值 float re_y = texture_height - y - height; //新建精灵切片数据对象用于保存单个切片信息 SpriteMetaData one_SpriteMetaData = new SpriteMetaData(); one_SpriteMetaData.name = sprite_name; one_SpriteMetaData.alignment = (int)SpriteAlignment.Center; one_SpriteMetaData.rect = new Rect(x, re_y, width, height); spriteMetaDatas[i] = one_SpriteMetaData; } Debug.Log(3); //将所有精灵切片信息数据绑定到TextureImporter上完成设置 importer.spritesheet = spriteMetaDatas; Debug.Log(4); } } }
准备工作:
在Unity项目的AssetsEditor下新增AutoSliceSpriteSheetWithXML.cs,粘贴上述代码。
使用流程:
Flash的Sprite选中后进行“导出png序列”操作,将产生一个包含各帧内容的png文件以及用来描述如何切割为不同帧的xml文件。
在Unity对Project的AssetsEditorAutoSliceSpriteSheetWithXML进行右键,选择import new assert,先导入xml,而后导入png。
脚本将自动产生new前缀文件(可删除),并对png进行切割。
代码解析:
png导入后,脚本将寻找同目录下的同名xml文件,删除其中Flash版本号与注释,创建new前缀文件并写入。该操作目的是简化后续的first child与sibling处理。
而后遍历new前缀文件的SubTexture元素,根据其中坐标与长宽对png进行切割。需要注意的是Flash坐标的Y轴与Unity坐标的Y轴反向,因而切割时脚本需要重新计算其Y轴。