变换

变换(transform)可以按顺序依次使用,将一个 可视组件 变为另一个可视组件。 总共有多种类型的变换,也有多种方式创建变换。 内建的变换常用于控制界面上某个对象的位置,而用户自定义的变换可以触发更复杂的效果,比如移动、缩放和旋转,甚至复杂的色彩效果。

快速入门

在scene和 show 语句后使用at分句就能应用各种变换。 下面样例中对图像 eileen happy 应用了 right 变换:

show eileen happy at right

可以同时应用多个变换,不同变换之间用英文逗号分隔。这些变换从左到右依次应用。

show eileen happy at halfsize, right

简单ATL变换:

transform slide_right:
    xalign 0.0
    linear 1.0 xalign 1.0

label start:
    show eileen happy at slide_right
    pause

使用Python显示变换:

label start:
    $ renpy.show("eileen happy", at_list=right)
    pause

使用 At() 的简单Python变换:

init python:
    def show_eileen_rotated():
        rotated = Transform(rotate=45)
        show_stmt = At("eileen happy", rotated)
        renpy.show("eileen", what=show_stmt)

label start:
    $ show_eileen_rotated()
    pause

内建变换

Ren’Py附带了一些默认定义好的变换。这些变换定义了界面上的位置信息。这里有一个默认变换下图像位置的描述:

             +-----------------------------------------------------------+
             |topleft, reset               top                   topright|
             |                                                           |
             |                                                           |
             |                                                           |
             |                                                           |
             |                          truecenter                       |
             |                                                           |
             |                                                           |
             |                                                           |
             |                                                           |
offscreenleft|left                   center, default                right|offscreenright
             +-----------------------------------------------------------+

offscreenleftoffscreenright 变换会让图像显示在界面之外。这两个变换可以用于将物体从界面移除(记得之后隐藏这些物体,并确认他们不再消耗系统资源)。

这些变换(transform)的详细信息如下:

center

水平居中,并与界面底部对齐。

default

水平居中,并与界面底部对齐。default可以通过 config.default_transform 重定义,这样show和scene语句显示的图片默认位置也会改变

left

与界面左下角对齐。

offscreenleft

将可视组件置于界面左外侧,与界面底部对齐。

offscreenright

将可视组件置于界面右外侧,与界面底部对齐。

reset

将所有变换特性的值都重置为默认值。

right

与界面右下角对齐。

top

水平居中,与界面顶部对齐。

topleft

与界面左上角对齐。

topright

与界面右上角对齐。

truecenter

水平和垂直都居中。

动画和变换语言

动画和变换语言(简称ATL)提供了一种高级方式,便于创建动画、界面内移动可视组件、设置组件位置、应用各种变换(等。 ATL语言可以根据时间变化实现效果,也可以根据事件类消息做出响应。

在Python中,与ATL变换等效的是 Transform() 类组件。目前没有办法通过编程创建一个ATL变换效果。

可以使用 transform语句 创建ATL变换对象。创建结果可用作可视组件(可能没有能被看到的子组件所以透明)。 ATL变换对象可以使用 add 传入某个界面,或者使用 show expression语句renpy.show() 函数直接显示。

Ren’Py脚本语句

ATL可以包含在Ren’Py脚本语句中。

transform语句

transform 语句会创建一个新的变换,可以在游戏中用于可视组件设置坐标和动画。 变换是可以复用的,使用 showscene 加上 at 从句就能将变换应用在图像和其他可视组件上。

变换也可以像 可视组件 一样直接显示。与可视组件存储在全局image命名空间(详见 定义图像(image))中不同,变换会以变量的形式存储在各合适的 命名存储区 中(或默认存储区)。

游戏启动时在 初始化阶段 创建变换。

语法

基本格式:

transform <transform_name>:
    <atl_block>

带参数的格式:

transform <transform_name>( <parameters> ):
    <atl_block>

使用方法

名称

类型

描述

transform_name

word

变换的名称。

必须是合法Python名,可使用英文符号“.”分隔。

(例如,my_transformsprites.bounce)

parameters

(可选)变换的参数。

atl_block

block

ATL代码块,定义变换。

创作者可以给变换添加参数,提高其灵活性和可复用性。参数的用法与Python中函数的参数类似。

目前不支持的参数用法如下:

  • 只有固定位置参数 (使用 /)。

  • 只有关键字参数(位于 * 之后且无默认值)。

  • *args (可变的固定位置参数)。

  • **kwargs (可变的关键字参数)。

Note

样例

transform left_to_right:
    xalign 0.
    linear 2 xalign 1.
    repeat

transform ariana.left:
    xalign .3

transform animated_ariana_disp(duration=1.0):
    "ariana"
    pause duration
    "ariana_reverse"
    pause duration
    repeat

label start:
    show eileen happy at left_to_right
    pause
    show animated_ariana_disp
    pause

带ATL语句块的image语句

使用ATL的另一种方法是,在 images 语句中包含ATL语句块。这将某个图像与给定的transform绑定。由于没有办法向该transform传入参数,所以只在transform自身定义了某个动画的情况下才有用。

语法

image <image_name>:
    <atl_block>

使用方法

名称

类型

描述

image_name

word(s)

图像名称

atl_block

block

ATL代码块,定义变换。

样例

image animated_ariana_img:
    "ariana"
    pause 1.
    "ariana_reverse"
    pause 1.
    repeat

带ATL语句块的scene和show语句

最后一种使用ATL的方法是,包含在 scene 或者 show 语句中。这种方法可以通过ATL改变图像。

语法

show <image_name>:
    <atl_block>

scene <image_name>:
    <atl_block>

使用方法

名称

类型

描述

image_name

word(s)

图像名称

atl_block

block

ATL代码块,定义变换。

样例

show eileen happy:
    xalign 1.

scene bg washington:
    zoom 2.

ATL语法和语义

ATL语句可能是单行的,也可能是多行组成的语句块(block)。 除了后面会提到的少数例外,ATL语句块中的语句按从上到下的顺序执行。

如果某个ATL语句需要计算某个表达式,那么对应的整个变换首次执行时(例如使用 show 语句或将该变换显示为某个界面的一部分时)将计算该表达式, 而不是执行某部分ATL语句时才计算。

下面列出各种ATL语句。

特性值语句

该语句可以将设置变换特性的值。

语法

<property_name> <property_value>

使用方法

名称

类型

描述

property_name

word

变换特性的名称(例如 xalignalpha 等)。

property_value

Varies

特性的值

“特性名”+“新的特性值”是该语句的用法。详见 变换特性 中使用列表形式同时给多个特性复制的方法。

样例

transform rightoid:
    xalign .9

transform ariana.left:
    xanchor .3 xpos 100

数值语句

数值语句可以暂停ATL语句块的执行一段时间,具体时间由给定的数值决定。关键词“pause”可以省略。

语法

pause <duration>

使用方法

名称

类型

描述

“pause”

keyword

(可省略)关键词,提示此处暂停。

duration

float, int (expr)

暂停时间,单位为秒。

样例

transform pause_example(duration=0.5):
    xalign 0.0

    # 暂停2秒。
    pause 2.0
    xalign 1.0

    # 暂停 `duration` 秒。
    pause duration
    xalign 0.5

    # 暂停3秒。
    3.0

    repeat

插值语句

插值语句主要用于获取平滑的动画效果。数值将随着时间从初始值变化为指定值。

warp函数 用于控制插值结果与时间的关系。

语法

基本格式:

<warper_name> <duration> <atl_property> [<atl_property> ...]

使用warp函数:

warp <warper_function> <duration> <atl_property> [<atl_property> ...]

语句块格式:

<warper_name> <duration>:
    <atl_property>
    <atl_property>
    ...

使用方法

名称

类型

描述

warper_name

word

内建warper 名称。

warper_function

str, function (expr)

warp函数和签名 (t: float) -> float

duration

float, int (expr)

整个插值过程总时长,单位为秒。

atl_property

特性值语句

待插值的特性。

整个插值语句的持续时长由给定的时间决定,至少为1帧。

指定的 变换特性 会逐渐逼近终值,并在插值语句结尾达到该终值。

如果某个 变换表达式语句 中只有一条特性(property)语句,也可以进行插值计算。 起始值就是ATL变换中对应特性的值,跟直接设置起点的值效果相同。

样例

基本用法:

show logo base:
    xalign 0.0 yalign 0.0

    # 耗时2秒,让logo移动到左下角。
    linear 2.0 yalign 1.0

使用warp函数:

show logo base(warper_expr="easein"):
    xalign 0.0 yalign 0.0

    # 耗时1秒,使用作为参数传入的warp函数将logo移动到界面最右侧。
    warp warper_expr 1.0 xalign 1.0

处理多个特性:

show logo base:
    xalign 0.0 yalign 0.0

    # 同时改变xalign和yalign
    linear 2.0 xalign 0.5 yalign 0.5

    # 使用语句块实现相同效果。
    linear 2.0:
        xalign 0.5
        yalign 0.5

使用创作者自定义的warp函数:

init python:
    def my_warper(t):
        return t**4.4

    my_warpers = [my_warper]

transform custom_warper_example:
    xpos 0
    warp my_warper 3 xpos 100
    warp my_warpers[0] 5 xpos 520

特性插值

使用样条运动(曲线路径):

<atl_property> knot <knot_value> [knot <knot_value> ...]

名称

类型

描述

knot_value

Varies (expr)

控制节点上对应特性的值

起始点就是插值开始时对应特性的值,结束点表示指定 <atl_property> 的终值。中间的节点(knot)用于控制样条(spline)。

二阶 贝塞尔曲线 只使用1个控制节点(knot),三阶贝塞尔曲线使用2个控制节点。 贝塞尔曲线中间的knot是纯粹的控制节点,通常不在曲线路径上。 Catmull-Rom样条使用3个或更多控制节点,只有首尾两个knot是控制节点(通常不在曲线路径上),其他knot则都在曲线路径上。

transform spline_motion_single_property:
    # 右下角略微放大一点。线性变换。
    zoom 0.5 xalign 1.0 yalign 1.0

    # 逐渐移动到底部中央,略微超过一点再弹回来。使用二阶贝塞尔曲线。
    linear 2.0 xalign 0.5 knot 0.0

    # 移动到顶部,在缓慢回到中心。使用三阶贝塞尔曲线。
    linear 2.0 yalign 0.0 knot 0.2 knot 0.8

    # 移动到左端,往复摆动。使用Catmull-Rom样条。
    linear 2.0 xalign 0.0 knot 1.0 knot 0.5 knot 0.0

transform spline_motion_multi_property:
    # 右下角略微放大一点。线性变换。
    zoom 0.5 align (1.0, 0.0)

    # 使用样条运动,让坐标(x, y)沿轻微的S形轨迹同时移动。
    linear 2.0 align (0.5, 1.0) knot (0.0, .33) knot (1.0, .66)

使用圆周运动:

<atl_property> clockwise
<atl_property> counterclockwise
<atl_property> circles <number_of_circles>

名称

类型

描述

number_of_circles

int (expr)

圆周运动的圈数(一圈等于360度)

Ren’Py处理圆周运动时,首先比较起点与终点位置(通常使用 posalignangleradius 设置), 然后找到极坐标原点(通常使用 around 设置)。接着计算指定方向需要旋转的角度值,单位为度。 如果出现了“circle”从句,Ren’Py则会加上对应数量的整圈。

show logo base:
    xalign 1.0 yalign 0.0

    # 设置旋转中心。
    anchor (0.5, 0.5)

    # 使用圆周运动将logo螺旋转到屏幕顶部。耗时2秒。
    linear 2.0 yalign 0.0 clockwise circles 3

使用transform表达式:

<transform_expression>

名称

类型

描述

transform_expression

Transform (expr)

待插值的变换

如果插值目标是一个表达式,则该表达式应是一个ATL变换且只含有单一特性。 计算时,变换中的单一特性会与直接将该特性写在插值语句中的效果一样。

show logo base:
    xalign 1.0 yalign 0.0

    # 耗时1秒,将logo从当前坐标移动到画面中心。
    ease 1.0 truecenter

pass语句

pass 语句不会触发任何效果:一种 no-op 。

语法

pass

pass语句可以用于分隔其他语句。比如出现两套choice语句的时候(后面会提到),如果不用pass语句,选项会混在一起。 pass语句还可以用在一些语法层面需要出现语句块,但创作者只想要空着的地方,比如某些选项语句后面必须写点什么。

(译者注:pass就是脚本中的占位符。空着不写会报错,写个pass就能运行了。)

repeat语句

repeat 语句会跳转到包含repeat的语句块的开头,并重新开始执行。

语法

基本格式:

repeat

使用count参数:

repeat <count>

使用方法

名称

类型

描述

count

int (expr)

(可选参数)语句块重复执行次数

repeat 2 结尾的语句块至多执行2次,以 repeat 1 结尾则不会重复执行。

repeat语句必须是一段语句块的最后一条语句。

样例

show logo base:
    xalign 0.0
    linear 1.0 xalign 1.0
    linear 1.0 xalign 0.0
    repeat

block语句

block 语句可以将一些语句组织为一个ATL语句块。用于对需要重复运行的语句分组。

语法

block:
    <atl_block>

样例

show logo base:
    alpha 0.0 xalign 0.0 yalign 0.0
    linear 1.0 alpha 1.0

    block:
        linear 1.0 xalign 1.0
        linear 1.0 xalign 0.0
        repeat

parallel语句

parallel 语句用于定义一个可以并行执行的ATL语句块的集合。

语法

parallel:
    <atl_block>

用法

名称

类型

描述

“parallel”

keyword

一个或更多并行语句块

atl_block

block

该并行分支内的ATL语句块

使用多个并行语句块时,所有语句块将同时运行。所有并行语句块都运行结束后,parallel语句才算运行结束。

语句块中的所有并行语句都应各自独立,并修改不同的 变换特性。例如,一个语句块控制水平方向的移动(xalign),另一个语句块控制垂直方向的移动(yalign)。当两个并行分支修改了同一项特性(property),会产生无法预料的结果。

parallel语句会尽可能多得将同一个语句块中的并行语句块加入到同一个并行集合中。

样例

show logo base:
    parallel:
        xalign 0.0
        linear 1.3 xalign 1.0
        linear 1.3 xalign 0.0
        repeat
    parallel:
        yalign 0.0
        linear 1.6 yalign 1.0
        linear 1.6 yalign 0.0
        repeat

choice语句

语句定义了一个所有可能选项的集合。Ren’Py会挑选其中一个选项,执行对应选项相关的ATL语句块(block),之后跳转到choice语句块结束处。

语法

基础格式:

choice:
    <atl_block>

选项带权重:

choice <weight>:
    <atl_block>

使用方法

名称

类型

描述

“choice”

keyword

一个或多个选项

weight

float (expr)

(可选)选项权重,默认值1.0.

atl_block

block

选项对应的ATL语句块

出现多个choice语句时,会尽可能多得将同一个语句块中的choice语句加入到同一个选项集合中。 如果使用 simple_expression 指定选项权重,该表达式结果必须是浮点数值,否则会变成默认值1.0。

pass 语句可以用于按顺序将几个选项语句块分割为几个choice语句,或产生一个空的选项语句块。

Example

image eileen random:
    choice:
        "eileen happy"
    choice:
        "eileen vhappy"
    choice 2.0:
        # 更大概率被选用。
        "eileen concerned"

    pause 1.0
    repeat

animation语句

使用 animation 语句时,必须将其放在整个ATL语句块的开头,告诉Ren’Py该语句块要使用动画时间轴(at)而不是显示时间轴(st)。详见 时间轴

语法

animation

使用方法

带有相同标签(tag)的图像或界面开始显示的那一刻,animation时间轴就将进行计时并被所有相同标签(tag)的图像和界面共享。 animation时间轴常用于动画过程中的图像替换。

样例

image eileen happy moving:
    animation
    "eileen happy"
    xalign 0.0
    linear 5.0 xalign 1.0
    repeat

image eileen vhappy moving:
    animation
    "eileen vhappy"
    xalign 0.0
    linear 5.0 xalign 1.0
    repeat

label start:
    show eileen happy moving
    pause
    show eileen vhappy moving
    pause

这个例子中,艾琳的立绘表情将在第一个 pause 语句处改变,但她的位置不会改变。因为两个动画使用相同的animation时间轴,避免了更换立绘后出现图像位置不连续。不使用 animation 语句的话,用户通过点击鼠标或屏幕后,角色的立绘位置将发生一次重置。

on语句

on 语句会定义一个事件处理器(handler)。

语法

单一事件:

on <event_name>:
    <atl_block>

多个事件:

on <event_name>, <event_name>, ...:
    <atl_block>

使用方法

名称

类型

描述

event_name

word

一个或多个 事件 名。

atl_block

block

获得事件后执行的ATL代码块。

on 语句会将语句块(block)中连续出现的多个on项都放入一个事件集之中。on语句可以只处理某一个事件名,或者使用逗号分隔的事件名列表。

on语句用于处理各种事件(event)。当某个事件被处理后,其他的事件处理就会停止,并且会立即进入新事件的处理流程。当某个事件处理器没有新的待处理事件,就会产生 default 事件(已经处理 default 事件的情况除外)。

on语句的执行不会自然终止。(但是其可以被time语句,或者关联的事件处理器终止。)

样例

show logo base:
    on show:
        alpha 0.0
        linear .5 alpha 1.0
    on hide:
        linear .5 alpha 0.0

transform pulse_button:
    on hover, idle:
        linear .25 zoom 1.25
        linear .25 zoom 1.0

可视组件语句

执行可视组件语句会设置或替换某个变换的 displayable 型子组件。

语法

基本格式:

<displayable>

带转场:

<displayable> with <transition>

使用方法

名称

类型

描述

displayable

Displayable (expr)

需要显示的子组件:图像或可视元素。

transition

Transition (expr)

(可选)转场(例如, dissolvefade)。

Note

需要注意的是,并非所有转场都能在此处正常使用。特别是 字典转场(Dict Transitions)move-ease- 类转场都不能在这里使用。

将变换用作可视组件: 如果使用需要显示的元素是ATL变换且变换中使用可视组件作为子组件,那当前ATL语句块会暂停执行并等待ATL变换中的动画跑完,再继续执行。

Warning

如果要显示的元素是一个不带子组件的变换,显示为透明内容,最终将看不到任何东西。 传入无子组件的ATL变换可能会被当作 变换表达式语句,产生与预期不同的效果。

对初学者的建议: 总是让可视组件中有点东西能被看到,比如图片文件("logo.png")或有实际内容的可视组件。

样例

image atl example:

    "logo_base.png"

    pause 1.0

    "logo_bw.png" with Dissolve(0.5, alpha=True)

变换表达式语句

变换表达式语句可以包含另一个ATL变换,并用作自身ATL语句块的一部分。

语法

<transform_expression>

使用方法

名称

类型

描述

transform_expression

Transform (expr)

插入的变换

该语句只有在ATL变换自身 没有 子组件时才有效。否则,同样的语句会被当作 可视组件语句 处理。变换表达式语句中的内容会替换变换名,并执行对应的变换。

样例

transform move_right:
    linear 1.0 xalign 1.0

image atl example:
    # 显示logo_base.png。
    "logo_base.png"

    # 运行move_right变换。
    move_right

单行contains语句

该语句会把当前ATL变换的某个子组件设置(或替换)成表达式计算结果,用作动画。

语法

contains <displayable>

使用方法

名称

类型

描述

displayable

Displayable, Transform (expr)

用作子组件的可视组件或变换

可视组件语句 不够直观,且容易与变换表达式语句混淆,但它允许使用 transition 替换子组件。当某个ATL变换希望将另一个ATL变换用作自身显示内容的一部分(而不是完全替换所有显示内容)时,该语句尤其有用。

Note

想要ATL变换将另一个ATL变换作为其子组件时,请使用此语句。当子项需要作为独立的变换对象,而不是直接引用代码时,这一点尤其有用。

否则,:ref:displayable-atl-statement 是更简单的设置子显示对象的方式,其优势在于可指定播放 转场 将旧子对象替换为新子对象时。

样例

transform an_animation:
    "1.png"
    pause 2
    "2.png"
    pause 2
    repeat

image move_an_animation:
    contains an_animation

    # 如果不使用contains语句,就无法跳出循环并执行后续代码。
    xalign 0.0
    linear 1.0 yalign 1.0

与变换表达式语句相比,可视组件语句 定义更明晰,但其可以使用 transition 来替换子组件。 contains语句适合用在某个ATL语句块中容纳另一个变换效果,而不是单纯复用某个变换的代码块。

contains语句块

contains语句块,类似于 单行contains语句,可以设置变换的子组件,但方式不同。

语法

contains:
    <atl_block>

使用方法

一个或多个contains语句块会被尽可能多得组成单个contains语句,并放在一个 Fixed() 组件中,设置为该变换的子组件。

每个语句块都必须定义一个可用的可视组件,否则会报错。 所有contains语句会立刻并行执行,并不会等待所有子组件内的代码都执行完毕才执行下一条contains。

样例

image test double:
    contains:
        "logo.png"
        xalign 0.0
        linear 1.0 xalign 1.0
        repeat

    contains:
        "logo.png"
        xalign 1.0
        linear 1.0 xalign 0.0
        repeat

function语句

function 语句允许ATL使用Python代码。

语法

function <func>

使用方法

名称

类型

描述

func

function (expr)

调用的函数,签名为 (trans: Transform, st: float, at: float) -> float | None

这些函数与 Transform() 具有相同的入参和返回结果:

  • 第一个入参是一个transform对象。可以设置该对象的 变换特性

  • 第二个入参是显示 时间轴,表示函数开始执行到现在经过的秒数。

  • 第三个入参是动画 时间轴,表示具有相同标签(tag)的对象在整个界面上已存在的秒数。

  • 如果函数返回一个数值,其会在数值对应的时间(秒)后再次被调用。(0秒表示尽可能快地调用该函数。)如果函数返回None,主控流程会跳到下一个ATL语句。

除了修改第一个入参中的Transform对象之外,该函数不应产生副作用。 并可以在任意时间传入任意值并调用,能配合预加载功能。

注意,function 不是一个变换特性,并且其跟 Transform()function 参数也不完全一致。

样例

init python:
    def slide_vibrate(trans, st, at, /):
        if st > 1.0:
            trans.xalign = 1.0
            trans.yoffset = 0
            return None
        else:
            trans.xalign = st
            trans.yoffset = random.randrange(-10, 11)
            return 0

label start:
    show logo base:
        function slide_vibrate
        pause 1.0
        repeat

time语句

time 语句是一种控制语句。

语法

time <value>

使用方法

名称

类型

描述

value

float/int (expr)

开始执行这段代码块的时间点,单位为秒。

当time语句中给定的“time”结束后,后面的语句才会开始执行。在上一个语句还在执行的情况下,这种控制转换依然会执行,也能强行终止任意优先级的语句。

表示如果主控流程提前执行到time语句处,它就会暂停并等到time语句获取流程控制权。

当一个语句块中存在多个time语句时,它们各自的结束时间点必须按顺序严格递增。

样例

image backgrounds:
    "bg band"
    xoffset 0
    block:
        linear 1 xoffset 10
        linear 1 xoffset 0
        repeat # control would never exit this block

    time 2.0
    xoffset 0
    "bg whitehouse"

    time 4.0
    "bg washington"

event语句

event 语句会使用给定的名称产生一个事件(event)。

语法

event <event_name>

使用方法

名称

类型

描述

event_name

word

待生成的事件名

当在某个语句块(block)运行过程中出现某个事件(event)时,语句块会检查自身是否存在对应事件名的处理器(handler)。如果处理器存在,主控流程会切换到对应的事件处理器。否则,事件会广播至所有事件处理器。

外部事件

下列事件会在ATL变换中自动触发:

start

一种伪事件,进入 on 语句时触发,前提是没有更高优先级的事件出现。

show

使用 show 或者 scene 语句显示transform,并且给定标签(tag)没有对应已显示的图像时触发。

replace

使用 show 语句中的transform根据给定标签(tag)替换某个图像时触发。

hide

使用 hide 语句或等效的python语句中的transform时触发。

需要注意的是,transform被 scene语句 清除,或者退出其所在的 上下文 时,hide事件是不会触发的。

replaced

transform被另一个transform替换时触发。原transform的图像实际上并不会隐藏或移除,直到整个ATL语句块(block)执行完。

hoveridleselected_hoverselected_idleinsensitiveselected_insensitive

当包含此transform的按钮或者被此transform包含的按钮,出现对应的状态名称时触发。

ATL的柯里化和部分入参传递

使用 transform语句 定义的ATL变换可以设置多种不同的入参列表。 如同调用函数一样调用ATL变换时,返回结果依然是一个transform,入参则可以改变原transform中同名参数的值。

例如:

transform screamer(child, screamee, wait_time=2, flash_time=.1):
    child
    pause wait_time
    screamee
    pause flash_time
    child

# 这样写不会报错(类似于引用Python函数返回结果)。
define shorter_screamer = screamer(wait_time=1)

define eileen_excited_screamer = screamer(screamee="eileen excited", flash_time=.2)

label start:
    show hhannahh happy at screamer(screamee="hhannahh surprised", wait_time=1.5)
    "这是一种方法。"

    show eileen vhappy at eileen_excited_screamer
    "这是另一种方法。"

    show patricia sad at eileen_excited_screamer(screamee="patricia wow")
    "并且你也可以这样做。"

需要注意,变换 shorter_screamer 虽然源自 screamer,但不能直接像 show eileen at screamer 这样直接用。 因为其 screamee 参数未赋值。

还要注意,类似脚本标签(label)和界面(screen)定义,使用 transform语句 定义的transform的入参默认值, 是在transform 被调用 时才计算的,而不是 被定义 时就计算好的。

总之,transform只有在调用另一个变换(例如上例中的 shorter_screamer 或部分入参传递)时,才会计算所有入参的默认值。 无论默认值来自原始的transform(比如 shorter_screamerflash_time 参数或部分入参传递的 wait_time 参数), 还是来自更早执行的脚本中的调用(比如 shorter_screamer` 中的 wait_time 参数或部分入参传递的 screamee 和`flash_time` 参数)。

特殊child参数

如果某个ATL变换有一个入参名为“child”,并且该入参获得了一个值,那么将 无视该入参值的类型和赋值方式 , 该变换的子组件将被设置为child参数的值。 (无视入参值类型和赋值方式是指,不需要考虑参数是固定位置入参是还是关键词入参,也不需要考虑该参数有默认值还是要求必须重新赋值。)

需要注意,child入参的默认值不会生效,还是需要从外部传入一个新的值。

另外,ATL变换用作一个transform时,默认不会将 child= 作为关键词参数传递并设置目标的child,除非目标有个同名的child入参。

例如,下面的脚本能在child与另一个可视组件之间来回切换:

transform lucy_jump_scare(child):
    # child的值会隐式设置为transform的子组件。
    pause 5

    # “jump scare”式惊吓。
    "lucy mad"
    pause .2

    # 再显示原来的子组件。
    child

还可以在 contains 语句块中放置原来的子组件:

transform marquee(width, height=1.0, duration=2.0, child=None):
    xcenter 0.5
    ycenter 0.5

    crop (0, 0, 0.5, 500)

    contains:
        child
        xanchor 0.0 xpos 1.0
        linear duration xanchor 1.0 xpos 0.0

old_widgetnew_widget 两个“关键词限定”入参(即不能用于固定位置入参)在 ATL转场 中有特殊用法。

warpers

warper是一类函数,其可以改变插值语句中用到的时间值。他们将时间t转换为t’,t和t’都是浮点数,t会将给定的时间值归一化为0.0到1.0。 (如果该语句给定的原时长是0,那运行时t就是1.0。) t’的初始取值范围也是0.0到1.0,不过可以超出这个范围。 以下warper都是默认定义好的。

pause

暂停,然后跳变成新值。如果 t == 1.0,则 t' = 1.0;否则 t' = 0.0

linear

线性插值。t' = t

ease

开头慢,中间加速,之后又减速。t' = .5 - math.cos(math.pi * t) / 2.0

easein

开头快,然后减速。t' = math.cos((1.0 - t) * math.pi / 2.0

easeout

开头慢,然后加速。t' = 1.0 - math.cos(t * math.pi / 2.0)

除此之外,Robert Penner的easing函数都是支持的。为了避免与上面的几个函数名重复,有些函数名字修改过。这些标准函数的图像可以在这个网站上查看 http://www.easings.net/

Ren’Py 函数名

easings.net 函数名

ease_back

easeInOut_back

ease_bounce

easeInOut_bounce

ease_circ

easeInOut_circ

ease_cubic

easeInOut_cubic

ease_elastic

easeInOut_elastic

ease_expo

easeInOut_expo

ease_quad

easeInOut_quad

ease_quart

easeInOut_quart

ease_quint

easeInOut_quint

easein_back

easeOut_back

easein_bounce

easeOut_bounce

easein_circ

easeOut_circ

easein_cubic

easeOut_cubic

easein_elastic

easeOut_elastic

easein_expo

easeOut_expo

easein_quad

easeOut_quad

easein_quart

easeOut_quart

easein_quint

easeOut_quint

easeout_back

easeIn_back

easeout_bounce

easeIn_bounce

easeout_circ

easeIn_circ

easeout_cubic

easeIn_cubic

easeout_elastic

easeIn_elastic

easeout_expo

easeIn_expo

easeout_quad

easeIn_quad

easeout_quart

easeIn_quart

easeout_quint

easeIn_quint

可以通过只读模块 _warper 访问这些warper效果。该模块包含了上述所有函数。 在Ren’Py内置效果中使用时间warp函数很有用,比如可以这样用:

with Dissolve(1, time_warp=_warper.easein_quad)

我们可以在一个 python early 语句块中,使用 renpy.atl_warper 装饰器定义新的warper函数。定义warper函数文件需要在使用那个函数的其他任何文件之前被处理。定义的代码如下:

python early hide:

    @renpy.atl_warper
    def linear(t):
        return t

替换变换

某个ATL变换、内建变换或使用 Transform 定义的变换对象被同类变换替换时, 同名特性的值会从前一个变换继承到新的变换。不同类型的变换无法继承。

如果 show语句 中的at关键字后列出了多个变换待替换,则新变换列表从后往前依次替换,直到新替换变换列表全部换完。例如:

show eileen happy at a, b, c
"我们稍等一下。"
show eileen happy at d, e

e 变换替换了 cd 变换替换了 b,而没有变换会替换 a

替换时,旧变换的特性值由新变换继承。如果旧变换正处于动画中,则新变换继承的可能是中间的某个值。例如:

transform bounce:
    linear 3.0 xalign 1.0
    linear 3.0 xalign 0.0
    repeat

transform headright:
    linear 15 xalign 1.0

label example:
    show eileen happy at bounce
    pause
    show eileen happy at headright
    pause

这个例子中,图像会左右弹跳,直到用户点击鼠标。 当用户点击鼠标后, bounce 中的 xalign 特性值将被 headright 继承。 精灵在x轴方向坐标移动的初始值,即是用户点击鼠标时的值。

位置相关特性(包括 xposyposxanchoryanchor,以及等效的:tpref:xalignradiusangle))继承时有一项特殊规则: 子组件设置的值会覆盖父组件的值。这样设计是考虑到可视组件往往只有一项位置信息,需要优先保证设置的值不受影响。 对位置特性的设置有多种方式,例如,xalign 会同时设置xpos和xanchor。

最后,如果某个 show 语句不包含 at 从句,则不需要搞特性值继承问题。若要重置所有变换特性,可以先隐藏再显示对应的可视组件。 若要中断动画效果,可以这样:

show eileen happy at some_animation
"Wow, so this is what antigravity feels like !"

show eileen:
    pass
"But I'm happy when it settles down."

时间轴

Ren’Py中有两个时间轴,很容易混淆:

  • st (显示时间轴):可视组件第一次显示在界面上就开始计时。

  • at (animation timebase): 具有相同tag的图像显示后开始计时,不算图像隐藏的时间。

可视组件不带任何tag显示时,stat 的值是一样的。

Note

默认情况下,变换使用 st。 可以使用 animation语句 切换为 at

Transform类

ATL变换在Python中等效于一个Transform对象。

class Transform(child=None, *, function=None, reset=False, **properties)

创建一个Transform对象,并将各种操作应用到其子组件,操作包括:剪裁、旋转、缩放和alpha混合等。 一个Transform对象的字段一一对应 变换特性 ,并都将应用到子组件。

child

应用变换的子组件。

reset

若为True,显示时会重置所有变化特性为默认值,而不是继承其替代的那个变换。

function(trans: Transform, st: float, at: float, /) int | None

若不是None,这是渲染变换效果时调用的函数。调用这个函数时使用3个固定位置入参:

  • Transform对象。

  • 显示时间轴,单位为秒。

  • 动画时间轴,单位为秒。

函数会返回一个延迟时间,单位为秒。在运行延迟时间之后这个函数会被再次调用。如果延迟时间是None,则会在下次互动之后立刻调用。

该函数除了修改第一个入参的变换对象之外不应有其他副作用,并且要求可以在任何时间点使用任何值调用以配合预加载。

其他关键词入参都会作为对应变换特性的值。 绘制变换效果时,对应的变换特性都会根据入参设置值,但在变换对象创建后不再更改。 使用 function 参数传入的函数或调用 update() 方法,可以改变对应的变换特性。

其他参数被视为设置变换特性的值。

hide_request

当function函数被调用时,这项会被设置为True,标识变换效果被隐藏。

hide_response

如果hide_request为True,这项会被设置为False,防止变换效果被隐藏。

original_child

创建变换对象时就设置的子可视组件,早于调用set_child。 如果创建时没有子组件,可以设置为None.

set_child(child)

使用一个新的 child 调用这个方法,child 成为变换的子组件。

update()

当变换特性(property)字段在 function 参数指定的回调方法之外被更新时,这个方法会被调用,确保修改生效。

unique():

新创建的transform对象可以调用该方法将自身标记为唯一。通常transform对象被添加到某个可视组件时会复制自身,并重置自身状态。调用该方法后可以避免出现这种情况。还可以在需要创建的transform对象用在多处而不发生改变,或从外部获取 function 参数的情况。

该方法返回结果是transform对象自身。

在Python中对可视组件应用变换

若要在Python中对可视组件 d 引用变换 t 有好几种方法:

  1. 最为通用也最推荐的方法是,使用 At(d, t) (下面有样例)。这种方法适用于所有变换。

  2. d(child=t) 适用于所有 ATL变换

  3. t(d) 适用于 Python变换,以及不需要坐标作为参数的ATL变换。

At(d, *args)

对指定的源可视组件 d ,将 args 中所有变换应用于该组件。变换的应用顺序是从左到右,所以最外层的变换效果是最右边的入参。

transform birds_transform:
    xpos -200
    linear 10 xpos 800
    pause 20
    repeat

image birds = At("birds.png", birds_transform)

Note

如果某些变换没有传入需要的参数,变换结果可能会导致无法正常显示。 这种情况下需要检查使用 transform语句 定义的变换到底需要什么参数。

Note

变换结果可能还是一个变换,可以进一步应用于另一个可视组件(及其子组件); 这种情况下ATL变换依然可以如其他变换一样使用,不影响其子组件。

可调用对象用作变换

最后,Python中的可调用对象可以用作变换。这些可调用对象必须能使用 可视组件 作为入参, 并且能返回一个新的可视组件。例如:

init python:

    # 这是一个使用right和left两个默认变换的自定义变换。
    def right_or_left(d):
        if switch:
            return At(d, right)
        else:
            return At(d, left)

某些内建对象可以也符合入参为可视组件并返回可视组件的要求,例如 Flatten(),也可以直接用作变换。