Unity3D UGUI圖集打包與動態使用(TexturePacker)

  • 製作圖集的好處:衆所周知CPU是用來處理遊戲的邏輯運算的,而GPU是用來處理遊戲中圖像的。在GPU中,我們要繪製一個圖像需要提交圖片(紋理)到顯存,然後再進行繪製(在這個過程中會產生一次DrawCall),也就是說我們要繪製100張圖片就要產生100次DrawCall.顯然這是非常消耗性能的。這是製作圖集的好處就顯而易見了:

  1. ①、減少性能消耗,提高處理效率

  2. ②、可以歸類不同模塊的圖片

  3. ③、一次加載或者卸載完成多圖片的處理,提高了運行效率

  • 打包圖集需要的工具

我們經常聽說是在NGUI中打包圖集,在用UGUI時,我們也需要將一個個小圖打包成圖集,以減小Drawcall(類似coco2d-x一樣,打包成圖集一次性加載以內存換取圖片讀取效率),UGUI打包並使用圖集有兩種方法:

  1. 一種是使用系統自帶的打包工具SpritePacker;
  2. 一種是使用外部插件TexturePacker打包圖片並使用;

關於第一種方法有另一個文章爲大家講解,另一種熟悉的方法用TexturePacker工具打包,也是本文下面要講解的本文所使用的是Unity 2018.2.5f1 (64-bit)版本,TexturePacker 5.2.0版本最新版本

1,先用TexturePacker打小圖打包成我們所需要的圖集,打包的格式要注意是"Unity - Texture2D sprite sheet"(有一些低版本的TP是沒有這個格式的。具體使用方法可以瀏覽下面的網站https://www.codeandweb.com/texturepacker/documentation

2、打包之後會有一個.png和一個.tpsheet,不用作其他修改,將這兩個文件放在工程資源中,這時從工程看這只是一張大圖,並不能算是一個圖集,使用裏面的小圖(這時雖然可以用unity3d自帶功能,手動對圖片進行裁剪,但裁剪的小圖大小基本是不對的)

2,接下來需要下載並導入一個Unity3d的插件,TexturePacker自己出的的一個插件(TexturePacker Importer),插件鏈接https://www.assetstore.unity3d.com/en/#!/content/16641,下載併成功導入之後,不用寫任何代碼,作任何操作,插件會自己根據.tpsheet,將剛纔打包好放進入工程的大圖自動裁剪成小圖,如下圖,打圖集點開

我們只需像使用單獨小圖一樣,將圖集裏的小圖拖進Source Image裏即可。這時我們還只能在編輯器裏設置使用圖集。

3.我們還需要在程序中動態加載圖集並使用圖集裏的小圖,纔算是完整的。unity3d 並沒有明確api說明我們如何用這種圖集,而常用Resources.Load()加載只能返回單獨的一個圖片紋理,所以我們用另一個方法 Resources.LoadAll();加載整一張圖集,此方法會返回一個Object[],裏面包含了圖集的紋理 Texture2D和圖集下的全部Sprite,所以我們就可以根據object 的類型和名字找到我們需要的某張小圖片。

4.下面寫了一個圖集紋理的管理類,去統一管理加載,是一個單例類,找個不被銷燬的GameObject綁定就行, 代碼比較簡單,用一個Dictionary按圖集的路徑過key將加載過的圖集緩存起來,需要時再由外部刪除掉,下面是代碼:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using UnityEngine.UI;
public class PPTextureManager : MonoBehaviour
{
    private static GameObject m_pMainObject;
    private static PPTextureManager m_pContainer = null;

    public static PPTextureManager getInstance()
    {
        if(m_pContainer == null)
        {
            m_pContainer = m_pMainObject.GetComponent<PPTextureManager>();
        }
        return m_pContainer;
    }
    //圖集的集合
    private Dictionary<string, Object[]> m_pAtlasDic;
    private void Awake()
    {
        initData();
    }
    private void initData()
    {
        PPTextureManager.m_pMainObject = gameObject;
        m_pAtlasDic = new Dictionary<string, Object[]>();
    }
    //加載圖集上的精靈
    public Sprite LoadAtlasSprite(string _spriteAtlasPath,string _spriteName)
    {
        //從緩存中查找圖集
        Sprite _sprite = FindSpriteFormBuffer(_spriteAtlasPath, _spriteName);
        if(_sprite == null)
        {
            Debug.LogError("查找的圖集爲空");
            Object[] _atlas = Resources.LoadAll(_spriteAtlasPath);//加載圖集
            m_pAtlasDic.Add(_spriteAtlasPath, _atlas);//將加載的圖集存到字典中(路徑對應圖片)
            _sprite = SpriteFormAtlas(_atlas, _spriteName);//從圖集中找到圖片
        }
        return _sprite;
    }
    //從圖集中找出sprite
    private Sprite SpriteFormAtlas(Object[] _atlas,string _spriteName)
    {
        for(int i = 0;i<_atlas.Length;i++)
        {
            if(_atlas[i].GetType()==typeof(UnityEngine.Sprite))
            {
                if(_atlas[i].name == _spriteName)
                {
                    return (Sprite)_atlas[i];
                }
            }
        }
        return null;
    }
    //從緩存中查找圖集並找出sprite
    private Sprite FindSpriteFormBuffer(string _spriteAtlasPath,string _spriteName)
    {
        if(m_pAtlasDic.ContainsKey(_spriteAtlasPath))
        {
            Object[] _atlas = m_pAtlasDic[_spriteAtlasPath];
            Sprite _sprite = SpriteFormAtlas(_atlas, _spriteName);
            return _sprite;
        }
        return null;
    }
    //刪除圖集緩存
    public void DeleteAtlas(string _spriteAtlasPath)
    {
        if(m_pAtlasDic.ContainsKey(_spriteAtlasPath))
        {
            m_pAtlasDic.Remove(_spriteAtlasPath);
        }
    }
}

接下來是如何使用:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class createTexture : PPTextureManager
{
    private Image image;
    private PPTextureManager ppTextureManage;
    public GameObject obj;
    // Use this for initialization
    void Start ()
    {
        obj = transform.Find("Image").gameObject;
        Sprite _sprite = PPTextureManager.getInstance().LoadAtlasSprite("Textures/common", "xiazai");
        image = obj.GetComponent<Image>();
        image.sprite = _sprite;

    }
}

這樣就可以動態使用圖集中的圖片啦!!!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章