NGUI所見即所得之UIAtlasMaker , UIAtlas

 NGUI所見即所得之UIAtlasMaker , UIAtlas

 

        本文的重點就是要將NGUI把多張圖片打成一個圖集(Atlas)的原理和過程研究下,學習下Unity提供的api和NGUI寫的功能以及設計思想。

 

UIAtlas

       在介紹UIAtlasMaker之前先看下,先看下UIAtlasMaker的產物——UIAtlas,在創建Sprite的時候都要指定UIAtlas,下面先對UIAtlas的代碼:

C#代碼  收藏代碼
  1.        // Material used by this atlas. Name is kept only for backwards compatibility, it used to be public.  
  2. [HideInInspector][SerializeField] Material material;  
  3.   
  4. // List of all sprites inside the atlas. Name is kept only for backwards compatibility, it used to be public.  
  5. [HideInInspector][SerializeField] List<UISpriteData> mSprites = new List<UISpriteData>();  
  6.   
  7. // Size in pixels for the sake of MakePixelPerfect functions.  
  8. [HideInInspector][SerializeField] float mPixelSize = 1f;  
  9.   
  10. // Replacement atlas can be used to completely bypass this atlas, pulling the data from another one instead.  
  11. [HideInInspector][SerializeField] UIAtlas mReplacement;  
  12.   
  13.        // Whether the atlas is using a pre-multiplied alpha material. -1 = not checked. 0 = no. 1 = yes.  
  14. int mPMA = -1;  

      可以很驚奇的發現UIAtlas的成員變量竟然極其精簡,就只有:Material material;      UISpriteDatat的List mSprites;      每個像素的大小 mPixelSize 這個跟UIWidget的像素大小應該是類似的,  UIAtlas mReplacement; 這個目前只能望文生義,雖然知道是用來替換UIAtlas,但好像沒有發現哪裏會有用到,在UISprite的那裏只是選擇不同的UIAtlas而不是替換UIAtlas本身,就暫且擱置,   最後一個是mPMA這個是pre-multiplied的像素存儲技術,大致瞭解下,好像是把alpha的值存儲在每個顏色的RGB中去已達到節省存儲空間的技術,想要了解更多可以自行google下。

      接着看UIAtlas,接下來就是把屬性的{get,set} 以及幾個函數,也很簡單,主要就是屬性改變,就調用MakeAsDirty()函數,下面看下這個函數的前面一部分:

C#代碼  收藏代碼
  1. public void MarkAsDirty ()  
  2.     {  
  3. #if UNITY_EDITOR  
  4.         UnityEditor.EditorUtility.SetDirty(gameObject);  
  5. #endif  
  6.         if (mReplacement != null) mReplacement.MarkAsDirty();  
  7.   
  8.         UISprite[] list = NGUITools.FindActive<UISprite>();  
  9.   
  10.         for (int i = 0, imax = list.Length; i < imax; ++i)  
  11.         {  
  12.             UISprite sp = list[i];  
  13.   
  14.             if (CheckIfRelated(this, sp.atlas))  
  15.             {  
  16.                 UIAtlas atl = sp.atlas;  
  17.                 sp.atlas = null;  
  18.                 sp.atlas = atl;  
  19. #if UNITY_EDITOR  
  20.                 UnityEditor.EditorUtility.SetDirty(sp);  
  21. #endif  
  22.             }  
  23.         }  
  24.             ……  
  25.         }  

 可以看出這個函數其實就是更新以replacemet和this爲UIAtlas的UISprite的UIAtlas,就是這麼簡單。

 

 UISpriteData

       在UIAtlas中有GetSprite()和GetListOfSprites(),其中GetSprite返回的UISpriteData,讓人不得不猜想UISpriteData就是UISprite中的圖片,但其實它只是一個結構體:

C#代碼  收藏代碼
  1. public class UISpriteData  
  2. {  
  3.     public string name = "Sprite";  
  4.     public int x = 0;  
  5.     public int y = 0;  
  6.     public int width = 0;  
  7.     public int height = 0;  
  8.   
  9.     public int borderLeft = 0;  
  10.     public int borderRight = 0;  
  11.     public int borderTop = 0;  
  12.     public int borderBottom = 0;  
  13.   
  14.     public int paddingLeft = 0;  
  15.     public int paddingRight = 0;  
  16.     public int paddingTop = 0;  
  17.     public int paddingBottom = 0;  

       一看這些成員變量,就會感覺很熟悉,這不是就是UI組件的基本熟悉麼,可以進一步看下UIInspectorEditor界面,就更加確信了,而且Border其實用在SliceSprite的,至於Padding就是空白不顯示區域,而且x,y,width,height其實該圖片就是在UIAtlas上Rect區域。

 

      也就是說,UISpriteData根本沒有實際記錄圖片的像素信息,而只是記錄圖片在UIAtlas生成的那張大圖的座標,寬度和高度,以及圖片拉伸的一些信息(Border,Padding)。

 

UIAtlasMaker

      從前面的分析,可以大概知道UIAtlasMaker的原理:把多張圖片合併成一張大圖,記錄每張圖片的在生成的大圖的座標和大小。下面將使用介紹算法那種思路把UIAtlasMakder的工作流程描述清楚。

      在詳細介紹之前,UIAtlasMakder定義了UISpriteEntry這個類:

C#代碼  收藏代碼
  1. class SpriteEntry : UISpriteData  
  2.     {  
  3.         // Sprite texture -- original texture or a temporary texture  
  4.         public Texture2D tex;  
  5.           
  6.         // Whether the texture is temporary and should be deleted  
  7.         public bool temporaryTexture = false;  
  8.     }  

       只是在UISpriteData基礎上擴展了一個Texture2D tex的成員變量,那麼這個類到底做什麼用呢?通過分析代碼可以知道:UISpriteEntry是UISpriteData和Texture2D的中間體,是Texture2D和UISpriteData轉化的載體,就提過程下面會有引人。

 

 

UIAtlasMaker的工作流程:

1)選擇圖片or圖集,函數:void OnSelectAtlas (Object obj) 和 List<Texture> GetSelectedTextures ()

2)導入選擇圖片的Texture2D,函數:static List<Texture2D> LoadTextures (List<Texture> textures)

3)將Texture2D轉出UISpriteEntry,函數:static List<SpriteEntry> CreateSprites (List<Texture> textures) ,這個函數中包括了2)的步驟

3)打包成大圖片並生成UISpriteData,函數:static bool PackTextures (Texture2D tex, List<SpriteEntry> sprites),這個函數提供兩種打包方式:1.NGUI自己實現類UITextPacker,2.Unity3D提供的api

4)釋放UISpriteEntry,函數:static void ReleaseSprites (List<SpriteEntry> sprites),主要是通過NGUITools.Destroy銷燬紋理,最後調用Resources.UnloadUnusedAssets();,這個趁機告訴我們Unity中資源銷燬的方法,一個不能少哈。

C#代碼  收藏代碼
  1. static void ReleaseSprites (List<SpriteEntry> sprites)  
  2.     {  
  3.         foreach (SpriteEntry se in sprites)  
  4.         {  
  5.             if (se.temporaryTexture)  
  6.             {  
  7.                 NGUITools.Destroy(se.tex);  
  8.                 se.tex = null;  
  9.             }  
  10.         }  
  11.         Resources.UnloadUnusedAssets();  
  12.     }  

 

差不多就是這樣子,其他就是一些功能操作:add,replace,delete,udpate,extract。

 

       這樣看來,把UIAtlas分析清楚,掌握UIAtlasMaker的原理應該不難,當然裏面有很多細節,使用很多api:AssetDatabase,Texture,SelectedObject以及NGUI自己封裝的一些函數。

 

 

小結:

       UIAtlas雖然在使用NGUI過程中用的太多了,但是經過上面的分析,其實不是很難,個人覺得還沒有UIRoot(NGUI所見即所得之UIRoot)的難以駕馭,即使UIRoot很短很單一。這裏說下D.S.Qiu的關於快速學習的一點體會:古人有云,“工欲善其事,必先利其器”,NGUI最爲一個工具,要使用好它,就要充分掌握它, 換句話說就要懂它,當然還可以從中偷到很多師——功能的具體實現和代碼邏輯的設計,其實一直覺得我對細節都不求甚解,會用就可以走路了,又不用自己寫一個NGUI,當然細節都能掌握就更完美了。已經到凌晨一點了,先寫這麼多,有補充在加。

         如果您對D.S.Qiu有任何建議或意見可以在文章後面評論,或者發郵件([email protected])交流,您的鼓勵和支持是我前進的動力,希望能有更多更好的分享。

        轉載請在文首註明出處:http://dsqiu.iteye.com/blog/1967088

更多精彩請關注D.S.Qiu的博客和微博(ID:靜水逐風)

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