【问题标题】:Making a Savefile for a Text-Based Game in Python在 Python 中为基于文本的游戏制作保存文件
【发布时间】:2017-03-24 18:33:15
【问题描述】:

tl;dr 下面用粗体表示

我目前正在开发一个基于文本的冒险游戏,并且我已经实现了一个基本的保存系统。

该过程利用了“pickle”模块。它生成或附加到具有自定义扩展名的文件(实际上是文本文件)。 引擎会腌制玩家的位置、他们的物品栏,而且,最后一部分是有点奇怪的地方。

游戏从特殊格式的脚本加载对话框(这里我的意思是在演员的脚本中)。一些对话会根据某些条件(之前已经与他们交谈过、新事件等)而发生变化。因此,对于引擎保存的第三个对象,它将所有对话树保存在其当前位置。例如,它将文字脚本保存为当前状态。

这是保存程序:

with open('save.devl','wb') as file:
    pickle.dump((current_pos,player_inv,dia_dict),file)
    for room in save_map:
        pickle.dump(room,file)
    file.close()

我的问题是,这个过程会生成一个非常丑陋、非常冗长、超大的文本文件。现在我知道文本文件基本上是我可以生成的最小文件,但我想知道是否有任何方法可以压缩或以其他方式更有效地记录游戏中所有内容的状态。或者,从长远来看,这只是一种更智能的保存玩家数据的方法。

请求了对话框的格式。这是一个示例:

[Isaac]
a: Hello.|1. I'm Evan.|b|
b: Nice to meet you.|1. Where are you going?\2.Goodbye.|c,closer|
c: My cousin's wedding.|1. Interesting. Where are you from?\2. What do you know about the ship?\3. Goodbye.|e,closer|
closer: See you later.||break|
e: It's the WPT Magnus. Cruise-class zeppelin. Been in service for about three years, I believe.||c|
standing: Hello, again.|1. What do you know about the ship?\2.Goodbye.|e,closer|

括号中的名称是程序如何识别要调用的树。每个字母都是树中的一个单独的分支。横条将分支分为三个部分: 1. 角色说了什么 2. 允许你做出的回应 3. 每个回应的去向,或者如果玩家没有回应,那么玩家随后会被引导到哪里。

在此示例中,玩家与艾萨克交谈后,“a”分支会从游戏存储在内存中的树副本中删除。然后它会永久使用“常设”分支。

【问题讨论】:

  • 对话树的格式是什么?你能edit 并提供体面的例子吗?
  • “现在我知道文本文件基本上是我可以生成的最小文件......”这似乎是一个可以使用一些支持证据的声明。我想你会发现这不一定是真的。如果您意识到您正在寻找一种方法来有效地序列化您的数据,它可能会帮助您找到解决方案。这可能会提供一些有用的搜索结果。不存储整个对话树似乎也是一个明显的优化(可能存储某种光标?或条件值?)
  • 他不要资源推荐,他要解决方案!

标签: python python-3.x game-engine


【解决方案1】:

Pickle 本身还有其他协议,它们都比默认协议(协议 0)更紧凑——这是唯一一个“基于文本”的协议——其他协议是二进制协议。

但是他们,您几乎不会得到超过 50% 的文件大小 - 为了能够增强答案,我们需要更好地了解您正在保存的什么,以及是否有更智能的方法保存您的数据 - 例如,如果您的多个房间中存在相同的子数据结构,则避免重复该结构。 (尽管如果您在游戏中使用对象标识,Pickle 应该会处理好这一点)。

也就是说,只需更改您的 pickle.dump 调用以包含协议参数 - -1 值相当于“HIGHEST_PROTOCOL”,这通常是最有效的:

pickle.dump(room,file, protocol=-1)

(加载泡菜根本不需要协议通过)

此外,您可能希望使用 Python 的 zlib 接口来压缩 pickle 数据。这可以让您再减少 20-30% 的文件大小 - 您必须链接对 file.write、zlib.compress 和 pickle.dumps 的调用,因此使用一些帮助代码会更容易 - 您还需要控制文件偏移量,因为 zlib 不像 pickle 会推进文件指针:

import pickle, zlib 

def store_obj(file_, obj):
    compressed = zlib.compress(pickle.dumps(obj, protocol=-1), level=9)
    file_.write(len(compressed).to_bytes(4, "little"))
    file_.write(compressed)

def get_obj(file_):

     obj_size = int.from_bytes(file_.read(4), "little")
     if obj_size == 0:
         return None
     data = zlib.decompress(self.file_.read(obj_size))
     return pickle.loads(data)

【讨论】:

  • 所以,例程自己腌制对象。我已经为房间、物品、角色等创建了对象类型。因此,保存文件看起来非常混乱,理论上玩家可以调整一些文本。可以在此处看到一个保存文件示例:imgur.com/UIASFZc(由于某种原因我无法复制文本)我腌制对象只是因为它更容易,至少引擎当前是如何工作的。我肯定要做的一件事是检查任何 unpickling 错误。如果他们发生了,我只是抓住它并指责玩家作弊:)
  • Pickle 定义不是一种设计为人工可编辑的格式,即使在协议的文本版本中也是如此。您应该考虑尺寸性能或人工可编辑性,在后一种情况下,使用 JSON 而不是 pickle 序列化您的对象。 (Json 并不是对所有 Python 对象类型都是自动的,你必须调整你的代码)。问题是针对文件大小的。
  • 但是,格式精美的 JSON 输出所获得的额外可读性可能会使文件更大,因为“手动”编辑肯定会更容易。
  • 我原本打算使用 JSON,但 pickle 更友好,因为我很懒。那么,如果我理解正确的话,我已经以一种相对最优的方式做到了这一点?
  • 我看到您主要使用文本 - 压缩解决方案将为您提供更小的文件。但不可编辑。所以这是你的选择。如您所见,对于可编辑文件,pickle 不是 goot。
猜你喜欢
  • 1970-01-01
  • 2015-09-10
  • 2018-07-28
  • 1970-01-01
  • 1970-01-01
  • 2023-01-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多