Unity3D-NGUI動態加載圖片


NGUI提供了很方便的UIAtlas,其主要作用是改進DrawCall,把眾多圖片整合在一張貼圖上,由於UNITY3D簡單易用的好處,所以只是用原生的GUI很容易忽視DrawCall的問題,所以NGUI為了改進,才有了UIAtlas。當然NGUI還做了很多優化。

這里主要還是介紹如何利用UISprite來動態的加載圖片。NGUI所提供的UIAtlas雖然好用,但只能在Editor內生成貼圖和prefab以供UISprite使用。為了能夠讓游戲資源與游戲本體盡可能的分離,特別是游戲資源需要動態更新的情況。很多時候,都需要動態加載,動態設置UIAtlas。

這里主要介紹2個方法。

方法1:直接在代碼中創建和設置UIAtlas並對UISprite進行顯示。這種方法可以對任何零散的貼圖進行加載,但缺點是浪費DrawCall,主要應用在特別零散的貼圖資源上。

public class ImageLoader : MonoBehaviour {
    
    //需要加載動態圖片的對象
    public UISprite m_img;
    //自用的Atlas
    private UIAtlas m_uiAtlas;
    /// <summary>
    /// 加載的貼圖
    /// </summary>
    /// <param name="tex">Tex.</param>
    public void ImageLoad(Texture2D tex)
    {
        if(tex == null)
        {
            return;    
        }
        if(tex.name == m_img.spriteName)
        {
            return;    
        }
        //准備對象和材質球
        if(m_uiAtlas == null)
        {
            Material mat;
            Shader shader = Shader.Find("Unlit/Transparent Colored");
            mat = new Material(shader);
            m_uiAtlas = this.gameObject.AddComponent<UIAtlas>();
            m_uiAtlas.spriteMaterial = mat;
        }
        //設定貼圖
        m_uiAtlas.spriteMaterial.mainTexture = tex;
        m_uiAtlas.coordinates = UIAtlas.Coordinates.Pixels;
        //為對應UISprite接口,給Atlas加對象
        UIAtlas.Sprite sprite = new UIAtlas.Sprite();
        sprite.name = tex.name;
        sprite.outer = sprite.inner = new Rect(0f, 0f, tex.width, tex.height);
        m_uiAtlas.spriteList.Clear();
        m_uiAtlas.spriteList.Add(sprite);
        //設置完成
        m_img.atlas = m_uiAtlas;
        m_img.spriteName = tex.name;
    }
}

 

方法2:將整個UIAtlas及其貼圖打包,而后形成資源,駐留在內存中(僅僅是指向資源的指針),UNITY3D會根據引用來確定貼圖是否直接放實際內存中。這種方法更適合ICON之類有規律可以配置整合的資源。缺點是需要維護。

 

//從資源文件夾加載打包成assetBundle的ICON資源文件
    private IEnumerator LoadResIcon()
    {
        //准備好資源們
        string strFormat = ResourcePath.GetPath() + "UI/{0}";
        string strFilePath = "";
        for(int i = 0 , nMax = GameConfig.Instance.IconSet.strIcons.Length; i < nMax ; i++)
        {
            string strAssetName = GameConfig.Instance.IconSet.strIcons[i];
            
            strFilePath = string.Format(strFormat, strAssetName);
            WWW tmp_www = null;
            try
            {
                tmp_www = new WWW(strFilePath);
            }
            catch
            {
                tmp_www = null;
            }
            if(tmp_www==null)
            {
                continue;
            }    
            yield return tmp_www;
            if(tmp_www.error !=null)
            {
                tmp_www.Dispose();
                tmp_www = null;
                yield break;
            }
            AssetBundle tmp_assetBundle = tmp_www.assetBundle;
            tmp_www.Dispose();
            tmp_www = null;
        
            UIAtlas atlas = tmp_assetBundle.Load(strAssetName,typeof(UIAtlas)) as UIAtlas;
            tmp_assetBundle.Unload(false);
            
            GameConfig.Instance.IconSet.SaveUIAtlas(i, atlas);
        }
        yield return null;
    }

管理UIAtlas

public class IconSet
{
    public string[] strIcons = 
    {
        "A1_Atlas",
        "A2_Atlas",
        "A3_Atlas",
    };
    public UIAtlas[] m_AtlasData;
    Dictionary<string, int> m_dicIcon;
    public IconSet()
    {
        m_AtlasData = new UIAtlas[strIcons.Length];
        m_dicIcon = new Dictionary<string, int>();
    }
    //保存Atlas的完整信息
    public void SaveUIAtlas(int nIndex, UIAtlas UIvalue)
    {
        m_AtlasData[nIndex] = UIvalue;
        foreach (string iconNames in UIvalue.GetListOfSprites())
        {
            m_dicIcon[(string)iconNames.Clone()] = nIndex;//將所有的ICONNAME信息記錄並且綁定成索引,以便查找
        }
    }
    //根據ICONNAME找出對應UIATLAS
    public UIAtlas FindAtlasBySpriteName(string name)
    {
        int nAtlasIndex = 0;
        if (m_dicIcon.TryGetValue(name, out nAtlasIndex))
        {
            return m_AtlasData[nAtlasIndex];
        }
        return null;
    }
}

實際使用的范例:

//設置顯示對象
UISprite sprite = this.GetComponent<UISprite>();
sprite.atlas = GameConfig.Instance.IconSet.FindAtlasBySpriteName("Icon001");
sprite.spriteName = "Icon001";

 

總結:

  以上兩種方法基本能夠應對大部分UI的現實問題,ImageLoader本身傳入的是Texture2D,所以,即便是RenderTexture也沒問題,都能與NGUI和諧相處。加以擴展的話,就是讓另一個攝像機導出的東西和當前NGUI擺的UI結合。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM