美文网首页
Unity 导入包含.xml的外部图集并自动切片

Unity 导入包含.xml的外部图集并自动切片

作者: hh5460 | 来源:发表于2019-12-07 18:46 被阅读0次

    我不知道从哪里搞到了一张图集tiles_sheet.png,然后它有一个同名文件tiles_sheet.xml,明显这个xml保存的是这张图集的所有切片信息...
    但是我也不确定是不是用Texturepacker导出的,所以我也没用Texturepacker importer来导入它,因为自己通过代码切割一下也很方便
    先晒出图集信息内容供参考:

    tiles_sheet.png tiles_sheet.xml

    如果直接将这两个东西导入到unity中,那么xml是无效的,只能得到一整张的切片,如果这时候手动去切,或者使用unity自带的 'Sprite Editor'去自动切割的话也是有问题的,因为这些小切片很多像素都是连在一起的,没有办法精确的切开,那既然已经有了xml文件,那肯定还是得利用上最好了...

    先说以下3个关键的大坑

    1.由于unity定义贴图像素坐标是以左上角为原点的,但是大部分第三方打包图集工具都是以左下角为原点
    2.由于1的原因,导致实际上每个切片数据的y值都要重新计算,但是重新计算却需要得到这场图片的宽高(有高就行),但是导入时候图集的宽高并不能通过简单的API直接得到
    3.想到通过AssetDatabase.LoadAssetAtPath去加载这张图,然后就能获取到长宽了,但是我们这个自动切片处理过程是在Import的时候执行的,这个时候这张图默认是还没有导入到AssetDatabase中,也就是说AssetDatabase.LoadAssetAtPath是无法加载到这张图的...最后为了不引入其他不必要的程序集模块,最终是通过反射来获取到的

    代码如下
    using UnityEngine;
    using UnityEditor;
    using System.IO;
    using System.Xml;
    using System.Reflection;
    
    public class AutoSliceSpriteSheetWithXML : AssetPostprocessor
    {
        private void OnPreprocessTexture()
        {
            //获取各种路径
            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);
    
            //检测是否存在同名的.xml文件,不存在则不用左处理
            if (File.Exists(xml_fullPath))
            {
                //根据XML参数进行自动进行图片切割
                XmlDocument doc = new XmlDocument();
                //加载xml文件
                doc.Load(xml_fullPath);
    
                //从xml中读取第一个节点,该节点imagePath是对应图片的名字,再次确定查看是否和图片的名字匹配
                string target_path = (doc.FirstChild as XmlElement).GetAttribute("imagePath");
                if (target_path != fileName_without_extension + extension)
                {
                    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];
    
                //遍历所有节点信息
                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"));
    
                    //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;
                }
                //将所有精灵切片信息数据绑定到TextureImporter上完成设置
                importer.spritesheet = spriteMetaDatas;
            }
        }
    }
    
    

    此时直接将图片和xml文件拖到unity中,ok,已经按照xml中的配置信息,自动完成切片了...


    切片后 切片后

    相关文章

      网友评论

          本文标题:Unity 导入包含.xml的外部图集并自动切片

          本文链接:https://www.haomeiwen.com/subject/nlgugctx.html