2014-04-12 20 views
0

爲了簡化長程序,我使用了一個包含List(aka tilemap)的Map類。在當前情況下,我的地圖必須具有2048x2048像素的維度,分爲16x16(像素)單元格,其中包括8層。這是總共(128x128個單元)乘以8 = 131072平鋪元素。如何在C#中高效地壓縮序列化的List <>

我最大的問題是當我序列化Map對象,並試圖用gzip壓縮它。然而,輸出文件是400 KB(或沒有gzip的640 KB),我認爲這是非常大的。我希望它小於40 KB,特別是我在這裏只使用整個tilemap中的Tile參考。該文件幾乎與我在整個場景中使用2048x2048大小一樣大,而使用拼貼的目的是使其尺寸非常小。

有什麼我完全誤解?有沒有一種非常有效的方法來壓縮列表<>?

下面你會發現代碼片段。我試圖在這些例子中保持超簡單,這在我的真實程序中相當複雜。

這裏的地圖類:

[Serializable()] 
public class Map 
{ 
    public List<Tile> tilemap = new List<Tile>(); 

    public Map() 
    { 
     Tile single_tile = new Tile(); 

     // Fill entire tilemap with one single tile object 
     for(int i = 0; i < 131072; i++) 
     { 
      tilemap.Add(single_tile); 
     } 

    } 

    public Map(SerializationInfo info, StreamingContext ctxt) 
    { 
     tilemap = (List<Tile>)info.GetValue("tilemap", typeof(List<Tile>)); 
    } 

    public void GetObjectData(SerializationInfo info, StreamingContext ctxt) 
    { 
     info.AddValue("tilemap", tilemap); 
    } 

} 

這裏的瓷磚類。

[Serializable()] 
public class Tile 
{ 
    public int id; 
    public string name; 
    public int type; 
    public int passage; 
    public bool autotiled; 

    public Tile() 
    { 

    } 

    public Tile(int _id) 
    { 
     id = _id; 
     name = "Grass"; 
     type = 1; 
     passage = 2; 
     autotiled = false; 
    } 

    public Tile(SerializationInfo info, StreamingContext ctxt) 
    { 
     id = (int)info.GetValue("id", typeof(int)); 
     name = (string)info.GetValue("name", typeof(string)); 
     type = (int)info.GetValue("type", typeof(int)); 
     passage = (int)info.GetValue("passage", typeof(int)); 
     autotiled = (bool)info.GetValue("autotiled", typeof(bool)); 
    } 

    public void GetObjectData(SerializationInfo info, StreamingContext ctxt) 
    { 
     info.AddValue("id", id); 
     info.AddValue("name", name); 
     info.AddValue("type", type); 
     info.AddValue("passage", passage); 
     info.AddValue("autotiled", autotiled); 
    } 

} 

最後,這裏的序列化+壓縮過程

Map map = new Map(); 
string filename = "Game_Data\\" + "Map_1.txt"; 

Stream stream = File.Open(filename, FileMode.Create); 

GZipStream compressor = new GZipStream(stream, CompressionMode.Compress); 

BinaryFormatter bFormatter = new BinaryFormatter(); 
bFormatter.Serialize(compressor, obj); 
compressor.Close(); 
stream.Close(); 
+0

同一個瓷磚可以在同一個瓷磚地圖列表中重複出現嗎? –

+0

您對尺寸的關注究竟是什麼? – kmacdonald

+0

我的擔憂是,我不希望我的整個項目+保存的對象最終可以保持在2 MB以下,而且可以保持在100 MB以下。 – EdgarFrog

回答

0

假設相同的瓷磚可以在同一地圖上反覆出現,您可以將信息分成的獨特瓷磚的列表,列表說明地圖中瓷磚的位置。

IEnumerable<Tile> uniqueTiles = tilemap.Distinct(); 
// Serialize these tiles, i.e each unique tile only once. 

IEnumerable<int> map = tilemap.Select(m => m.id); 
// Serialize the IDs. 

反序列化圖塊時,首先使用ID作爲密鑰將圖塊加載到字典中。

var tileDict = new Dictionary<int, Tile>(); 

使用ID和此字典的列表,您現在可以快速重建原始瓷磚地圖。在每個元素(一個參考)4字節

List<int> ids = ... // Deserialized IDs. 
var tilemap = new List<Tile>(ids.Count); 
for (int i = 0; i < ids.Count; i++) { 
    tilemap.Add(tileDict[ids[i]]; 
} 
+1

我不認爲他是指像素。我認爲這是顯示內容的元數據。 – kmacdonald

+0

@kmacdonald:我完全改變了我的答案。感謝您的有用評論。 –

+0

事實上,我並不是試圖在n級圖像壓縮下進行壓縮,而是在元數據級別上重新使用圖像編輯器。我會用你的例子做一些測試,但我恐怕最終會得到更大的列表/數組。 – EdgarFrog

1

131072元素使得原始數據的512KB,讓你得到你應該得到什麼。其餘數據應該是序列化開銷。

我認爲改善這種情況的唯一方法,不是保存每個瓦片,而只保留重要的瓦片/不是默認的瓦片,相同的稀疏矩陣也能起作用。根據你的地圖,甚至可能有整個圖層你不必實際保存。

0

如果您需要一個緊湊型的表示,請不要使用BinaryFormatterBinaryFormatter實現了許多事情的一個很大的權衡的格式。

我明白這是圖像數據。因此請將其保存爲2048x2048 PNG圖像並使用ScriptPNG將其縮小。

如果它不是圖像,請實現自定義二進制序列化格式。

相關問題