0

所以我目前正在为Slick2d库创建一个名为TiledMapPlus的库扩展。它旨在为使用 Tiled 的人们提供更大的支持,并更快地访问数据等。

该库的目标之一是提供动态地图编辑,因此能够将新地图写入流。我今天和昨天实施了这个,现在需要你的帮助。我的代码有问题。

所以基本问题是,XML 图层数据格式错误, TiledMap 解析器/编辑器无法读取。我已经阅读了许多试图将数据压缩成GZIP 压缩的 BASE64 格式的教程。我终于将与 GZIP 压缩选项一起使用。但是,每次我压缩数据等时,它总是输出比 Tiled2d 编辑器更大的输出,并且输出损坏的数据。为什么是这样?

文件链接:

TiledMap 编辑器自动生成的 Tiled Map

使用我的库从上面的 TiledMap 生成的 Tiled Map

我的库中不起作用的代码片段

或者,您可以在此处查看所有格式

4

3 回答 3

1

您正在使用的方法是设置这样的输出流管道:

ObjectOutputStream -> GZIPOutputStream -> Base64OutputStream

您将不希望拥有第一个 ObjectOuputStream,因为它正在序列化一个 JAVA 字节数组对象。您应该直接向 GZIpOuputStream 提供字节。如果找不到合适的方法,使用 apache commons 编解码器很容易设置自己的:

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());
}
于 2011-10-27T21:04:34.640 回答
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 号,它正在完美地接受和编码它!

于 2012-02-26T15:03:19.127 回答
0

我无法说出四十二个答案的价值。如果它有效,请回复这样说。我已经在我正在编写的游戏中得到了这个工作,问题出在你使用的格式上。

当您创建一个 TMX 文件时,按照 TiledMapPlus 和 slick2d 的要求压缩和 gzip 压缩了数据,您不要<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 它会作为该图块的 GID 的空值(在读取文件时)崩溃,即使该图块集中有 20 个左右的图块。因此,在对任何 2 位数字进行编码和压缩后返回的内容有问题。这似乎是特定于 java 的,因为使用 obj-c 工作的人似乎没有遇到同样的问题。

任何帮助将不胜感激。

于 2012-02-25T22:05:00.830 回答