“级别字符串”的最佳解决方案?


10

我有一个会在关卡开始时生成随机关卡地图的游戏。我想实现某种保存和加载级别的方法。

我当时在想XML可能是保存所有变量的好选择,那么对我来说,构建可以解析XML并生成完全相同级别的内容很容易。

但是XML可能对我的需求而言过于严格。我记得当初使用旧的Sega游戏机无法保存您的游戏(我认为Worms游戏也可以保存游戏),它们会给您很多角色,您可以写下来。如果稍后再打入该字符串,它将加载准确的电平。

“级别字符串”会是一个不错的选择吗?会是某种“ base60”转换吗?我将如何实施呢?

Answers:


20

大概您需要保存的只是随机种子,它通常只是一个整数。如果您想使int更加不透明,可以将int编码为base64,但这可能就不需要了。


您还可以从一个真实的单词中生成种子(也许要购买加起来的字符来获取您的种子),从而返回更有意义的东西。您将不得不将单词存储在游戏中或将其检索出来。
乔纳森·费斯霍夫

很好,但是如果要玩游戏,它还必须存储动态数据。该字符串将需要保存字符位置/分数等。那么生成此字符串的最佳方法是什么?
亚当·哈特

我可能会使用JSON(或XML,如果您愿意)来序列化世界状态,然后对该字符串进行base64编码。不确定这是否有用,为什么不制作一个更加基于GUI的保存/加载系统呢?我假设这是基于Web的,并且您不希望处理此服务器端。也许看看shygypsy.com/farm/p.cgi为例?
coderanger 2010年

23

无论您用于保存游戏的格式是什么,为了方便起见,请放入一个版本号。通过分支该版本号,您将可以具有向后兼容的加载,也可以安全地识别过旧的保存装载。

如果不这样做,您会后悔的。


7
+1并不能真正回答问题,但非常重要。
乔纳森·

10

JSON很好,但是YAML更好。:)http://www.yaml.org/http://code.google.com/p/yaml-cpp/,这是一种易于使用的实现。

YAML是JSON的超集,它增加了对一些不错功能的支持,最值得注意的是:

  • 二进制节点。这对于序列化级别描述可能要处理的数据类型非常有用。JSON要求您在解析之前/之后转换为您选择的某种中间格式,例如Base64。YAML具有!! binary节点类型,它告诉解析器库为您执行此操作。
  • 文档内参考。如果同一对象在文档中出现两次,JSON将对其写入两次,当您读回时,将获得两个副本。许多YAML发射器可以检测到这种情况,而不是第二份副本,而是在加载时可以检测到时输出对第一个副本的引用。
  • 自定义节点类型。您可以使用!! Player,!! Enemy等在列表中标记每个地图,从而使您的类型信息更加带外。
  • YAML支持更具可读性的格式。
  • 由于JSON是YAML的子集,因此大多数YAML读者都可以轻松阅读JSON文档。

1
Yaml非常酷,如果您避免使用某些超集功能,则可以毫不费力地将其转换为json。
杰斯罗·拉尔森


3

如果您不受大小的限制并且XML本身受支持(例如,.NET和Flash),那么XML是一个不错的选择,但是如果您想要一种苗条的格式,则可以轻松地创建自己的格式和解析器。我通常使用1个字符,例如。以逗号分隔每个对象。要对字符串进行解码,请对逗号进行分割。现在,每个对象都需要不同的属性,因此请使用不同的字符(例如,半冒号)分隔这些属性,并使用另一个字符将属性名称与属性值分开,例如。结肠。因此,仅通过使用string.split就可以轻松地解码所有内容而无需使用正则表达式。这是一个例子:

id:1;x:5;y:45.2;angle:45,id:28;x:56;y:89;angle:12;health:78

您可以通过将属性名称的字符数减少到1个字符来节省更多空间,例如,h表示健康。例如。

i:1;x:5;y:45.2;a:45,i:28;x:56;y:89;a:12;h:78

与JSON替代方案比较:

{"o":[{"i":1, "x":5, "y":45.2, "a":45}, {"i":28, "x":56, "y":89, "a":12, "h":78}]}

另外,如果您想减小数字的大小,则可以使用全套可打印的UTF16字符对它们进行编码。这个线程启发了我在Stack Overflow上一个问题,您可以将多少数据打包成一个屏幕字符。如果您不介意使用烤肉,汉字和国际象棋棋子,答案似乎是一个整数超过40,000个值:♔♕♖♗♘♙♚♛♜♝♞♟

为了进一步减小大小,可以使用读/写顺序确定哪个值是哪个值,因此前两个字符代表id,后两个字符代表x位置,后两个字符y,然后是角度,然后是健康值等等。

F5DGP@%&002DFTK#OP1F

可以存储与其他示例相同的所有信息。

瓦片网格可以存储为一个字符串,每个字符代表不同类型的瓦片,例如:

i789pog5h3kl

我可能是指熔岩,9是草等


