所以我目前正在为名为Slick2d的TiledMapPlus库创建一个库扩展。它旨在为使用Tiled的人们提供更大的支持,并更快地访问数据等。
该库的目标之一是提供动态地图编辑,因此能够将新地图写入流。 我今天和昨天实施了这个,现在需要你的帮助。我的代码有问题。
因此,基本问题是,TiledMap解析器/编辑器的XML层数据格式错误,无法读取。 我已经经历了许多教程,试图将数据压缩为 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
答案 0 :(得分: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());
}
答案 1 :(得分:1)
谢谢Liam我实际上一直在跟踪你能找到的所有可能的东西,你已经写好了,而你在TiledMapPlus中的代码终于为我解决了这个问题。
这是从利亚姆代码中正确使用的解决方案:
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号,它完全接受并编码它!
答案 2 :(得分:0)
我不能说四十二的答案的价值。如果有效,请回复说。我已经在一个正在编写的游戏中使用了这个问题,问题在于你正在使用的格式。
当你创建一个TMX文件,其中包含TiledMapPlus和slick2d所需的压缩和gziped数据时,你不要使用<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工作的人似乎没有遇到同样的问题。
非常感谢任何帮助。