This page is out of date

You've reached a page on the Ren'Py wiki. Due to massive spam, the wiki hasn't been updated in over 5 years, and much of the information here is very out of date. We've kept it because some of it is of historic interest, but all the information relevant to modern versions of Ren'Py has been moved elsewhere.

Some places to look are:

Please do not create new links to this page.


关于Ren'Py语言

这一部分讲述Ren'Py语言的概况及其功能。

脚本、行与块结构

Ren'Py脚本由一个或多个.rpy文件构成。 这些脚本文件的命名没什么特别的限制,可以是任何顺序,它们一起组成Ren'Py的脚本。 请参见../The Ren'Py Runtime Environment/,里面有Ren'Py启动时是如何检查.rpy文件的信息。

这些文件各自被分成“逻辑行”(logical lines)。 一个文件的逻辑行由第一行开始,一个逻辑行结束后开始另一个逻辑行,直到文件末端为止。 缺省方式下,一个新行的出现终结上一个逻辑行。 不过,当出现下述情况时,一行将结束:

Ren'Py脚本同样也有注释(comments)。 注释用符号“#”开始,其后的所有内容都是注释,但不包括下一行的字符。 这儿是一些例子:

# 这一行只是注释。
scene bg whitehouse # 从这开始也是注释

如果在注释结束之后,逻辑行为空,那么该逻辑行将被忽略。

于是,逻辑行形成了“块”(blocks)。 如果在两个逻辑行之前有着同样的缩进(indentation),同时在这两行中间没有比它们的缩进更小的逻辑行出现,那么这两行就组成一个块。 注意:缩进只能由空格(space)组成,不能是制表符(tab)。 看下面这个例子:

line 1
    line a
    line b
line 2
    line c
    line d

这个例子中,有3个块。 一个块包含了lines1和lines2,另一个包含了lines a和b,第三个包含了lines c和d。这个例子很好的诠释了块与行的关系。 如果一个块在一行的下面开始,那么这个块就和这一行连结起来。 比如,含有lines a和b的块就行line 1连结起来。

在Ren'Py程序中有3种块。 最常见的是含有Ren'Py语句的块。 块也包含选择肢或Python代码。 最顶级的块(就是包含一个文件第一行的)总是一个Ren'Py语句块。

语法构造

在讲述Ren'Py的语句之前,我们得先谈一谈生成这些语句的语法构造。

“关键词”(keyword)是指必须完整地出现在源码中的词。 它们用来表明语句的开始或界定语句的范围。 在语句你随处都可看到关键词。 在语法规则中,关键词是要加引号的。 Ren'Py使用的关键词有:

at
call
elif
else
expression
hide
if
image
init
jump
label
menu
onlayer
pass
python
return
scene
set
show
while
with
zorder

一个“名称”(name)是由字母或下划线(_)开始,其后可接字母,数字或下划线。 基于此目的,U+00a0到U+fffd的统一码(unicode) 都被当作是字母。 一个名称不可以是关键词。 一“简单的表达式”(simple expression)是一个以名称,字符串开头的Python表达式,或任何在括号中的Python表达式。 在其之后可接下述的任一对象:

“Python表达式”(python_expression)是一个带有冒号的任意Python表达式。 这种表达式通常用来在if和while语句中表达某种条件。

“图像名称”(image_name)由多个以空格分开的名称组成。 图像名称的第一个名称将作为“图像标签”(image tag)。

image_spec -> image_name ( "onlayer" name) ( "at" transform_list )? ( "with" simple_expression )?

“图像规格”由图像名称,可选的’onlayer‘关键词,可选的'at’子句,以及一系列由逗号分开的简单表达式以及可选的’with’子句构成。

语法规则

这里将讲述一些语句的语法规则。 在这些规则中,引号中的词必须完整地出现在脚本中。 括号的作用是将东西组群,但它们在脚本中不对应任何物事。 Star, question mark, and plus are used to indicate that the token or group they are to the right of can occur zero or more, zero or one, or one or more times, respectively.

如果我们给一个规则起了个名字,我们将用(->)这个箭头符号来分开。

调用语句(Call Statement)

调用语句是用来将控制传递给给定名称的语句。 它将其后的语句名放入调用堆栈(call stack),并用返回语句(return statement)将控制返还给其后的语句。

call_statement -> "call" name ( "from" name )?
call_statement -> "call" "expression" simple_expression ( "from" name )?

如果”expression”关键词存在,就会执行表达式,而字符串就被当作语句名称来调用。 如果”expression”关键词不存在,就必须明确给出要调用的语句名。