这更符合我的要求。我在问题中提到了XML,但仍然有人建议这样做!
亚当·哈特

1
在其周围加上{},基本上就可以得到JSON ;-)
coderanger 2010年

您还需要添加大量引号。字符数可能会增加一倍,但是您会嵌套对象。
伊恩

1

如果您使用.Net进行编码,那么XML非常容易使用,因为您可以仅用几行就可以将级别类序列化/反序列化为XML,也可以将其反序列化为XML,然后将其全部托管在一个很好的托管类中。

TheMap将是Map类型的变量,您已将所有数据加载到其中。

Dim TheMap As New Map

假设您已经构建了一个Map类,这会将您的地图保存为XML:

Dim Serializer As New System.Xml.Serialization.XmlSerializer(GetType(TheMap))
Dim Strm As New FileStream("c:\Map.xml", FileMode.Create, FileAccess.Write, FileShare.None)
Serializer.Serialize(Strm, TheMap)
Strm.Close()

然后,这会将XML加载回您的地图类中,以再次在代码中使用。

Dim Reader As New StreamReader("map.xml")
Dim Serializer As New System.Xml.Serialization.XmlSerializer(GetType(TheMap))

TheMap = Serializer.Deserialize(Reader)
Reader.Close()

至此,您的XML文件现在已加载到您的类中,以方便使用。

至于您的“级别字符串”问题,前面所说的将很有效,您可以将种子编号用作“级别字符串”。

否则,您可以只预生成所需的许多不同地图,然后将它们全部保存为“ Level String”,然后使用它来拉出适当的地图。


即使我讨厌XML,也+1-如果该语言提供了默认的序列化格式,则最好首先考虑这一点,尤其是如果它是其他工具理论上可以解析的格式(例如XML / JSON / YAML)。

0

我会使用简单struct或类似的设备(取决于您的语言)将所有游戏状态存储在一个中央位置。如果要保护设置器/获取器,可以将结构包装在中class

如果您愿意,可以使用位域,或者简单地使用按位运算符自己进行位操作。

请注意,在某些语言中,结构填充和打包规则可能会有些复杂-但是如果您有一个或两个填充字节,则对于您的情况也可能没有太大关系。

您也可以使用#pragma#pragma pack(1)或)或__attribute__紧密封装结构,从而消除填充。根据您的编译器和目标体系结构,此方法可能有效也可能无效。

请注意,使用位域和压缩实用程序或属性会降低可移植性。在整个硬件体系结构中,结构字段的字节序(字节顺序)也可能发生变化。因此,如果您尝试进行可移植性,则可能要避免这种情况。

(例如,对于吃豆人,该结构可能天真地包含一个地图ID或地图种子,一个吃豆人x和y位置,四个幽灵x和y位置以及一个大的位域,用于显示是否存在32-64个药丸,不论最大值是多少。)

获得结构后,将其传递给xxencode函数:

encode_save( char * outStringBuf, size_t outStringBufSize,
             const SaveStruct * inSaveData, size_t inSaveDataSize )

编写此函数有点容易出错。您需要根据需要对字节进行移位和组合,以一次获得6位,然后转换为适当的字符。我个人会尝试查找别人的代码,除非我这样做是为了“有趣”(而且我可能想要一个测试套件)。

永远不要低估struct正确位置上老派的力量。我们在这里为GBA和DS游戏大量使用了它。


原始结构序列化是不可移植的,并且对于新代码而言非常脆弱。除非这是为资源非常有限的平台烘焙数据的最后一步,否则它是非常过早的优化。您为什么有6位而不是8位的原因?无论如何,该格式都不是人类可读的,您不妨充分利用真实结构布局的速度和可调试性。

@Joe:我确实提到了它是不可携带的以及一些潜在的问题。这个问题专门要求使用人类可读的“关卡字符串”,例如旧的Sega游戏和提到的base60转换。通过类似xxencode的结构传递结构将做到这一点。这不一定是过早的优化:一个简单的结构(没有位打包)是一种很好的“中心”方式来存储保存数据,并且可以简化与数据交互的许多代码。参见Noel Llopis最近关于非成员非朋友结构和“由内而外”编程的文章。这只是吻。
leander

1
我完全同意这种方式。是的,它不能跨版本或系统移植,但是保存游戏又不是开发期间需要重用或跨平台复制的资源。就地进行读/写,可调试性几乎不是问题,只需实施一次即可,并且永远有效。如果可扩展性确实是一个问题,请添加一个版本号作为第一个ybyte / word,然后您可以打开它(尽管这会引入数据漏洞)。并不是说xml可以解决版本控制问题-不仅要设置值,还涉及更多的问题。是的,我很务实。
Kaj 2010年

0

XML适用于任意结构化的文档(元素可以出现在树的不同级别)或外来格式嵌入(例如将svg放在xhtml页面中)。如果您没有这些要求,那是一种效率很低的格式,最好使用csv或json等更简单的格式。

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.