前置知识: Ren'Py

ATL:变换与动画

8 min入门

用变换语言给图像定位缩放淡入淡出,掌握插值缓动并行随机与事件驱动的动画写法

第三篇里我们用 at right、at left 把立绘摆到固定位置,但那只是变换(transform)的最浅层用法。Ren’Py 内置了一门专用的小语言——ATL(Animation and Transformation Language,动画与变换语言),用声明式的语句块描述图像的位置、缩放、透明度如何随时间变化。打字机式移动的 logo、随机切换的表情、按钮的脉冲呼吸、淡入淡出的转场,都可以用 ATL 写出来。

ATL 的价值在于它是数据而不是代码:一段 ATL 块可以附着在 transform、image 或 show 语句上,被引擎按帧解释执行。本篇从三种承载方式讲起,逐个过一遍 ATL 语句,最后说清 transform 相互替换时的继承规则。

学习目标

  • 理解 ATL 的三种承载方式:transform 语句、image 语句加 ATL 块、show/scene 语句加 ATL 块;
  • 会用常用 transform 属性(xalign、zoom、alpha、rotate、blur 等)与内置位置变换;
  • 掌握 ATL 基础语句:属性语句、pause、插值语句、repeat、block;
  • 认识常用 warper(缓动函数):linear、ease、easein、easeout 与 Robert Penner 家族;
  • 会用 parallel 做并行动画,用 choice 做随机选择,用 animation 固定动画时间基;
  • 会用 on 语句响应 show、hide、hover 等事件。

三种承载方式

第一,transform 语句定义一个可复用的变换,之后任何 show 都能 at 它,还支持参数:

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

第二,image 语句可以直接跟一个 ATL 块,把动画固化成一张”图”:

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

这个图像显示 1 秒 ariana,再显示 1 秒 ariana_reverse,无限循环——帧动画就这么写。

第三,show 或 scene 语句后面直接跟 ATL 块,现场包裹一次性变换:

show eileen happy:
    xalign 1.0
    linear 2.0 xalign -1.0

立绘从屏幕右侧滑到左侧,只此一次,不留名字。三种方式共享同一套 ATL 语法,学会了语句就全都通了。

常用属性与内置位置

写 ATL 主要就是在摆弄一组变换属性:

xpos / ypos      水平 / 垂直位置(像素或相对值)
xalign / yalign  0 到 1 的对齐:0 贴左(上),1 贴右(下),0.5 居中
anchor           锚点,决定"图像上的哪个点"对到给定坐标
zoom             整体缩放
xzoom / yzoom    水平 / 垂直单独缩放
alpha            不透明度 0.0 到 1.0
rotate           旋转角度
xysize           尺寸
blur             高斯模糊强度

其中 xalign/yalign 是最常用的定位方式:一个数字同时表达”放在哪”与”以哪点对齐”。此外 ATL 有一个 Properties 语句的概念——一行里直接写多个属性即为属性语句,如 xanchor .3 xpos 100,立即生效。

引擎也内置了一批位置变换,它们就是用 ATL 写好的现成 transform:

center                        水平居中、贴底(show 的默认位置)
left / right                  贴左 / 贴右
truecenter                    水平垂直都居中
top / topleft / topright      顶部系列
offscreenleft / offscreenright 完全移出屏幕左 / 右
reset                         重置位置属性
default                       默认位置

注意 offscreenleft 与 offscreenright:图像被移出屏幕后仍在被”显示”,引擎不会自动回收,需要时应当用 hide 隐藏以释放资源。

ATL 基础语句

pause 与插值

pause 语句让画面停顿:pause 2.0 等 2 秒,也可以直接写裸数字 3.0,pause 关键字可选。

插值语句是 ATL 的核心,形式为”warper 时长 属性…”:第一个词是缓动函数(warper),随后是时长与一组目标属性:

show logo base:
    xalign 0.0 yalign 0.0
    # Take 2.0 seconds to move things to the bottom-left corner.
    linear 2.0 yalign 1.0

logo 先瞬移到左上角,再用 2 秒匀速滑到底部。第一行是不带 warper 的属性语句(立即生效),第二行是插值语句(渐进生效)。插值语句也可以写成块形式,把多个属性的插值目标放进缩进块里一次完成。

repeat 与 block

repeat 让语句序列循环,可带次数(repeat 3);它必须是所在块的最后一条语句。想让”一段序列”整体循环,用 block: 分组:

show eileen thinking:
    block:
        linear 1.0 xalign 0.0
        linear 1.0 xalign 1.0
    repeat

立绘在左右两端之间往返。

缓动 warper

warper 决定插值的节奏曲线。内置五个:

pause    不改属性,纯等待
linear   匀速
ease     慢-快-慢
easein   先快后慢
easeout  先慢后快

