UGUI中动态加载图集中的图片(转)


前言

图集打包的好处都有啥?不管你是新手还是大神,要是项目中ui图片很多,特别是小图很多,需要运行时动态加载或切换Image中的sprite的时候,基本上都会选择打包成图集这种解决方案。

图集的好处有很多,我就说一下主要的两点,其它的大家可以问度娘:

  • 减少DrawCall,虽然新版Unity没有DrawCall显示了,但也引入了Batches和SetPass calls这两个数值,实际上都是指图片渲染的次数(这样说可能有点不严谨,但代表这个意思)。每张单独的图片占用一次渲染,假如10张小图,就10次渲染了,但如果这10张小图打到一个图集里面,那么系统只需渲染1次即可,大大减少系统负担
  • 减轻IO负担,假如你每次加载图片的时候还是用Load()之类的通过操作IO读写的方式来加载的话,那么每次加载图片都需要进行一次IO读写,而使用图集之后只需一次读取图集到内存中,那么每次加载图片就只需从内存中取出,大大减轻系统负担,当然,这是舍弃内存保速度的解决方案。

 

图集打包工具我推荐大家用TexturePacker,虽说用unity自带SpritePacker也可以,功能也差不多,但我个人认为自带的用起来并不顺手。关于TexturePacker软件的使用教程,可以查看我之前发表过的文章(请务必使用TexturePacker4.8.1版的教程),链接:http://www.tinkingli.com/?p=302

 

代码解读

代码十分简单,主要就两个.cs文件AtlasPackerEditor.cs和SpriteData.cs。

SpriteData.cs

这个类是继承自MonoBehaviour的,大家只需要获取到这个组件的引用,调用GetSprite()方法即可

[ExecuteInEditMode()]
public class SpriteData : MonoBehaviour
{
    public Sprite[] sprites;
 
    private Dictionary<string, int> Index = new Dictionary<string, int>();
    private int indexS = 0;
 
    public Sprite[] SetSP
    {
        set
        {
            sprites = value;
        }
    }
 
    public Sprite GetSprite(string spName)
    {
        if (Index.Count == 0)
        {
            for (int i = 0; i < sprites.Length; i++)
            {
                Index.Add(sprites[i].name, i);
            }
        }
        if (Index.TryGetValue(spName, out indexS))
        {
            return sprites[indexS];
        }
        return null;
    }
}

 

而另一个类是Editor类,需要放在Editor文件下

    /// <summary>
    /// 图集图片的路径
    /// </summary>
    public static string AtlasPath = "Assets/codeandweb.com/Example/SpriteSheet";
    /// <summary>
    /// 打包后预制体存放路径
    /// </summary>
    public static string UISharePath = "Assets/codeandweb.com/Example/";

使用前请修改AtlasPath和UISharePath两个路径为自定义路径

    [MenuItem("渐渐/打包所有图集")]
    public static void PackAtlas()
    {
        string[] _patterns = new string[] { "*.png" };
        string multiTag = "_multi_";
        Dictionary<string, List<string>> _allFilePaths = new Dictionary<string, List<string>>();
        string _tempName = String.Empty;
        foreach (var item in _patterns)
        {
            string[] _temp = Directory.GetFiles(AtlasPath, item, SearchOption.AllDirectories);
            foreach (string path in _temp)
            {
                System.IO.FileInfo _fi = new System.IO.FileInfo(path);
                _tempName = _fi.Name.Replace(_fi.Extension, "").ToLower();
                if (!_tempName.Contains(multiTag))
                {
                    _tempName = "atl_" + _tempName;
                }
                else
                {
                    _tempName = "atl_"+ _tempName.Split(multiTag)[0];
                }
                if (!_allFilePaths.ContainsKey(_tempName))
                {
                    _allFilePaths.Add(_tempName, new List<string>());
                }
                _allFilePaths[_tempName].Add(path);
            }
        }
 
        foreach (var item in _allFilePaths)
        {
            CreateAtlasPrefab(item.Key, item.Value.ToArray());
        }
    }

此处遍历AtlasPath文件夹下的所有.png图片(可以根据项目需要添加或修改为.jpg等),然后用于创建图集,大家应该发现,此处用到一个关键词“_multi_”,这个适用于多图片图集,后面会介绍用法

    //创建图集预设
    public static void CreateAtlasPrefab(string atlasName, string[] atlPath)
    {
        List<Sprite> _texs = new List<Sprite>();
        foreach (string path in atlPath)
        {
            _texs.AddRange(AssetDatabase.LoadAllAssetsAtPath(path).OfType<Sprite>().ToArray());
        }
        if (null != _texs)
        {
            GameObject _go = new GameObject();
            _go.name = atlasName;
            SpriteData _spData = _go.AddComponent<SpriteData>();
            _spData.SetSP = _texs.ToArray();
            string path1 = UISharePath + atlasName + ".prefab";
            GameObject temp = PrefabUtility.CreatePrefab(path1, _go);
 
            #region 添加ab标记
            //此处自动添加ab标记
            //如果加载方式是Resources.load()等不需要ab标记的可以把此处注释掉
            AssetImporter importer = AssetImporter.GetAtPath(path1);
            if (importer == null || temp == null)
            {
                Debug.LogError("error: " + path1);
                return;
            }
            importer.assetBundleName = "ui-share.unity3d";
 
            #endregion
 
            GameObject.DestroyImmediate(_go);
            EditorUtility.SetDirty(temp);
            AssetDatabase.SaveAssets();
        }
        Resources.UnloadUnusedAssets();
        AssetDatabase.Refresh();
    }

此处我添加了一个ab标记,因为在我项目中所有用这个方法打包的都是UI的Share包,如果不了解或不需要用到AssetBundle的朋友,请务必把这个注释掉

 

打包图集预设

1
此处是放置图集文件的地方,然后把AtlasPackerEditor.cs里的AtlasPath路径设置为此处。

然后设置UISharePath为图集预制体存放路径
2
点击渐渐->打包所有图集
3
即可看到图集已经自动打包好了

多图片图集使用方法:假如你们UI的图集非常大,2048*2048的图片都放不下(unity限制2048),需要两张或以上的图集图片,这时候图片的命名只需为:UI_multi_1,UI_multi_2,

UI_multi_3以此类推,最后打包只会出现一个预制体,这样加载的时候就像单张图集那样加载了。

 

动态加载

1、首先,我们需要加载atl_开头的预制体,你可以把导出路径放在Resources文件夹下,这样就可以通过调用Load()来加载了,你也可以像我那种通过AssetBundle的方式来加载

2、Load出来的prefabs并不需要像一般预制体那样实例化到场景,直接GetComponent<SpriteData>()即可获得SpriteData的引用,我们保存这个引用即可

3、当需要加载其中的图片的时候调用GetSprite(spriteName)即可

 

此处各位可以做一个LoadHelper来保存SpriteData引用和自动加载,各位也可以根据需求改成异步加载和异步获取,此处不作介绍

public static class LoadSpriteHelper
{
    //所有图集名
    public const string Atl_UI = "UI";
    public const string Atl_Scene = "Scene";
    public const string Atl_Role = "Role";
 
    /// <summary>
    /// SpriteData缓存
    /// </summary>
    private static Dictionary<string, SpriteData> spriteDates = new Dictionary<string, SpriteData>();
 
    /// <summary>
    /// 获取图片(自动加载缺失的图集)
    /// </summary>
    /// <param name="atlName"></param>
    /// <param name="spriteName"></param>
    /// <returns></returns>
    public static Sprite LoadSprite(string atlName, string spriteName)
    {
        if (!spriteDates.ContainsKey(atlName))
        {
            GameObject atl = null;//todo 此处加载atl_开头的预制体
            spriteDates.Add(atlName, atl.GetComponent<SpriteData>());
        }
        return spriteDates[atlName].GetSprite(spriteName);
    }
}

 

下载:

GitHub(国外):

ET模组仓库: https://github.com/egametang/ET-Modules.git

本人工具仓库:https://github.com/HealthyChina/HealthyResource.git

Gitee(国内):

本人工具仓库:https://gitee.com/healthyZ/HealthyResource.git


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM