2011-10-27 46 views
0

因此,我目前正在爲名爲TiledMapPlusSlick2d庫創建庫擴展。它旨在爲使用Tiled的人們提供更大的支持,並更快地訪問數據等。如何使用Java正確壓縮和轉換TiledMap數據?

該庫的目標之一是提供動態地圖編輯功能,因此可以將新地圖寫入流。 我今天和昨天實施了這個,現在需要你的幫助。我的代碼有問題。

所以基本問題是,XML層數據是畸形,和不能由TiledMap類解析器/編輯器讀取。 我已經經歷了很多教程,試圖將數據壓縮成GZIP壓縮,BASE64格式。我終於訴諸於使用this與GZIP壓縮選項。 但是,每次我壓縮數據等時,它總是輸出比Tiled2d編輯器大的輸出,並且它會輸出損壞的數據。爲什麼是這樣?

文件的鏈接:

A Tiled Map automatically generated by the TiledMap editor

A Tiled Map generated from the above TiledMap, using my library

Snippet of the code from my library which isn't working

Alternatively you can view them all formatted here

+0

無法遵循所有這些,但我知道使用base64來壓縮某些東西是一個非常糟糕的想法。但是再一次,任何像樣的壓縮器都會接受這樣一個事實,即每個字節中的第7位和第8位始終爲0並相應地進行壓縮... – bdares

+0

如果有任何混淆,我使用GZIP壓縮數據,然後將其轉換爲Base64編碼。它的TiledMap標準,我沒有定義它大聲笑。 – liamzebedee

回答

1

感謝利亞姆我實際上一直在關注着你所寫的每一件可能的事情,它是你在TiledMapPlus中的代碼,終於爲我解決了這個問題。

這是正常工作從Liam的代碼所採取的解決辦法:

  Element layer = doc.createElement("layer"); 
     layer.setAttribute("name", "layer"); 
     layer.setAttribute("width", width); 
     layer.setAttribute("height", height); 



      Element data = doc.createElement("data"); 

      ByteArrayOutputStream os = new ByteArrayOutputStream();     
      for(int tileY = 0;tileY<layerHeight;tileY++){ 
       for(int tileX = 0;tileX<layerWidth;tileX++){ 
        int tileGID = this.data[tileX][tileY]; 
        os.write(tileGID); 
        os.write(tileGID << 8); 
        os.write(tileGID << 16); 
        os.write(tileGID << 24); 
       } 
      } 
      os.flush(); 
      String compressedData = Base64.encodeBytes(os.toByteArray(),Base64.DONT_BREAK_LINES|Base64.GZIP|Base64.ENCODE); 
      data.appendChild(doc.createTextNode(compressedData));    
      data.setAttribute("encoding", "base64"); 
      data.setAttribute("compression","gzip"); 

      layer.appendChild(data); 

     mapElement.appendChild(layer); 

我用我的相同數據生成技術和傳遞我想要的任何ID號,它是接受和完美的編碼吧!

1

您使用的是建立這樣的輸出流的管道的方法:

的ObjectOutputStream - > GZIPOutputStream - > Base64OutputStream

你不會希望有第一ObjectOuputStream,因爲它是一個序列化JAVA字節數組對象。您應該直接向GZIpOuputStream提供字節。如果你不能找到一個合適的方法,這是很容易建立自己的使用Apache公地編解碼器:

public String compressAndEncode(byte[] data) throws Exception { 
    ByteArrayOutputStream out = new ByteArrayOutputStream(); 
    GZIPOutputStream gz = new GZIPOutputStream(out); 
    ByteArrayInputStream in = new ByteArrayInputStream(data); 
    int c; 
    while ((c = in.read()) != -1) 
     gz.write(c); 
    gz.finish(); 
    Base64 b = new Base64(0); 
    return b.encodeToString(out.toByteArray()); 
} 
0

我不能答覆的價值從42說話。如果有效,請回復說。我已經在遊戲中得到了這個工作,我正在寫作,問題在於你正在使用的格式。

當您創建一個TMX文件,該文件具有壓縮和gziped所需的TiledMapPlus和slick2d的數據時,您不需要使用<tiled>標籤,如一般的非壓縮文件。它的反直覺,但它是如何工作的。

