Unity - 模拟Sprite Packer合并多个Sprite

Unity - 模拟Sprite Packer合并多个Sprite


现在做一个卡牌Demo,由于没有沟通好,动画师为了做Anima2D动画方便,把角色每个部位拆分成单个Sprite,这样肯定是不行的,不仅加大了容量,运行时效率也不高。但是由于动画已经做好了,再回去手动合并再修改Anima2D非常麻烦,只好让程序实现一个快捷工具,把单个的Sprite合成一张大图集,把与单个Sprite绑定的Anima2D数据迁移到大图集。忙了一天总算弄好了,现在记录一下。

Sprite Packer

把Sprite合并成图集其实是Unity内置的功能——Sprite Packer,Sprite Packer会把相同Packing Tag的Sprite合并成大图集,我们要做的就是模拟Sprite Packer。简单的一个思路是:把要打包的Sprite放到一个文件下;得到所有单独的Sprite;生成单独的Texture;打包;切分Texture。

using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.IO;
using System.Linq;

namespace Utility
{
    public class AtlasTest
    {
        [UnityEditor.MenuItem("SpriteAtlas/CreateAtlas")]
        public static void CreateAtlas()
        {
            string spritePath = string.Empty;
            spritePath = EditorUtility.OpenFolderPanel("选择文件夹", "", "");

            List<Sprite> sprites = new List<Sprite>();
            List<Texture2D> newTexs = new List<Texture2D>();
            List<string> extensions = new List<string>() { ".png", ".jpg", ".psd" };
            // 找出单独的sprite
            string[] files = Directory.GetFiles(spritePath, "*.*", SearchOption.AllDirectories)
                .Where(s => extensions.Contains(Path.GetExtension(s).ToLower())).ToArray();
            for (int i = 0; i < files.Length; i++)
            {
                string relativePath = files[i].Substring(files[i].IndexOf("Asset")).Replace('\\', '/');
                Object[] newSprites = AssetDatabase.LoadAllAssetsAtPath(relativePath);
                for (int j = 0; j < newSprites.Length; j++)
                {
                    if ((newSprites[j] as Sprite) != null)
                        sprites.Add(newSprites[j] as Sprite);
                }
            }
            // 把单独的sprite变化成texture
            for (int i = 0; i < sprites.Count; i++)
            {
                Rect t_Rect = sprites[i].rect;
                Texture2D t_SourceTex = sprites[i].texture;
                string pathStr = AssetDatabase.GetAssetPath(sprites[i].texture);
                // 开启源Spirte的可读
                TextureImporter t_Importer = AssetImporter.GetAtPath(pathStr) as TextureImporter;
                t_Importer.isReadable = true;
                t_Importer.SaveAndReimport();
                AssetDatabase.ImportAsset(pathStr);
                // 裁剪出新的Texture
                Color[] t_Colors = t_SourceTex.GetPixels((int)t_Rect.x, (int)t_Rect.y, (int)t_Rect.width, (int)t_Rect.height);
                newTexs.Add(new Texture2D((int)t_Rect.width, (int)t_Rect.height));
                newTexs[i].SetPixels(t_Colors);
            }
            // 打包成Atlas
            string atlasPath = spritePath + "/AllAtlas.png";
            string atlasRelativePath = atlasPath.Substring(atlasPath.IndexOf("Assets"));
            Texture2D atlasTex = new Texture2D(1024, 1024);
            Rect[] atlasRects = atlasTex.PackTextures(newTexs.ToArray(), 1, 4096);
            SpriteMetaData[] atlasSheets = new SpriteMetaData[atlasRects.Length];
            File.WriteAllBytes(atlasPath, atlasTex.EncodeToPNG());
            // 设置Atlas的sprite
            for (int i = 0; i < atlasSheets.Length; i++)
            {
                SpriteMetaData t_Meta = new SpriteMetaData();
                t_Meta.name = sprites[i].name;
                t_Meta.rect = atlasRects[i];
                t_Meta.rect.Set(
                    t_Meta.rect.x * atlasTex.width,
                    t_Meta.rect.y * atlasTex.height,
                     t_Meta.rect.width * atlasTex.width,
                     t_Meta.rect.height * atlasTex.height
                );
                t_Meta.alignment = 9;
                Rect t_Rect = sprites[i].rect;
                t_Meta.pivot = new Vector2(sprites[i].pivot.x / t_Rect.width, sprites[i].pivot.y / t_Rect.height);
                atlasSheets[i] = t_Meta;
            }
            // 设置Atlas Texture属性
            TextureImporter atlas_Importer = AssetImporter.GetAtPath(atlasRelativePath) as TextureImporter;
            atlas_Importer.textureType = TextureImporterType.Sprite;
            atlas_Importer.spriteImportMode = SpriteImportMode.Multiple;
            //imp.textureCompression = TextureImporterCompression.Uncompressed;
            atlas_Importer.mipmapEnabled = false;
            atlas_Importer.spritesheet = atlasSheets;
            atlas_Importer.SaveAndReimport();

            AssetDatabase.ImportAsset(atlasRelativePath);
            AssetDatabase.Refresh();
        }
    }
}

结果:两张Atlas和一个单独的Sprite合并成最后一张大图集,其实前两张Atlas已经是合并过一次的了
Unity - 模拟Sprite Packer合并多个Sprite_第1张图片

Anima2D数据迁移

这里就做简单的数据的位置偏移就可以了,伪代码如下。

Vector2 offset = new Vector2(newSprite.rect.x - oldSprite.rect.x, newSprite.rect.y - oldSprite.rect.y);
spriteMesh.sprite = newSprite;
spriteMeshData.pivotPoint += offset;
for (int k = 0; k < spriteMeshData.vertices.Length; k++)
	spriteMeshData.vertices[k] += offset;
SpriteMeshUtils.UpdateAssets(spriteMesh, spriteMeshData);
AssetDatabase.SaveAssets();
AssetDatabase.Refresh();

你可能感兴趣的:(Unity,Editor)