用于游戏数据的“二进制XML”?


17

我正在使用一个级别编辑工具,它将其数据另存为XML。

这是开发过程中的理想选择,因为不费吹灰之力即可对数据格式进行少量更改,并且可以很好地处理树状数据。

但是,不利的是XML文件过大,主要是由于标记和属性名称的重复。同样由于数字数据比使用本机数据类型占用的空间大得多。较小的级别很容易最终达到1Mb +。我想大幅减小这些尺寸,特别是如果该系统用于iPhone或内存相对有限的其他设备上的游戏时。

针对内存和性能的最佳解决方案是将XML转换为二进制级别的格式。但是我不想这样做。我想保持格式相当灵活。XML使得向对象添加新属性非常容易,如果加载了旧版本的数据,则可以为它们提供默认值。因此,我想保留节点的层次结构,并将属性作为名称/值对。

但是我需要以更紧凑的格式存储它-消除标记/属性名称的大量重复。也许还为属性提供了本机类型,因此,例如,浮点数据存储为每个float 4个字节,而不是文本字符串。

Google / Wikipedia透露“二进制XML”几乎不是一个新问题-已经解决了很多次。这里有没有人有使用任何现有系统/标准的经验?-是否有适合游戏使用的理想选择-拥有免费,轻量级和跨平台的解析器/加载器库(C / C ++)?

还是我应该自己重新发明这个轮子?

还是我会忘记理想,而只是压缩我的原始.xml数据(它应该与zip类压缩一起很好地压缩),而让内存/性能受到重载呢?


1
XML可以使用gzip等压缩非常好。
ThiefMaster 2012年

Answers:


18

我们将二进制XML大量用于《超人归来:电子游戏》。我们正在谈论成千上万的文件。它工作正常,但老实说似乎不值得付出努力。它占用了我们加载时间的一小部分,并且XML的“灵活性”没有得到扩展。过了一会儿,我们的数据文件中有太多怪异的标识符,需要保持同步的外部引用以及对它们进行真正人工编辑的其他奇怪要求。

而且,XML实际上是标记格式,而不是数据格式。它针对带有临时标签的大量文本进行了优化。对于完全结构化的数据而言,它不是很好。这不是我的电话,但是如果已经打过电话,而且我知道然后我现在所知道的话,我可能会做JSON或YAML。它们既简洁又不需要压缩,并且针对表示数据(而非text)进行了优化。


1
有一个称为BSON的JSON二进制版本。
菲利普2014年

12

以普通XML的方式存储和编辑关卡,但是让您的游戏引擎在加载过程中将其懒惰地烘烤为二进制XML,然后将二进制XML保存回磁盘,以便下次可以加载(如果原始XML不变) 。

像这样:

data loadXml(xmlFile)
{
    if (xmlFile has changed OR binFile doesn't exist)
    {
        binFile = convertToBinary(xmlFile)
        save(binFile)
    }
    return loadBinaryXml(binFile)
}

这样一来,您可以两全其美。发布时,您只需要确保所有二进制文件都在其中即可。


5

Google协议缓冲区似乎是一种解决之道,但我自己并未使用它们。
http://code.google.com/p/protobuf/

您定义一个描述文件格式的.proto文件:

message Person {
  required int32 id = 1;
  required string name = 2;
  optional string email = 3;
}

然后使用命令行工具进行编译,该工具生成C / C ++类,以先前定义的数据格式写入和解析二进制数据文件。对于不同的编程语言,还有一些扩展。

ProtocolBuffer的缺点是它们不是纯文本格式。您将需要一个工具来生成,读取和编辑它们。但是,如果您仅使用它们在游戏编辑器和游戏之间交换数据,那么这应该不是问题。我不会用它来定义配置文件;)

压缩原始xml文件也应该可以。您正在制作哪种类型的游戏?如果它是基于级别的,那么在加载级别时,您应该只加载一次所有必需的资源。

