我知道您在想什么…什么…为什么有人要这样做? 我正在学习Python的朋友提到他想构建一个基于文本的角色扮演游戏,这让我开始思考。 自从我尝试构建上一个基于文本的"游戏" monty.py至今已有七年了,这只是一个简单的Monty Python短剧。 这就是为什么我要再努力用python创建一个基于文本的角色扮演游戏引擎。
定义我们的输入和输出
首先,我们需要树立我们的期望。 我认为游戏最简单的形式就是要做以下事情:
· 加载包含游戏信息的文件
· 显示游戏中的文字输出
· 接受玩家的输入
我们将希望将输出和输入分组在一起。 我们将它们放在我们称为页面的内容上。 每页都会有一个数字,以便我们跟踪它们。 这是页面的外观:
1: { 'text': 'options':}
我们不想只包含大块文本,因此"文本"应该是包含字符串的列表元素。 这样,在输入之前,您必须单击多行对话。 另外,当文本看起来像在屏幕上键入时,我真的很喜欢它,因此我们稍后将实现该功能。
'text': [ "This is out first line", "And this is our second"]
接下来,输入。 每个输入语句可能应该包含一行文本,然后还有一个指示符,用于指示何时选择此输入进入此页面。 因为此数据定义良好,所以我们可以使用元组数组来存储它,如下所示:
'options': [ ("Option 1", 2) ("Option 2", 3)]
一旦我们以正确的格式编写了故事,就可以使用以下脚本将其包装成一个二进制的pickle文件,该文件可以分发并从引擎中读取。
import picklestory = { 1: { 'Text': [ "Hello there..", "I bet you werent exepecting to hear from me so soon...", "...you seem a little confused do you know who I am?" ], 'Options': [ ("Yeah of course!", 2), ("I'm sorry I dont", 3) ] }}with open('chapter1.ch', 'wb') as chapter: pickle.dump(story, chapter)
输出文字
我们要做的第一件事是弄清楚如何像在键入文本一样将文本缓慢地输出到屏幕上。 通过这种出色的解决方案,可以将堆栈溢出进行救援。 这会遍历每个字母并将其放在输出端子上。 sys.stdout调用提供了对命令提示符的较低级别的访问,允许您覆盖Python设置的默认值。
import sys,time,randomdef slow_type(t): typing_speed = 100 #wpm for l in t: sys.stdout.write(l) sys.stdout.flush() time.sleep(random.random()*10.0/typing_speed)
好的,既然我们已经摆脱了慢速打字的麻烦,那么我们就可以开始实际工作了。 我们说过,我们希望一次打印一页文本中的每一行。 当您单击Enter键时,它应移至下一个输出。 该功能如下所示。
它从页面的文本部分获取行列表; 然后在行上进行迭代,以慢速键入一行,然后等待按下Enter键,然后再移至下一行。
def display_page_text(lines: list): for line in lines: slow_type(line) # Make the user press enter to see the next line get_input([''])
坚持下去! 我知道我只是使用了get_input()而没有显示该函数的外观。 接下来,让我们看一下如何获得输入值。
接受输入
从命令行获取输入还不错。 首先,我们将创建一个函数的唯一目的是接受输入。 我们将传递有效输入字符串列表。 然后,我们将接受用户输入。 如果他们的输入未在有效输入列表中列出,我们会通知用户,告诉他们什么是有效输入,然后清除输入。 否则,我们返回输入。
def get_input(valid_input: list): while True: user_entered = input() if user_entered not in valid_input: print("Invalid input. Please use one of the following inputs:") print(valid_input) user_entered = None else: return user_entered
如果期望输入键,我们将使用前面提到的['']来获取输入。 否则,获取输入的主要用途是确定下一页。 这是获得响应功能的工作。 它传递了代表选项的元组列表。 它们具有字符串选项,然后具有页码,例如:("选项1",2)。
获取响应遍历元组,为选项和选项文本打印一个数字。 然后,传入有效输入(选项的索引)以获取输入功能以获取用户的输入。 最后,它返回下一个页码。
def get_response(options: list): for index, option in enumerate(options): print(index + ". " + option[0]) valid_inputs = [str(num) for num in range(len(options))] option_index = int(get_input(valid_inputs)) return options[option_index][1]
一起拉
我们需要做的最后一件事就是将它们整合在一起。 加载应用程序时,我们需要加载第一页。 然后,我们设置程序循环。 要退出循环,我们将页面设置为无。
然后,我们将从故事字典中获取当前页面。 如果没有页面,那么我们需要跳出循环。 这样,如果没有提到索引的页面,程序将正常退出。
提取页面后,将使用前面定义的功能显示页面文本。 一旦他们完成了页面文本,我们将得到他们想要进入下一页的输入。 如果列表中没有任何选项,那么我们会说故事结束了,我们可以结束故事了。 如果有选项,我们将使用我们的get response函数来获取它们的选择。
def story_flow(story: dict): curr_page = 1 while curr_page != None: page = story.get(curr_page, None) if page == None: curr_page = None break display_page_text(page['Text']) if len(page['Options']) == 0: curr_page = None break curr_page = get_response(page['Options'])
最后,我们将让脚本加载pickle文件来播放故事。 这是完成的方式。
import pickleif __name__ == "__main__": story= {} with open('chapter1.ch', 'rb') as file: story = pickle.load(file) story_flow(story)
这就对了! 查看Github仓库,查看完整的示例。 另外,恭喜! 如果遵循此示例,那么您刚刚实现了地图数据结构!
(本文翻译自David Tippett的文章《Building a Text-Based RPG Engine in Python》,参考:https://levelup.gitconnected.com/building-a-text-based-rpg-engine-in-python-e571c94500b0)