选择菜单与多 Label
# 选择菜单与多 Label
注意!!!
本文将假定您有一定的 Python 基础,因为本文涉及到变量,虽然也很简单,但我仍建议您在了解 Python 基础知识后再来完成本教程。
这一次我们所接触的东西可能会比较复杂,但它可以为你的 Mod 注入灵魂。
# 选项菜单
让我们先复习一下上节课学的脚本:
label ch1_start:
stop music fadeout 2.0
scene bg club_day with dissolve_scene_full
"今天是学园祭的第一天。"
show monika 2 at t42 zorder 2
m "好了,各位!我们开始准备吧!"
show sayori 4r at t43 zorder 2
s @1r "耶!小饼干!"
show natsuki 2l at t41 zorder 2
n "要不也来尝下我的纸杯蛋糕?"
show yuri 3m at t44 zorder 2
y "...其实都可以了。"
mc "总之,以后也要多多关照!"
如果只是单纯的让角色说话,与玩家没有任何的互动,是不是很枯燥无味?因此,我们需要给游戏增加一些与玩家的互动,比如一个选项菜单。 简单来说,通过一个选项菜单,游戏能够给玩家提供一或多个选项,玩家选择一个选项后,通常有相应的回应,例如一段剧情。
试试下面的代码:
label ch1_start:
stop music fadeout 2.0
scene bg club_day with dissolve_scene_full
"今天是学园祭的第一天。"
show monika 2 at t42
m "好了,各位!我们开始准备吧!"
show sayori 4r at t43
s "耶!小饼干!"
show natsuki 2l at t41
n "要不也来尝下我的纸杯蛋糕?"
show yuri 3m at t44
y "...其实都可以了。"
menu:
"那么,我该先吃些什么呢?"
"纸杯蛋糕":
n "怎么样,是不是很好吃啊?"
"小饼干":
s "怎么样,是不是很好吃?"
mc "总之,以后也要多多关照!"
运行代码,你会发现剧情里多了一个选择菜单,询问我们是要吃纸杯蛋糕还是小饼干。
这是 menu 的基本语法:
menu:
"我是一个菜单" # 文本框内显示的内容。
"选项 1": # 选项名称
# 选择此项后所发生的事件。
"选项 2": # 选项名称
# 选择此项后所发生的事件。
... # 可以添加更多选项。
注意!
上面的 :
和 ""
都必须使用英文符号。
现在,尝试着理解一下下面的代码,并运行一下。
label ch1_start:
stop music fadeout 2.0
scene bg club_day with dissolve_scene_full
"今天是学园祭的第一天。"
show monika 2 at t42
m "好了,各位!我们开始准备吧!"
show sayori 4r at t43
s "耶!小饼干!"
show natsuki 2l at t41
n "要不也来尝下我的纸杯蛋糕?"
show yuri 3m at t44
y "...其实都可以了。"
menu:
"那么,我该先吃些什么呢?"
"纸杯蛋糕":
n "怎么样,是不是很好吃啊?"
"小饼干":
s "怎么样,是不是很好吃?"
menu:
"我该先和谁交流?"
"纱世里":
s "你好啊!在文学部感觉怎么样?"
"莫妮卡":
m "嗨,有什么事吗?"
"夏树":
n "哼,看我干什么?"
"优里":
y "你好..."
mc "总之,以后也要多多关照!"
提示
不理解上面的脚本吗?没关系,看了下面的解释,你大概就会懂了。
在 Ren'Py 中,$
与 [init] [优先级] python [hide/early]/[in ...]:
都表示 Python 语句。区别为 $
开头的语句只有后续单行的代码被视为 Python 语句,而 包含在 [init] python [hide/early]/[in <变量名>]:
块中的代码全部被视为 Python 代码
python hide
:以匿名者视角运行,允许使用不能被保存的临时变量。python in <变量名>
:以下的 Python 语句被放在<变量名>
储存区中允许,若要使用在其代码块中定义的变量、函数等,需以<变量名>.<变量名、函数名...>
init [优先级] python
:以下 Python 语句将在游戏初始化阶运行。可以在init
与python
之前加上一个整数表示运行优先级。数字越大代表越往后运行,越小则越先运行,默认优先级为 0。我们不建议您将优先级设为负数,具体原因将在后续章节解释。
# 多 Label
在剧情里,我们常常会需要编写多个分支,如果剧情只围绕一个分支来讲述故事,那么一定是很枯燥的。这时候,就需要定义多个 label。
label ch1_start:
stop music fadeout 2.0
scene bg club_day with dissolve_scene_full
play music t1
"今天是学园祭的第一天。"
show monika 2 at t42
m "好了,各位!我们开始准备吧!"
show sayori 4r at t43
s "耶!小饼干!"
show natsuki 2l at t41
n "要不也来尝下我的纸杯蛋糕?"
show yuri 3m at t44
y "...其实都可以了。"
menu:
"那么,我该先吃些什么呢?"
"纸杯蛋糕":
n "怎么样,是不是很好吃啊?"
call ch1_natsuki
"小饼干":
s "怎么样,是不是很好吃?"
call ch1_sayori
mc "总之,以后也要多多关照!"
return
label ch1_natsuki:
"您已进入夏树分支"
return
label ch1_sayori:
"您已进入纱世里分支"
return
运行上面的代码后,我们会看到在选择完吃哪个食物时,会提示进入到了 xxx 分支,然后会返回到主脚本里。
这就是多 label,当然多个 label 也可以分在多个 rpy 文件里,Ren'Py 会初始化所有 rpy 文件里的 label。
# return
其中,你应该能注意到 return
,这个语句相当于返回上级,这个概念比较复杂,但如果两个节点属于并列状态,你必须在每个节点末尾添加 return
。在本例中,如果不添加 return
的话,等价于以下效果:
# 假定你选择的是夏树的纸杯蛋糕
label ch1_natsuki:
"您已进入夏树分支"
label ch1_sayori:
"您已进入纱世里分支"
即:
"您已进入夏树分支"
"您已进入纱世里分支"
意味着,只要你选择夏树的分支,那么就会同时出现 "您已进入夏树分支"
和 "您已进入纱世里分支"
两句对话。
在 Ren'Py 里,有两种方法可以跳转到其他分支里,call
和 jump
。接下来,我会介绍 call
和jump
的区别。
# call
call
的语法如下:
call <label 名称>
call 的作用是调用分支,如下例:
label a:
"你好!"
call b
"你已回到 a 分支。"
return
label b:
"你已进入 b 分支。"
return
执行这个脚本,你会发现在旁白说完 你好
后会跳入 b 分支并提示 你已进入 b 分支
,然后会回到 a 分支并提示 你已返回 a 分支
。
可以看到,call 的作用就是在一个 label 里调用另一个 label,在另一个 label 里的脚本 return 后会跳回到原先的 label 并继续执行。
# jump
jump
格式如下:
jump <label 名称>
jump
的作用是跳转,如下例:
label a:
"你好!"
jump b
"你已回到 a 分支。"
return
label b:
"你已进入 b 分支。"
return
执行这个脚本,你会发现旁白在说完 你好
和 你已进入 b 分支
后并不会说 你已回到 a 分支
。
可以看到,jump 的作用就是从一个脚本里跳转到另一个脚本。
提示
jump 与 call 的不同点是:
- call 执行完另一个 label 里的内容后会跳回原 label。
- 而 jump 执行另一个 label 里的内容后不会跳回原 label。
扩展知识
调用 call
和 jump
时想要使用表达式运算 label 名?只需要在 call
或 jump
后面加上 expression
。如下:
label main:
$ chapter = 1
stop music fadeout 2.0
scene bg club_day with dissolve_scene_full
play music t1
"今天是学园祭的第一天。"
show monika 2 at t42
m "好了,各位!我们开始准备吧!"
show sayori 4r at t43
s "耶!小饼干!"
show natsuki 2l at t41
n "要不也来尝下我的纸杯蛋糕?"
show yuri 3m at t44
y "...其实都可以了。"
menu:
"那么,我该先吃些什么呢?"
"纸杯蛋糕":
n "怎么样,是不是很好吃啊?"
$ winner = "natsuki"
"小饼干":
s "怎么样,是不是很好吃?"
$ winner = "sayori"
scene bg club_day with wipeleft_scene
mc "总之,以后也要多多关照!"
call expression ("ch" + str(chapter) + "_" + winner)
"第二天"
call expression ("ch" + str(chapter) + "_" + winner)
return
label ch1_natsuki:
"您已进入夏树分支"
$ chapter = 2
return
label ch1_sayori:
"您已进入纱世里分支"
$ chapter = 2
return
label ch2_sayori:
"您已进入第二章的纱世里分支"
return
label ch2_natsuki:
"您已进入第二章的夏树分支"
return
另外,所有 label 不必要放在一个文件里,可以存放于多个 rpy 文件内,如下例:
script-ch1.rpy:
label ch1_start:
stop music fadeout 2.0
scene bg club_day with dissolve_scene_full
play music t1
"今天是学园祭的第一天。"
show monika 2 at t42
m "好了,各位!我们开始准备吧!"
show sayori 4r at t43
s "耶!小饼干!"
show natsuki 2l at t41
n "要不也来尝下我的纸杯蛋糕?"
show yuri 3m at t44
y "...其实都可以了。"
menu:
"那么,我该先吃些什么呢?"
"纸杯蛋糕":
n "怎么样,是不是很好吃啊?"
call ch1_natsuki
"小饼干":
s "怎么样,是不是很好吃?"
call ch1_sayori
mc "总之,以后也要多多关照!"
return
script-ch1_2.rpy:
label ch1_natsuki:
stop music fadeout 2.0
"您已进入夏树分支"
return
label ch1_sayori:
stop music fadeout 2.0
"您已进入纱世里分支"
return
执行 script-ch1.rpy,我们可以发现即使 label ch1_natsuki
、ch1_sayori
、ch1_start
放在不同的文件里,脚本依然可以正常运行。
# 可是,Label 到底是什么?
好问题。Label,你可以把它理解为“视觉小说脚本的片段”,或者是“一个书签”,它在 Ren'Py 中起到“随叫随到”的作用。像 script.rpy
中的 call ch1_start
那样,
# 本章原作者
@PartyParrot359 (opens new window)