更新: 有一些其他语言(例如C#)可以与ProtocolBuffers一起使用的项目:http :
//code.google.com/p/protobuf/wiki/ThirdPartyAddOns


序列化程序是否适合这种问题?我想不是,但是我看不出明显的区别。但是对我来说,这个答案似乎是适当的。但是tar / gzip xml文件也会大大减小它们的大小(因为它是文本,但我想它也适用于xml),因此这可能是“更轻松”的解决方案。无论如何,XML是一种简单的语言,但是在解析/使用内存方面非常昂贵:当您使用XML时,应尽可能少地读/写。
jokoon 2011年

这是一个有趣的选项,但看起来更像是在管道中任何地方使用XML的完整替代方案。坦白地说,我对生成的代码并不热衷-另一个复杂之处是,我在工具方面使用C#(我很高兴工具能够继续与大型.XML文件一起使用)。XML-> PB转换器可能是一个选择,尽管我认为我仍在寻找更“通用二进制XML”的东西,而不是烘烤特定“二进制级别数据”的方法(即使那会更多)高效)
bluescrn 2011年

“我将C#用作工具方面的东西”,其中有几个针对c#的项目。更新了我的答案。
斯蒂芬

@bluescrn,我不会太担心生成的代码。Google为C ++,Java和Python提供了一流的支持。他们在内部广泛使用它;生成的代码非常健壮。PB的一大优势是您针对.proto文件的工具程序,几乎可以消除沟通不畅的问题。如果您甚至具有使用XML模式的纪律(和时间),Protos比XML模式更容易阅读/维护。
deft_code 2012年

4

JSON格式呢?

http://www.json.org/xml.html


它看起来比XML更为紧凑,但仍然存在属性名称重复的主要问题。如果文件包含具有“ XPosition”,“ YPosition”和“ Scale”属性的游戏对象列表,则字符串“ XPosition” /“ YPosition” /“ Scale”将为每个单个游戏对象重复。这是我目前要“压缩”的主要内容
bluescrn 2011年

1
@bluescrn:不,它没有那个问题。对象是一种结构。您也可以使用数组[只是,看起来,像这样]。这意味着您最终可能会用这样的方式来存储汽车的名称和属性:"cars":{"ford":[8C,FA,BC,2A,384FFFFF],"holden":[00,00,04,FF,04FF54A9]}您甚至可以省略“汽车”标识符,如果知道汽车字段的位置,则直接进入数组。如果您不需要保存数据,甚至可以忽略“ ford”和“ holden”名称,而只需:[...,[[8C,FA,BC,2A,384FFFFF],[00,00,04,FF,04FF54A9]]]。它会变得更紧凑吗?
doppelgreener 2011年

1
@Axidos:如果要使标记变得不可读和不结构化,则最好将其设置为二进制。除此之外,这是一种虚假的节省,除非您在运行时解析未压缩的数据(在这种情况下,无论如何您都可能被搞砸了),或者在解析期间以某种方式限制了数百字节的字符串内存(除非您在微波炉,不是)。

@Joe:bluescrn似乎正在寻找一种没有重复名称的可读格式。我在说明JSON的功能。我完全同意,尽管在某个时候您可能还想知道为什么您还要为这样的标记感到困扰。
doppelgreener 2011年

4

使用JSON。

(基于Munificent的回应,并且主要是回应您在其他地方表达的关注)

您已经提到了有关JSON浪费空间命名元素(例如XML)的问题。没有。

JSON建立在两个结构上:名称/值对(对象)和值的有序列表(数组)。XML 基于名称/值对构建。

如果您认为JSON依赖于对象,则您正在阅读的JSON都是自描述性的并且易于阅读,例如(使用八位数字对表示单个字节):

{
    "some": ...,
    "data": ...,
    "fields": ...,
    "cars": [
        {"name":"greg","cost":8C,"speed":FA,"age":04,"driverID":384FFFFF},
        {"name":"ole rustbucket","cost":00,"speed":00,"age":2A,"driverID":04FF54A9}
    ]
}

但是,您也可以选择这样编写,只要您知道一切都在哪里即可(因此可以查找索引4,而不是对象“ cars”来获取汽车列表):

{
    [
        ...,
        ..., 
        ...,
        [["greg",8C,FA,04,384FFFFF],["ole rustbucket",00,00,2A,04FF54A9]],
        ...,
    ]
}

它得到的不仅仅是有更简洁[],和你的价值观?

好吧,如果您愿意离纯二进制流越来越近,那就可以了。

"cars":{"names":["greg","ole rustbucket"],"stream":8CFA04384FFFFF00002A04FF54A9}
or
[["greg","ole rustbucket"],8CFA04384FFFFF00002A04FF54A9]

只是不要通过优化太多而使自己陷入困境。


2

我知道您已经接受了答案,但是Google既提供了“快速信息集”(二进制XML)又提供了vtd-xml。

尽管后者(VTD)可能无法解决XML使用方面的压缩问题,但它可能会加速跨大型文件的节点访问(相当大的程度(它使用二进制偏移量“字典”跳转到节点,并且不会为每个节点创建对象) ,而是使用原始XML字符串)。因此,它的XML查找速度据说更快,并且不需要太多的进程内内存来访问/操作XML文档。

以上两种都具有流行语言(包括C#)的绑定。

干杯

丰富


1

您可以尝试Karvonite。它应该是敏捷的。这是一个持久性框架,可以很好地适应您数据中的更改(与处理自己的二进制文件相比,这是很好的选择)。我实际上不确定数据的结构,但是文件比xml膨胀文件小得多。(我假设它以二进制格式而不是像xml这样的文本保存数据)

我唯一能想到的缺点是,如果您的数据遭到破坏或以某种方式被Karvonite不喜欢的方式弄乱了,除非您弄清楚数据的结构如何,否则您将受制于创作者数据有效。

指定保存/加载数据的方式是,只需打开其持久性编辑器,将所有数据对象导入程序集,然后选中某些复选框以显示要支持的对象以及要保存的字段/属性。

可能值得一试。自从您使用C#之后,它就可以与您的语言配合使用,因为它可以与XNA(Windows,Xbox360和Windows Phone 7一起使用,自您提到iPhone以来,我认为您对此很感兴趣?)。

编辑:刚注意到您只使用C#的工具。这可能不太适合您的工作流程。由于某种原因,我脑中有了XNA。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.