用Python实现角色扮演类游戏制作(以《潜伏之赤途》)为例
前言
《潜伏之赤途》是由fantasia制作的一款以抗日战争时期上海滩为背景的PC端文字推理谍战游戏,发售于2016年3月15日。我是在大学期间遇见它的,给了留下了十分深刻的印象。它的故事深长,回味无穷【强推!!!!】。
今天就简单以该游戏的序章、第一章为例,简单讲解如何用Python去实现它。
如何玩《潜伏之赤途》
游戏中你叫方别,两年前还是上海一个慷慨激昂的爱国学生,在街上奔走疾呼“抗日救亡”,甚至还秘密加入中国共产党,却因年少血气方刚,被抓进了监狱。
释放后老师出钱将你送去日本留学为了把你塑造成亲日派的形象,两年来你当年的书生形象早已被人们遗忘,老师与组织决定,让你成为“汉奸”,你要如何机智地扮演好这个“碟中谍”?面对一个个艰难的选择是顾全大局还是心慈手软?
游戏介绍链接:https://baike.sogou.com/v142469287.htm?ch=frombaikevr&fromTitle=%E6%BD%9C%E4%BC%8F%E4%B9%8B%E8%B5%A4%E9%80%94
一、序 · 章游戏实现
1. 流程展示
在本游戏的序章中,主要采用的分支结构,原则是非对即错,除了最后一步需要将所有的情况都了解外,其余选择都是只能选对唯一正确的选项。总体来说还是比较简单。因为图片大小有限,所以用思维导图的方式展示了主要流程,这是不标准的【能看就好】。
对于最后一步,
需将所有情况了解清楚,所以直接点击【我没有问题了。】是不能进入第一章的,这个过程采用了循环和条件判断的方法,流程图如下:
- 因为故事开篇有太多的背景情节需要介绍,所以大量的运用的输出语句。此处核心需要解决的是,如何判断是否问完。
- 相同问题是允许多次询问的,顺序不定。如果给每个问题设置一个数值,用累加的方法是不行的。这样可能会出现一个问题问六七次,其他问题不问就通关的情况,所以为了解决这个问题,我采用建立一个空列表的方式,把每个问题对应一个字母编号,每点击一一次某个问题,就将该列表放入该字母,通过for循环遍历该列表,判断所有问题对应字母是否齐全。
print("你一定有许多问题。现在问吧,我们会尽可能详细地回答你。")
My_list1=["a","b","c","e","f","g"]
check = []
flag=0
while (1):
answer = input("请用字母代替你要回答的问题:")
if answer=='a':
print("图书馆馆长是谁?")
print("""刘先生:你可以称呼我“刘先生”,我是中共地下党,也是你和薛先生的联络人。
你们的情报直接传递给我,再由我向上级汇报。我的代号是“红娘”。""")
check.append('a')
if answer=='b':
print("薛老师的情况是?")
print("""薛星文:我的主要任务是组织、引导学生进行地下抗日救亡活动。我的代号是“野火”
刘先生:你是我们培育已久的苗子,当初派你赴日留学,就是为了把你塑造成亲日派的形象。
现在这个世界上,只有我和薛先生两个人知道你的真实身份。""")
check.append('b')
if answer=='c':
print("我的情况是?")
print("""刘先生:你是我们培育已久的苗子,当初派你赴日留学,就是为了把你塑造成亲日派的形象。
现在这个世界上,只有我和薛先生两个人知道你的真实身份。""")
print("刘先生:你的主要任务,就是取得日军信任,进入其核心机关,将重要情报源源不断地送出来。你的代号是“海蛇”。")
check.append('c')
if answer=='d':
print("薛老师为什么要装作和我决裂?")
print("""薛星文:两年前你入狱后不久,学联的多名干部就先后遭到迫害。那时候我就怀疑学生中间有叛徒,但我相信那个人不是你。
薛星文:两年间,又发生了几起情报泄露的事件。远在日本的你绝不可能是黑手,因此我几乎可以肯定,叛徒就在我身边这几人中。
薛星文:今天我们当着众学生的面演这场戏,一方面可以将你隐藏得更深,另一方面也能让叛徒放松警惕。只是委屈你背黑锅了。""")
check.append('d')
if answer=='e':
print("下一步工作计划是?")
print("""刘先生:我们为你在东荣通讯社安排了一份记者的工作。东荣通讯社是亲日派的报社,而记者身份又能让你和日军高层接触。
刘先生:你要把握采访的机会,赢得日军高层的信任,尽快打入敌人内部。""")
check.append('e')
if answer=='f':
print("薛梅的情况是?")
print("""薛星文:她挺好的……虽然积极参加抗日活动,但还没有被日军列入威胁名单。
薛星文:……两年来,她也时常打听你的情况。
薛星文:不过,你不能让她知道你的地下党身份!
薛星文:一方面,知道的东西少点可以让她更安全;另一方面,有时我也怀疑自己的女儿会不会就是叛徒……
薛星文:总之,你的身份不能让我们以外的任何人知道!""")
check.append('f')
if answer=='g':
print("我没有问题了。")
check.append('g')
flag=1
print(check)
for i in ["a", "b", "c", "e", "f", "g"]:
b = i in check
#print(b,flag)
flag *= b
if flag==1:
print("好,看来你已经深入了解当前情况了。")
break
else:
print("一些情况你还不了解,再问得详细一些吧!我和刘先生都会耐心为你说明的。")
print("""薛星文:第一次密谈就这样结束了。
临别前,刘先生认真地握住你的手。
刘先生:革命总是伴随着牺牲,你应该已经拥有了这份觉悟。
刘先生:就让我代表党组织,向你表示感谢!
刘先生:希望你能顺利完成任务……在抗战的历史上,留下属于你的传奇!""")
运行结果如下:
2. 关键代码及讲解
- print输出语句,利用三引号进行段落输出。
- append函数,语法格式list.append(obj),list为列表,obj为添加到列表末尾的对象。
#随着问题的回答,列表check的长度逐渐增长。
for i in ["a", "b", "c", "e", "f", "g"]:
b = i in check#将a、b、c、d、e、f、g几个字母依次用关键字in检验是否在check列表中
print(b,flag) #打印是否存在过程,如果在则返回Ture,不在返回False。
flag *= b #当所有返回值都为True时,相乘才为真。
- 后面根据flag的值,判断是否能够进入下一环节,如果相乘为false,则还有问题没有询问,请继续询问。当所有返回值都为True时,相乘才为真。
二、第一章游戏实现
第一章的主要剧情是要让岗山雄二对方别产生好感度以及信任,从而方别后续的潜伏工作。
当好感度达到要求之后,还有一个最后的考验,每一步皆是步步为营。
1. 流程展示
这个过程中,比较难的点在于这些流程走得有些复杂【即判断的嵌套】和好感度的累加。第二章我的代码就展示汉奸线的开启(即好感度开到8那里),到这里总体来说都是比较简单的,就是文案有些长。
2. 关键代码
在代码的最开头,因为有重复性的文字,所以运用了Python函数定义和函数调用。
num_all=0
flag=1
diliuzhang=0
def copy1_4():
print("""不知不觉,已经到了夜晚。你决定送冈山爱回大使馆。
谁知迎面遇见了薛梅。
薛梅:方别……你竟然和日本女人在一起……
薛梅:我看到了……我看到你在东荣社发表的文章了。
薛梅:你的文采还是那么好……但是……
薛梅:我觉得非常恶心……""")
Quastion1_4_2 = input("你的回答是……(选择1、2)")
if Quastion1_4_2 =="1":
print("【我的事情和你有什么关系?别挡道!】")
print("""薛梅不肯让开。没办法,你狠狠扇了她一巴掌。
冈山爱:方君!你干什么……怎么能当众打女孩子呢
你赶紧拉着冈山爱离开了""")
if Quastion1_4_2 =="2":
print("【……我只是做自己该做的事情罢了。】")
print("""薛梅:……
薛梅缓缓走掉了。""")
print("""冈山爱向你询问薛梅的事情,你敷衍了几句,她没有追问。
很快,你顺利将她送到了大使馆。冈山父女再三向你表示感谢。""")
def copy1_5_1():
print("""冈山雄二:嗯,现在像你这样的年轻人不多了啊!
此后的一个月里,你以记者身份来往于上海的名流世家。在刘先生的指示下,有选择地把情报透漏给冈山雄二。
但是,经过了一段时间的接触,冈山雄二似乎并没有对你放下戒心,反而渐渐疏远了你。
几个月后,没有发挥任何作用的你被薛老师派人送到了延安。你在中共中央成为一名优秀的书记员,直到抗战胜利。
1972年,由于你有曾在东荣通讯社工作,在文革中遭红卫兵批斗至死。""")
def copy1_5_2():
print("""经过了一段时间的接触,冈山雄二似乎越来越器重你了。
终于有一天,他把你叫到身边。
冈山雄二:方君,经过一段时间的观察,我认为你是个可以被皇军信赖的中国人。
冈山雄二:今天你和我一起去办件事吧。做好这件事,我就给你安排一个新工作。""")
#_____________________________________________________________________________________________________________
print("""在组织的安排下,你顺利成为东荣通讯社的记者。
数月后,通讯社派你采访日本大使馆。在那里,你见到了大使馆领事冈山雄二。
冈山雄二:方记者,你好!初次见面,以后还请多多关照。
冈山雄二:方记者,日本和中国一衣带水,本该是睦邻友好的关系,如今却深陷战争的泥淖。天下苍生生灵涂炭,我为之心痛啊!
冈山雄二:痛定思痛。我一直在寻找改变当前局势,救民于水火之中的方法。不知方记者有何高见?""")
while(flag):
Quastion1_1=input("你的回答是……(回答1或2):")
if Quastion1_1=='1':
print("【继续战争,彻底消灭反日势力。】")
print("""冈山雄二:方记者,我与你看法不同。战争只会无端增加人民的伤亡,破坏中日美好的友谊。
冈山雄二:我认为应该举办国际会议,邀请诸如英国、法国等有威信和影响力的西方国家裁决中日问题。这样才能做到公平、公正!""")
if Quastion1_1=='2':
print("【和平谈判,通过国际仲裁解决争端。】")
print("""冈山雄二:好!方记者果然是真正的爱国者!蒋介石也好,毛泽东也好,抗日只是借口。他们丝毫不为自己的人民着想,只是想通过战争来夺取权利,满足自己的野心。
冈山雄二:只有像汪精卫先生和方记者这样识大体、顾大局的人,才称得上是“爱国者”!""")
num_all += 1
print("""冈山雄二:方记者,我希望你能就今天的谈话写一篇文章,让全世界都知道我冈山雄二对和平的渴望!
不久,你将冈山雄二的和谈主张发表在报纸上,引起了轩然大波。
爱国报社纷纷发表社论,声称“和谈是一场阴谋”“西方国家已经与日本串通,将对中国采取绥靖政策”
很快,冈山雄二把你叫到大使馆……
冈山雄二:方记者,上次的文章我看了,你写得非常好!不过很可惜,:还是有不少民众被某些报社的无良言论迷惑,不能理解我们的善意。
冈山雄二:方记者,你是报社圈子里的人,打听消息更容易也更准确。我希望你能给我一个名单,上面包括所有你认为有反日倾向的记者和编辑的名字。
冈山雄二:你明白我的意思吗,方记者?""")
Quastion1_2=input("你的回答是……(回答1或2):")
if Quastion1_2=='1':
print("【没问题,冈山领事!】")
print("冈山雄二:方记者,在我看来,你前途无限啊!")
num_all += 1
if Quastion1_2=='2':
print("【……我尽力而为。】")
print("冈山雄二:那就拜托你了。")
print("""你找到刘先生,商量该如何是好。
刘先生:发表爱国社论的人,大部分都是我党和国民党隐藏在报社的地下工作者。如果你把真实的名单交给日本人,势必对抗日力量造成巨大损失。
刘先生:可是你如果不交名单,或者交一份虚假的名单,可能会永远失去进入日军核心部门的机会。
刘先生:革命总是伴随着牺牲。用牺牲换来的东西是否有更高的价值?你来做决定吧!""")
Quastion1_3=input("你打算……(回答1、2、3、4)")
if Quastion1_3=='1':
print("【交一份真实而完整的名单。】")
print("""刘先生:……好吧。我会向上级索要这份名单,并提前给名单上的同志发出警告。
几天后,冈山按照你的名单,对各个报社的爱国人士进行了突击抓捕。尽管事先得到了警告,还是有大批地下工作者被捕。""")
num_all += 5
if Quastion1_3=='2':
print("【交一份只有国民党地下分子的名单。】")
print("""刘先生:……好吧。我会向上级索要这份名单,并提前给名单上的同志发出警告。
几天后,冈山按照你的名单,对各个报社的爱国人士进行了突击抓捕。尽管事先得到了警告,还是有大批地下工作者被捕。""")
num_all += 3
if Quastion1_3=='3':
print("【交一份完全虚假的名单。】")
print("""刘先生:……好吧。我来准备这份假名单,希望能帮你掩护过去。
几天后,冈山按照你的名单,对各个报社的爱国人士进行了突击抓捕。
但是经过审讯,冈山意识到你的名单纯属虚构。
冈山雄二:不过这份名单,还是告诉了我一个真实的名字……哈哈,不错,方记者!
冈山雄二喊人把你绑了起来。
几天后,日本人把你带到郊外进行了活埋。
刘先生和薛老师也在日后的斗争中先后牺牲,均被追为烈士。
而不知什么时间死在什么地方的你,永远贴着“汉奸”的标签。""")
flag = 0
break
if Quastion1_3=='4':
print("【不交名单。】")
print("""冈山对你非常失望,再也没有让你踏入大使馆半步。
几个月后,没有发挥任何作用的你被薛老师派人送到了延安。你在中共中央成为一名优秀的书记员,直到抗战胜利。
1972年,由于你有曾在东荣通讯社工作,在文革中遭红卫兵批斗至死。""")
flag=0
break
print("""冈山非常欣赏你的才干,邀请你到大使馆共进晚餐。
冈山雄二:方君,我要感谢你为中日和平所做出的贡献!来,干杯!
一位少女突然出现。
冈山雄二:向你介绍一下,这是我的女儿小爱。她在中学当历史老师,一直想亲眼看一看历史悠久的中国。这次就以想念父亲为借口,干里迢迢跑到上海来圆梦了!
冈山爱:父亲……我是真的想念你啊!
冈山雄二:哈哈!方君,明天可否请你带着小爱在上海繁华的街区转一转,让她见识一下大东亚共荣圈的和平景象?""")
Quastion1_4=input("你……答应还是拒绝")
if Quastion1_4=="答应":
print("你答应了。")
print("""冈山雄二:好!那就拜托你照顾小爱了。
冈山爱:谢谢方君!
次日,你和冈山爱在上海的大街小巷游玩。
看到百姓平凡而简单的生活,冈山爱很开心。
冈山爱:方君,来上海以前,我还担心中国人会不会仇视日本人。没想到大家能够和平相处,看来天皇陛下说的“大东亚共荣圈”不是骗人呢。""")
num_all += 2
Quastion1_4_1=input("你的回答是……(回答1、2)")
if Quastion1_4_1=="1":
print("【军犯下滔天罪行,中国人岂会轻易忘记?】")
print("""冈山爱:滔天罪行……是什么?
你不想回答,但在冈山爱的苦苦追问下,你再也控制不住自己的巴抚顺惨案、宁武血案、成安三屠、南京大屠杀……
你把自己所了解的事实全部倾吐出来,狠狠打击这个什么都不知道的女人。
冈山爱:谢谢你,告诉我历史的真相。""")
diliuzhang = 1
copy1_4()
if Quastion1_4_1=="2":
print("【当然。中国人民打心眼里感激日本人呢!】")
print("冈山爱:谢谢你,我很高兴!")
copy1_4()
if Quastion1_4 == "推脱":
print("冈山雄二:既然你在通讯社还有很多事情要做,我就不勉强你了。")
print("""送女儿返回日本后,冈山雄二又把你叫到大使馆。
冈山雄二:方君,我很欣赏你搜集情报的能力。希望你以后能继续为我办事。作为报酬,每月我都会给你300元的交际费。你意下如何?""")
Quastion1_5=input("你的回答是……")
if Quastion1_5=="1":
print("【为领事效命是我应该做的!钱我坚决不要!】")
if num_all<8:
copy1_5_1()
break
else:
copy1_5_2()
if Quastion1_5=="2":
print("【当然愿意!那我就不客气了……】")
num_all += 1
if num_all<8:
copy1_5_1()
break
else:
copy1_5_2()
if Quastion1_5=="3":
print("【愿意是愿意……只是300元有点……】")
num_all+=2
if num_all<8:
copy1_5_1()
break
else:
copy1_5_2()
print("剧终")
三、其他游戏基础功能
1. 页面可视化
Python实现页面可视化的库有很多,我这边采取pygame库作为示例。
import pygame,sys
from pygame.locals import *
pygame.init() #初始化pygame
windowSurface=pygame.display.set_mode((956,534),0,32) #创建图形化用户界面,使用元组,创建500*400像素的窗口
#因为使用的是元组,所以窗口大小不可变
pygame.display.set_caption("潜伏之赤途")
#设置颜色
BLACK=(0,0,0)
#给背景画上黑色
windowSurface.fill(BLACK)
background1_1 = pygame.image.load('fengmian.png') #把你的图片放在项目代码同等的文件夹里
# 将图片绘制到窗口上
windowSurface.blit(background1_1, (0, 0))
# update更新屏幕显示
pygame.display.update()
while True:
for event in pygame.event.get():
if event.type==QUIT:
pygame.quit()
sys.exit()
利用元组设置颜色变量。我只设置了黑色,对应的表格如下:
颜色 | RGB值 |
---|---|
Black | (0,0,0) |
Blue | (0,0,255) |
Green | (0,128,0) |
Gray | (128,128,128) |
Lime | (0,255,0) |
Purple | (128,0,128) |
Red | (255,0,0) |
Teal | (0,128,128) |
White | (255,255,255) |
Yellow | (255,255,0) |
① 图像绘制与调用
background1_1 = pygame.image.load('fengmian.png') #把你的图片放在项目代码同等的文件夹里
pygame.display.update()# update更新屏幕显示
对象的blit()方法将一个Surface对象的内容绘制到另一个Surface对象之上。
然后,利用pygame.display.update()函数,显示更新后的Surface对象。
为了节省内存,我们并不是每次调用了绘图函数之后,都更新到屏幕上,只有在绘制函数都调用完之后,才想要一次性更新屏幕。
② 事件与游戏循环
游戏循环是不断地查看新事件、更新窗口状态并在屏幕上绘制窗口的一个循环。任何时候,当用户按下一个按键、点击或移动鼠标或使其他一些事件发生的时候,pygame都会创建该对象。事件(event)是pygame.event.Event函数的对象。
while True:
#将while语句的条件设为True,则会一直循环。唯一推出的方式即是我在下面设置一个事件满足了某条件导致程序终止。
while True:
for event in pygame.event.get():
if event.type==QUIT:
pygame.quit()
sys.exit()
调用pygame.event.get()函数检索自上次调用该函数后所生成的任何新的pygame.event.Event对象。这些事件会以Event对象的一个列表形式返回。所有Event对象都有一个叫做type的属性,告诉我们事件是什么类型。
当事件的类型event.type为QUIT时,程序就调用pygame.quit()和sys.quit()关闭程序。
参考资料:《Python游戏编程快速上手(第四版)》 AI Sweigart 著
2. 下个文章继续——按钮设置、限时机制、图片显示、音频播放、游戏存档
有空继续写。