要創建<data>標記中的數據,您需要使用32位整數創建每個gid的字符串/流,然後將其轉換爲UTF-8,然後對其進行壓縮和編碼。

這裏是我的地方在網上找到了一個例子:

   Element data = doc.createElement("data"); 
      data.setAttribute("encoding", "base64"); 
      data.setAttribute("compression", "gzip"); 

       String bytestring = new String(); 
       for (int x = 0; x < w; x++) {      
        for (int y = 0; y < h; y++) { 
         switch(this.data[x][y]){ 

          case 0: bytestring += "1000"; 
           break; 
          case 1: bytestring += "2000"; 
           break; 
          case 2: bytestring += "3000"; 
           break; 
          case 3: bytestring += "4000"; 
           break; 
          case 4: bytestring += "5000"; 
           break; 
          case 5: bytestring += "6000"; 
           break; 
          case 6: bytestring += "7000"; 
           break; 
          case 7: bytestring += "8000"; 
           break; 
          case 8: bytestring += "9000"; 
           break; 

         } 
        } 
       } 

       Text value = doc.createTextNode(compress(bytestring)); 
       data.appendChild(value); 

壓縮和編碼都做過這樣的:

private static String compress(String str){ 

    byte byteAry[] = null; 

    try{ 
     byteAry = str.getBytes("UTF-8");  
    }catch(UnsupportedEncodingException e){ 
     System.out.println("Unsupported character set"); 
    } 

    for(int i = 0; i < byteAry.length; i++) { 
     if(byteAry[i] == 48) 
      byteAry[i] = 0; 
     if(byteAry[i] == 49) 
      byteAry[i] = 1; 
     if(byteAry[i] == 50) 
      byteAry[i] = 2; 
     if(byteAry[i] == 51) 
      byteAry[i] = 3; 
     if(byteAry[i] == 52) 
      byteAry[i] = 4; 
     if(byteAry[i] == 53) 
      byteAry[i] = 5; 
     if(byteAry[i] == 54) 
      byteAry[i] = 6; 
     if(byteAry[i] == 55) 
      byteAry[i] = 7; 
     if(byteAry[i] == 56) 
      byteAry[i] = 8; 
     if(byteAry[i] == 57) 
      byteAry[i] = 9; 
    } 
    ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 

    try { 
     OutputStream deflater = new GZIPOutputStream(buffer); 
     deflater.write(byteAry); 
     deflater.close(); 
    }catch (IOException e) { 
     throw new IllegalStateException(e); 
    } 
    String results = Base64.encodeBase64String(buffer.toByteArray()); 
    return results; 
} 

現在,這裏是一個更先進的問題,那就是高度相關。在上面的例子中,您可以看到每個GID都由一個32位字符串(如1000)表示。這些字符串直接與包含的tileset文件相關聯。我遇到了問題,因爲我似乎可以使用這種技術來使用GID 9(顯示爲9000)。我相信這與ByteStream本身有關。如果我輸入1100,那麼即使tileset中有20個左右的圖塊,它也會爲該圖塊的GID(讀入文件時)的空值崩潰。因此,在編碼和壓縮任何2位數字後返回的內容是錯誤的。這看起來頗爲具體,因爲與obj-c一起工作的人似乎並沒有遇到同樣的問題。

任何幫助將不勝感激。

+0

作爲說明,我是TiledMapPlus庫的創建者,它可以編寫TiledMap文件。 – liamzebedee

+0

對不起,這篇文章出現在查看隨機生成的地圖時。因爲這是無處不在,我的補充將幫助那些人。我的'高級'問題在我的另一篇文章中解決。基本上,我發現這種弦技術有更好的方法。更好的方式是Liam在TiledMapPlus的write()方法中找到[這裏](https://github.com/liamzebedee/TiledMapPlus/blob/master/src/org/newdawn/slick/tiled/TiledMapPlus)。 JAVA)。 再次感謝您在這個圖書館利亞姆壯觀的工作。 順便說一句關於在狀態之間傳遞數據的任何詞? –

+0

假設42個答案沒有真正解決問題,我是否正確?這是你編碼''標籤的事實,對吧? 這出現了很多地圖生成問題,所以我添加了一些細節B/C很多人似乎遇到了隨機地圖等問題。也許這會幫助其他人。 –