对于unity NGUI动态加载的简单总结,供大家学习、参考和交流。在NGUI中提供了很简单也很方便的UIAtlas,它主要是把DrawCall改进和优化,将许多图片整合在一张贴图上,由于UNITY3D本身就有简单易用的缘故,因此只是需要用原生的GUI很容易忽视DrawCall的问题,所以NGUI为了改进,才有了UIAtlas。当然NGUI还做了很多优化。

这里主要还是介绍如何利用UISprite来动态的加载图片。NGUI所提供的UIAtlas虽然好用,但只能在Editor内生成贴图和prefab以供UISprite使用。为了能够让游戏资源与游戏本体尽可能的分离,特别是游戏资源需要动态更新的情况。很多时候,都需要动态加载,动态设置UIAtlas。

这里主要介绍2个方法。

方法1:直接在代码中创建和设置UIAtlas并对UISprite进行显示。这种方法可以对任何零散的贴图进行加载,但缺点是浪费DrawCall,主要应用在特别零散的贴图资源上。

  1. public class ImageLoader : MonoBehaviour {
  2. //需要加载动态图片的对象
  3. public UISprite m_img;
  4. //自用的Atlas
  5. private UIAtlas m_uiAtlas;
  6. /// <summary>
  7. /// 加载的贴图
  8. /// </summary>
  9. /// <param name="tex">Tex.</param>
  10. public void ImageLoad(Texture2D tex)
  11. {
  12. if(tex == null)
  13. {
  14. return;    
  15. }
  16. if(tex.name == m_img.spriteName)
  17. {
  18. return;    
  19. }
  20. //准备对象和材质球
  21. if(m_uiAtlas == null)
  22. {
  23. Material mat;
  24. Shader shader = Shader.Find("Unlit/Transparent Colored");
  25. mat = new Material(shader);
  26. m_uiAtlas = this.gameObject.AddComponent<UIAtlas>();
  27. m_uiAtlas.spriteMaterial = mat;
  28. }
  29. //设定贴图
  30. m_uiAtlas.spriteMaterial.mainTexture = tex;
  31. m_uiAtlas.coordinates = UIAtlas.Coordinates.Pixels;
  32. //为对应UISprite接口,给Atlas加对象
  33. UIAtlas.Sprite sprite = new UIAtlas.Sprite();
  34. sprite.name = tex.name;
  35. sprite.outer = sprite.inner = new Rect(0f, 0f, tex.width, tex.height);
  36. m_uiAtlas.spriteList.Clear();
  37. m_uiAtlas.spriteList.Add(sprite);
  38. //设置完成
  39. m_img.atlas = m_uiAtlas;
  40. m_img.spriteName = tex.name;
  41. }
  42. }

方法2:将整个UIAtlas及其贴图打包,而后形成资源,驻留在内存中(仅仅是指向资源的指针),UNITY3D会根据引用来确定贴图是否直接放实际内存中。这种方法更适合ICON之类有规律可以配置整合的资源。缺点是需要维护。


  1. //从资源文件夹加载打包成assetBundle的ICON资源文件
  2. private IEnumerator LoadResIcon()
  3. {
  4. //准备好资源们
  5. string strFormat = ResourcePath.GetPath() + "UI/{0}";
  6. string strFilePath = "";
  7. for(int i = 0 , nMax = GameConfig.Instance.IconSet.strIcons.Length; i < nMax ; i++)
  8. {
  9. string strAssetName = GameConfig.Instance.IconSet.strIcons;
  10. strFilePath = string.Format(strFormat, strAssetName);
  11. WWW tmp_www = null;
  12. try
  13. {
  14. tmp_www = new WWW(strFilePath);
  15. }
  16. catch
  17. {
  18. tmp_www = null;
  19. }
  20. if(tmp_www==null)
  21. {
  22. continue;
  23. }    
  24. yield return tmp_www;
  25. if(tmp_www.error !=null)
  26. {
  27. tmp_www.Dispose();
  28. tmp_www = null;
  29. yield break;
  30. }
  31. AssetBundle tmp_assetBundle = tmp_www.assetBundle;
  32. tmp_www.Dispose();
  33. tmp_www = null;
  34. UIAtlas atlas = tmp_assetBundle.Load(strAssetName,typeof(UIAtlas)) as UIAtlas;
  35. tmp_assetBundle.Unload(false);
  36. GameConfig.Instance.IconSet.SaveUIAtlas(i, atlas);
  37. }
  38. yield return null;
  39. }

  40. 管理UIAtlas

  41. public class IconSet
  42. {
  43. public string[] strIcons = 
  44. {
  45. "A1_Atlas",
  46. "A2_Atlas",
  47. "A3_Atlas",
  48. };
  49. public UIAtlas[] m_AtlasData;
  50. Dictionary<string, int> m_dicIcon;
  51. public IconSet()
  52. {
  53. m_AtlasData = new UIAtlas[strIcons.Length];
  54. m_dicIcon = new Dictionary<string, int>();
  55. }
  56. //保存Atlas的完整信息
  57. public void SaveUIAtlas(int nIndex, UIAtlas UIvalue)
  58. {
  59. m_AtlasData[nIndex] = UIvalue;
  60. foreach (string iconNames in UIvalue.GetListOfSprites())
  61. {
  62. m_dicIcon[(string)iconNames.Clone()] = nIndex;//将所有的ICONNAME信息记录并且绑定成索引,以便查找
  63.         }
  64. }
  65. //根据ICONNAME找出对应UIATLAS
  66. public UIAtlas FindAtlasBySpriteName(string name)
  67. {
  68. int nAtlasIndex = 0;
  69. if (m_dicIcon.TryGetValue(name, out nAtlasIndex))
  70. {
  71. return m_AtlasData[nAtlasIndex];
  72. }
  73. return null;
  74. }
  75. }

实际使用的范例:

  1. //设置显示对象
  2. UISprite sprite = this.GetComponent<UISprite>();
  3. sprite.atlas = GameConfig.Instance.IconSet.FindAtlasBySpriteName("Icon001");
  4. sprite.spriteName = "Icon001";

总结:
以上两种方法基本能够应对大部分UI的现实问题,ImageLoader本身传入的是Texture2D,所以,即便是RenderTexture也没问题,都能与NGUI和谐相处。加以扩展的话,就是让另一个摄像机导出的东西和当前NGUI摆的UI结合。