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