WP7 - XNA載入圖片策略與效能

  • 6723
  • 0
  • WP
  • 2011-11-02

WP7 - XNA載入圖片策略與效能

遊戲的圖片載入是最重要的功能,遊戲要玩的順暢,如何讓載入的速度變快也是一門學問,

在學習做2D遊戲的時候,上網搜尋遊戲素材,會發現很多素材都是如下圖

PeopleW

會將很多動作或是一堆物件做在同一張圖片上,而不是個別單一圖檔,

這不是為了網路下載素材方便才這樣做的,

而是因為遊戲載入受到硬體限制,所以希望載入的次數越少越好,

才會將相關的動作或是物品全都集合成一張圖,然後只要載入一次大圖就可以了。

 

雖然聽起來很合理,不過身為專業的阿宅工程師,不可以道聽塗說、人云亦云,

因此我們就來做做實驗吧!以下都是HD7實機測試。

首先產生100張200X200的png圖,

Small

再用此100張圖拼成一張200X200的大圖,載入程式碼如下:

   1: protected override void LoadContent() {
   2:     // Create a new SpriteBatch, which can be used to draw textures.
   3:     spriteBatch = new SpriteBatch(GraphicsDevice);
   4:  
   5:     Start();
   6:     LoadLarge();
   7:     End("LoadLarge cost");
   8:  
   9:     Start();
  10:     LoadSmallList();
  11:     End("LoadSmallList cost");
  12:  
  13: }
  14:  
  15: private void LoadLarge() {
  16:     Large = Content.Load<Texture2D>("Large");
  17: }
  18:  
  19: private void LoadSmallList() {
  20:     for (int i = 0; i < 100; i++) {
  21:         SmallList[i] = Content.Load<Texture2D>(string.Format("Small ({0})", i + 1));
  22:     }
  23: }

LoadLarge就是載入一張大圖,LoadSmallList就是載入100張小圖

執行六次得到的數據如下:

  平均
Large 193 182 195 227 249 228 212
SmallList 446 439 461 441 462 440 451

 

接著我們將兩個載入方式互換,先載入100張小圖,再載入一張大圖,得到如下數據

  平均
Large 182 181 170 184 183 181 180
SmallList 533 473 452 472 472 473 494

 

單位都是毫秒。

由此可知第一次載入會多花費一些時間,但是一張大圖的效率也比多張小圖好上2.1到2.7倍。

不過這是在所有小圖都可以放入大圖內的情形,但是效能差距還是挺明顯的。

 

知道載入次數對效能影響,再來試試看載入怎樣的大圖會最快,

由於手機載入圖片有最大2048X2048的限制,

所以我們測試的圖片大小分別為1000X1000、2000X500 以及 500X2000,

這三張圖的面積都一樣,理論上是可以塞一樣多的東西,數據如下:

  單個檔案大小
1000x1000 44 44 41 192K
2000x500 44 44 43 111K
500x2000 43 43 40 305K

測了三次就不想測了,結果是都一樣。

由上一個測試可以發現第一次載入都會有特別的時間消耗,

因此這次的測試在載入這三個圖之前有先載入一個小圖,

之後這三個圖的載入時間才會如此接近。

 

由上面第一個實驗可以知道載入速度看的是載入的次數,

而第二個實驗三個檔案大小不一樣,載入速度卻是一樣的,難道是看檔案面積?

其實載入的確除了看次數,另外一個就是看檔案大小,只是檔案大小不是看PNG的檔案,而是看XNA編譯後的XNB檔,

 

看了一下圖檔的大小,原本只有192K的圖檔,編譯成XNB檔後竟然有3.81MB,這是發生甚麼事??

XNA為了載入快速,會捨棄需要編碼的圖檔格式(如Jpg,Png等),全都轉成不用解碼可以直接讀取的檔案,

因此1000x1000的檔案大小就變成1000*1000*4(bytes) 大約等於3.81MB,而載入的速度就取決於XNB的大小。

 

甚麼?你說身為專業的阿宅工程師,不可以沒做實驗就認為XNB真的比較快??

那就來簡單做個實驗,關鍵程式碼如下:

 

   1: protected override void LoadContent() {
   2:     // Create a new SpriteBatch, which can be used to draw textures.
   3:     spriteBatch = new SpriteBatch(GraphicsDevice);
   4:  
   5:  
   6:     Start();
   7:     Small = Content.Load<Texture2D>("Small");
   8:     End("Small cost");
   9:  
  10:     Start();
  11:     Large = Content.Load<Texture2D>("Large");
  12:     End("L cost");
  13:  
  14:     Start();
  15:     Large2 = Texture2D.FromStream(GraphicsDevice, TitleContainer.OpenStream("Large2.png"));
  16:     End("L2 cost");
  17: }
  18:  

我們要從專案裡直接讀取檔案的話,要把檔案放到主專案(不是Content專案),

並且Build Action設定成None或是Content,

Copy to Output Directory設定為Copy always。

之後在程式裡可以用TitleContainer取得Stream,再藉由Texture2D.FromStream讀取進來,

數據如下:

  平均
xnb 166 162 153 162 163 163 161.5
png 964 920 895 920 919 920 923

由此可以看出xnb的確載入速度更快。

 

結論:

如果遊戲的物件沒有特殊需求,全都放在一張圖檔裡載入的速度是最快的。

而一張圖載入的速度和xnb檔案大小成正比。

xnb檔案大小直接從size決定。

 

這樣在用XNA做遊戲時對於資源的運用就會有個底了!