如果存在可选的’from’子句,它的效果就是使给定的标签语句作为直接跟在call语句后面的语句。 这里需要一个明确的标签,以确保读取进度时能返回到正确的call语句。 在发布游戏时,所有的call语句都必须包含from子句。`

由于在开发游戏时,如果时时都要注意到from子句的话,的确是件让人头痛的事。所以我们提供了一个名叫‘add_from’的工具,它能给所有的call语句加上from子句。这在发布游戏时很有用。 它能在`tools/add_from`目录中找到,尽管它需要在基本目录中运行。 在windows平台上使用它的最简单方式就是运行`tools/game_add_from.bat`。 在你最终发布游戏时必须要运行。 在运行前请注意备份你的游戏目录,以防不测。 还有一点要注意,'add_from’会为所有的文件生成备份文件(后缀名为.bak的文件),所以当你对所有的工作都感到满意后,删掉这些备份文件。

e "首先,我们来调用一个子程序(subtoutine)。"

call subroutine from _call_site_1

# ...

label subroutine:

    e "接下来,我们由子程序返回。"

    return

隐藏语句(Hide Statement)

隐藏语句(hide)是用来从屏幕上清除图像。

hide_statement -> "hide" image_spec

隐藏语句执行的图层由图像规格的onlayer子句而定,缺省为主图层(master)。 如果在一个图像规格中图像名称的图像标签和hide语句的图你标签相同,它就从那个图层移除那个图像。

请注意, hide语句在实际中其实很少用到。 Show语句本身就能够实现角色的表情、姿势变换,而scene语句可以移除屏幕上的所有图像。 一般而言,hide语句只是在表现角色离开时才会用到。

条件语句之一__If语句(If Statement)

If语句是用来有条件地执行一个块当中的语句。

if_statement -> "if" python_expression ":"
elif_clause -> "elif" python_expression ":"
else_clause -> "else" ":"

If语句是唯一的一个由同一块中复数的逻辑行组成的语句。 起始的if语句后面可接0个或多个elif子句,以一个可选的else子句结束。 该表达式会依次取值,如果值为真,就执行其相关的块。 如果没有为真的值,就执行else子句。 (如果else子句不存在,就直接执行后面的语句。) 不管怎样,块结束后,控制权都后移交给if 语句之后语句。

if points >= 10:

   e "恭喜!你达成Best Ending!"

elif points >= 5:

   e "这是个Good Ending。"

else:

   e "抱歉,这是个Bad Ending。"

图像语句(Image Statement)

图像(image)语句在Ren'Py中用来声明图像。 图像语句只能出现在初始块(init block)中。

image_statement -> "image" image_name "=" python_expression

图像语句的作用是将一个图像名称连结到显示体(displayable)。 显示体是由提供的Python表达式计算,在粗放模式下,计算的结果将被传递到im.Image函数。 这就意味着如果赋值是一个单一字符串,它将被解释为一个图像的文件名。 显示体将被无损传送。 一个图像一旦被image语句定义过后,它就能在scene, show及hide语句中使用。

init:
    image eileen happy = "eileen/happy.png"
    image eileen upset = "eileen/upset.png"

初始语句(Init Statement)

初始(init)语句的作用是在执行脚本前预先执行的一些关于全局配置的语句。 初始语句块(init blocks)的作用是用来定义图像,角色,一些固定的文件数据结构以及进行一些Ren'Py的自定义设置。 初始语句块中不能含有用户交互语句,不能改变游戏的图层设置,同时也不能含有say, menu, scene, show或是hide等语句,当然,也不能调用含有上述东西的函数。

init_statement -> "init" (number)? ":"

初始语句以关键词’init’开头,后边跟有一个可选的优先级序号(priority number),还有一个强制的冒号。 如果没有给定优先级序号,缺省为0。

优先级序号的作用是用来确定初始块中的语句执行顺序, 该顺序是由低至高。 在同一文件中,相同顺位的初始块按从上到下的顺序执行。 文件之间的相同顺位初始块的执行顺序没有定义。

在特别的初始阶段(init phase),所有的初始块只会运行一次。 在通常运行中,当控制权达到块的终结点,块的执行结束。 如果在通常运行中遇到初始语句,该语句不会被运行。 这时,控制权传递到下一个语句。

跳转语句(Jump Statement)

跳转(jump)语句是用来将控制权传递给给定名称的语句。

jump_statement -> "jump" name
jump_statement -> "jump" "expression" simple_expression

如果'expression'关键词存在,就会执行表达式,而字符串就被当作语句名称来跳转。 如果”expression”关键词不存在,就必须明确给出要跳转的语句名。

和call语句不同,jump不会将目标放入任何堆栈。 因此,你无法返回到你开始跳转的地方。

label loop_start:

e "哎,糟糕!看来我们陷入了一个无限循环。"

jump loop_start

标签语句(Label Statement)

标签(label)语句的作用是赋给一个程序点名字。 它们独立存在以待被调用或跳转,不管是在脚本代码中还是在Ren'Py库中。

label_statement -> "label" name ":"

一个标签语句可能会有一个和它连结的块。 在那种情况下,一旦触及到标签,无论是否达到块的终结点,控制权便移交到块,并开始执行标签语句后面的语句。

选择肢语句(Menu Statement)

选择肢(menu)是用来给玩家复数的选项。 在AVG游戏中,选择肢是玩家影响情节的首要手段。

menu_statement -> "menu" ( name )? ":"

选择肢(menu)语句以关键词menu开头,后接一个开选的名称和一个必须的冒号。 如果有提供名称,它将作为选择肢的标签,好比在选择肢语句前有一个标签语句。

一个标签语句必须有一个和它连结的块。 在这个选项块中必须有一个或多个选项。 在选项块中有好几种不同的选择肢要素。

caption_menuitem -> string

第一种选择肢要素是字符串。 在选择肢中的字符串会被当作选项的标题,而不是当作选项。 通常而言,标题的作用是提示这些选项是干什么用的,尤其是在仅从选项字面无法判断时。

choice_menuitem -> string ( "if" python_expression )? ":"

第二种选择肢要素就是给玩家的选项。 每一个选项必须有一处Ren'Py的语句块和它连结。 如果玩家做出某个选择,就执行和它连结的语句块。 选项也可以带有可选的含有Python表达式的if子句。 该子句给定了一个玩家需满足的条件。 行末跟有冒号表明该选择肢要素是个选项。

with_menuitem -> "with" simple_expression

最后一种选择肢要素是with子句。 请参看../Transitions/以获得更多关于'with'的信息。

menu 干什么呢?:

    "今天该做什么呢?"  #这是选项标题。

    "去看电影":  #这是选项一。
        "我们去看了电影。"

    "去购物":  #这是选项二。
        "我们去购物了,女孩们买了泳装。"
        $ have_swimsuits = True

    "去海边" if have_swimsuits:
        "我们一起去了海边,看见女孩们穿上了新泳装。"

细节

当显示选择肢的时候,第一件事就是出现选项标题与选项。 每个选项都有一个与之相连的表达式,如果取值为真,就执行该选项,反之,则不执行。 如果没有任何一个选项符合条件,选择肢就不会出现,而是直接执行后面的语句。 另外,选择肢函数被调用时,在屏幕上出现一些选项,然后返回选择的值。 接着就执行选项相应的块。 如果语句的执行到达块的终点,就继续执行其后的语句。

注意: 详述选择肢函数

跳过语句。(Pass Statement)

pass(跳过)语句不执行任何动作。 它之所以存在是因为在Ren'Py语句块中需要至少一个语句,同时对在那些块中执行一个动作并不敏感。

pass_statement -> "pass"

menu:
    "我应该去看电影吗?"

    "是的":
        call go_see_movie

    "不":
        pass

"快要到吃饭时间了,肚子也饿了。"

Python语句(Python Statement)

Python语句的作用是在Ren'Py脚本中执行Python代码。 它可以用来为Ren'Py声明一些东西,或是调用Ren'Py的大多数功能,或是用变量储存一些数据以便玩家访问。 有两种形式的python语句。

python_statement -> "$" python_code
python_statement -> "python" ( "hide" )? ":"

一种是以美元符号$开头,在其之后的这一行都将是Python代码。 通常用这种形式来执行一句单一的Python语句。

第二种是以关键词python打头,后接一个可选的关键词hide,以及一个必须的冒号。 这是用来在语句之后执行一段Python代码块。 通常,Python代码在全局脚本名称集中执行,不过如果给定了hide关键词,将在这个块中创建一个名称集。 (可以在该块中访问全局脚本名称集,但不能指派值。)

$ score += 1

python:
    ui.text("这是一个在屏幕上出现的文本。")
    ui.saybehavior()
    ui.interact()

返回语句(Return Statement)

Retrun(返回)语句的作用是终止call堆栈,并转换控制权。 如果call堆栈为空,则执行Ren'Py的完全重启。

return_statement -> "return"

说语句(Say Statement)

Say(说)语句的作用是在屏幕上以对方或内心活动的形式显示文本。 因为脚本的大多数都是对话与心理活动,所以语句要设计得越方便越好。 基于此,say语句是唯一一个不需要关键词和定界符的语句。 它由字符串组成,在其之前可以有可选的简单表达式,用以指明是谁在说话,在其后可以有一个可选的with子句,用以指定过渡效果。

say_statement -> ( simple_expression )? string ( "with" simple_expression )?

根据是否提供有简单表达式,say语句有两种表现形式。 一种是由单一字符串构成(带有或不带有with子句)。 这种形式在屏幕上显示一段没有说话人姓名标签的字符串。 按照惯例,这种形式常用来表现第一人称角色的内心活动或是旁白。

"我向左边移动,而她向右边靠过去。"

"所以我们仍然堵着对方的路。"

"于是我向我的右手边移过去,同时她也向她的左手边移去。"

"看来我们今天是走不了了。"

另一种是带有参数的形式。由简单表达式和可选的with子句构成。 这种形式通常用于对话。 第一个参数通常是对象(object),或是对象。这些对象的作用是决定对话显示的方式。 字符串将传递给这些对象,它们负责将对话展现在玩家面前。

简单表达式不仅能是一个对象,也可以是一个字符串。 这个字符串用来直接指定角色名。

"Girl" "嗨,我叫Eileen."

e "从今天开始,我将住在这儿。"

详述

第二种形式,也就是两参数说语句(two-argument say statement),会先取简单表达的值。 然后它会在给定的对话台词中的字符串(wha字符串)尝试调用who值。 如果可以运行,它就结束,因为被调用的对象将负责把对话显示在屏幕上。

如果不能运行,它就以who值和what字符串为参数调用say函数。 这时say函数就负责将对话显示在屏幕上。

单参数形式只是简单地以字符串为参数调用一个特别的narrator函数(或对象)。 这个函数负责在屏幕上显示文本。 和对象作为narrator使用也是可以的。

With子句是用来指定过渡效果的,参见with语句和子句以获取详细信息。

场景语句(Scene Statement)

scene语句的作用是以移除所有图像的方式来清除图层。 然后在屏幕上显示一张给定的图片。 通常用这来更换背景。

scene_statement -> "scene" ("onlayer" name | image_spec )?

Scene语句首先将图层中的所有图像清除。 清除的图层由image_spec或onlayer的子句而定,如果有子句的话。 如果没有指定特定图层的话将使用master(主图层)。

如果有image_spec,将以show语句将其加在图层中。

在缺省方式下,屏幕上不会添加任何背景,所以我们建议每个脚本都以scene语句开头,这样能在屏幕上形成一个全屏背景。

显示语句(Show Statement)

Show语句的作用是将指写的图像放入指定的图层,如果没有onlayer子句的话将放入主图层(master)。

show_statement -> "show" image_spec

Show语句首先会将一个显示体添加到屏幕上。 完成这个过程首先要在图像注册列表中查找图像名称。 然后再将变换应用到显示体的at列表。 这样图像就被添加到图层中。 然后show语句就开始检查在当前图层是否存在相同的图像标签。 如果存在那样的图像,就用新图像替换它。 否则,就直接将新图像添加到图层中,并且位于以前的图像之上。

scene living_room
show eileen happy at left

e "我现在觉得挺开心。"

show eileen upset at left

e "不过有时,我会不明究理地生气。"

with语句与子句(With Statement and Clauses)

With语句和with子句的作用是用来显示过渡效果。 这些过渡效果总是从前一画面过渡到当前画面。 当with语句结束时,最后一个画面就在为当前画面。 最后一个画面也能够被say, menu语句及python代码更新。

With语句的形式如下:

with_statement -> "with" simple_expression

简单表达式要求取一个过渡函数的值。 如果取值为None,则前画面更新为当前画面,不执行任何过渡效果。 如果不想让暂存界面要素(transient interface items)参与到过渡效果中时,这是非常有用的。

出于便利考虑,很多语句都支持with子句。 比如说,在scene, show及hide语句后跟有with子句的话,等价于在先在scene, show,及hide语句前写上一个with None,然后在其后加上一个with过渡效果的语句。 例如这语句:

show eileen happy with dissolve

等价于:

with None
show eileen happy
with dissolve

这种行为会导致一些不需要的副作用。 代码:

show bg whitehouse with dissolve
show eileen happy with dissolve

这样会出现两个过渡效果。 要确保只出现一个过渡效果,得这么写:

with None
show bg whitehouse
show eileen happy
with dissolve

With子句也能像这样应用到say和menu语句。 这样的话,过渡效果就只会在第一次出现时展现在玩家面前。

至于如何在脚本中使用预定义的过渡效果,参见示例。 关于返回过渡效果函数的内容,参见../Transitions/

While语句(While Statement)

While语句的作用是在当给定条件持续为真的情况,执行一段Ren'Py语句块。

while_statement -> "while" python_expression ":"

当一个while语句执行时,要求取python表达式的值。 如果取值为True(真),控制权将转移到连结while语句的块的第一行语句。 如果为False(假),控制权将传递给其后的while语句。

当控制权到达连结while语句的块的终结点时,返回到while语句。 这样就使while语句再次检查条件,并取值看是否为True。

while not endgame:

   "早上了。一天之计在于晨,该起床了。"

    call morning
    call afternoon
    call evening

    "嗯,时间不早了。"

"现在该醒来面对终章了。"