此外还有一整个 Robert Penner 缓动家族:ease_back、ease_bounce、ease_circ、ease_cubic、ease_elastic、ease_expo、ease_quad、ease_quart、ease_quint,以及各自的 easein_ 与 easeout_ 变体(如 easeout_bounce)。bounce 弹跳、elastic 橡皮筋、back 回弹过冲,都在其中,给 UI 动画挑节奏时值得逐个试。

parallel:并行执行

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

这个官方示例让 logo 水平方向 1.3 秒一趟左右往返循环,垂直方向 1.6 秒一趟上下往返循环——两个周期叠加,轨迹是一个利萨如曲线式的漂移。

choice:按权重随机

choice 块从多个分支中按权重随机选一个执行,默认权重 1.0:

image eileen random:
    choice:
        "eileen happy"
    choice:
        "eileen vhappy"
    choice 2.0:
        # More likely to be chosen.
        "eileen concerned"
    pause 1.0
    repeat

每次循环随机挑一个表情显示 1 秒;choice 2.0 的块被选中的概率是普通块的两倍。这种”随机待机表情”是 galgame 的常见演出。

animation:固定动画时间基

animation 语句必须是 ATL 块的第一条,它让该块改用动画时间基(at 而不是 st)。效果是:当图像属性被替换(例如换表情)时,动画的进度不会从头重放,而是沿着自己的时钟继续走:

image eileen happy moving:
    animation
    "eileen_happy_a.png"
    pause 1.0
    "eileen_happy_b.png"
    pause 1.0
    repeat

对循环待机动画加 animation,可以避免”每次换表情动画都重新跳回第一帧”的违和感。

on:事件驱动

on 语句为具名事件指定处理块。引擎会在特定时机发出事件:show、replace(被同 tag 图像替换)、hide、replaced(替换掉旧图),以及按钮状态事件 hover、idle、selected_hover 等:

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

第一个示例让 logo 出现时半秒淡入、隐藏时半秒淡出。第二个示例是按钮脉冲:一行 on hover, idle 同时声明两个事件的处理(进入 hover 与回到 idle 时都播放),按钮在鼠标悬停时放大又缩回,形成一次”心跳”。on 也可以显式声明 event 语句产生的事件。

其他语句与进阶运动

  • function 语句:每帧调用一个签名为 (trans, st, at) 的自定义函数,返回下一次调用的时间(返回 None 表示停止),是 ATL 的逃生舱口,适合程序化动画;
  • time 语句:到达指定时间后强制切换到下一语句,常用来给动画定节拍;
  • event 语句:产生一个具名事件,可被其他 on 块或屏幕捕获;
  • contains 语句:在一个 ATL 块里容纳多个子对象,各自带各自的动画。

样条与圆周运动:插值语句支持 knot 控制点,让图像沿样条曲线运动(1 个控制点为二次贝塞尔曲线,2 个为三次贝塞尔曲线,3 个以上为 Catmull-Rom 样条);ATL 还提供 clockwise 与 counterclockwise 圆周运动的写法。细节见官方 transforms 文档,本篇不展开。

transform 的替换规则

最后是三个容易踩坑的规则:

  • show 不带 at 子句时,图像会沿用它当前已在使用的 transform——已经滑到屏幕中间的立绘,不会因为一句 show eileen happy 就跳回默认位置;
  • 一个 ATL transform 替换另一个时,属性会被继承:新 transform 没写的属性沿用旧值;
  • 想完全重置,要么 hide 之后再 show(从零开始),要么显式 at reset。

小结

  • ATL 是 Ren’Py 内置的动画与变换语言,三种承载方式:transform 语句(可复用、支持参数)、image 语句加 ATL 块(帧动画)、show/scene 加 ATL 块(一次性包裹)。
  • 常用属性:xpos/ypos、xalign/yalign、anchor、zoom、xzoom/yzoom、alpha、rotate、xysize、blur;内置位置有 center、left、right、truecenter、top 系列、offscreenleft/right 与 reset,离屏图像记得 hide 释放。
  • 基础语句:属性语句立即生效;pause 2.0 或裸 3.0 停顿;插值语句”warper 时长 属性”渐进生效;repeat 可带次数且必须是块最后一条;block 分组配合 repeat 循环一段序列。
  • warper:pause、linear、ease(慢快慢)、easein(先快后慢)、easeout(先慢后快),以及 Robert Penner 家族及其 easein_/easeout_ 变体。
  • parallel 多块并行、全完才完、各改各的属性;choice 按权重(默认 1.0)随机选块;animation 必须是块第一条,改用 at 时间基,换属性不重置动画。
  • on 响应 show/replace/hide/replaced 与 hover/idle/selected_hover 等事件;另有 function、time、event、contains 等语句;样条 knot 与顺逆时针圆周运动见官方文档。
  • 替换规则:无 at 子句沿用旧 transform;ATL 相互替换属性继承;彻底重置用 hide 加 show 或 reset。

参考链接