Skip to content

粒子与天气特效 ​

本页属于 GenPy Ren'Py 学习路线。教程内容面向 Ren'Py 8.x,并在页面末尾连接到 GenPy 的对应工作流。

学习目标 ​

  • 了解“粒子与天气特效”在 Ren'Py 项目中的用途。
  • 能在一个最小项目里验证本章相关语法或工作流。
  • 知道发布前需要检查的常见风险,并能在 GenPy 中继续维护。

核心语法 ​

  • SnowBlossom
  • SpriteManager
  • particles
  • weather layer
  • performance

可运行示例 ​

text
image snow = SnowBlossom("fx/snow.png", count=100)

label start:
    scene bg night
    show snow                 # 直接显示,雪花持续飘落
    "下雪了……"
    hide snow

教程正文 ​

下雪、下雨、樱花飘落、灰烬上扬、萤火虫飞舞……这些“大量小图运动”的效果,用 Ren'Py 内置的 SnowBlossom 最省事;要更复杂(互相影响、躲避鼠标)用 SpriteManager。

1. SnowBlossom:一行搞定落雪 ​

text
image snow = SnowBlossom("fx/snow.png", count=100)

label start:
    scene bg night
    show snow                 # 直接显示,雪花持续飘落
    "下雪了……"
    hide snow

完整参数(官方签名) ​

SnowBlossom(d, count=10, border=50, xspeed=(20, 50), yspeed=(100, 200),
            start=0, fast=False, horizontal=False,
            distribution='linear', animation=False)
参数含义
d粒子用的可显示物(雪花/雨丝/花瓣 PNG)
count同屏粒子数(越大越密)
border边界余量,让粒子飞出屏幕外才回收,避免突然消失
xspeed / yspeed水平/垂直速度;单值或 (最小,最大) 区间随机;可正可负
start每个粒子加入前的延迟(秒),避免“一整排同时落下”的波浪感
fastTrue 时粒子一开始就布满全屏(而非只从边缘进入)
horizontalTrue 时粒子从左右两侧进入(而非上下)
distribution起始位置分布:'linear' 均匀 / 'gaussian' 偏中间 / 'arcsine' 偏两边
animationTrue 时用动画时基,重复显示不会重置

2. 不同天气的配方 ​

下雪(缓慢飘落) ​

text
image snow = SnowBlossom(
    "fx/snowflake.png",
    count=120,
    xspeed=(-30, 30),        # 左右轻飘
    yspeed=(60, 140),        # 缓慢下落
    fast=True,               # 进场即布满
)

下雨(快速、近乎垂直) ​

用细长的雨丝图,速度快、横向几乎为 0:

text
image rain = SnowBlossom(
    "fx/raindrop.png",       # 一条 2x24 的半透明竖线
    count=300,
    xspeed=(-10, 10),
    yspeed=(900, 1200),      # 又快又直
    fast=True,
)

樱花飘落(横向大幅摇曳) ​

text
image sakura = SnowBlossom(
    "fx/petal.png",
    count=80,
    xspeed=(-120, 120),      # 大幅左右飘
    yspeed=(40, 90),         # 慢慢落
    fast=True,
)

想让花瓣自转,把粒子图本身做成会旋转的动画(用 ATL 包一层再传给 d), 或用 SpriteManager 自己控制每片旋转。

灰烬 / 气泡上扬(向上飘) ​

yspeed 用负值让粒子向上:

text
image embers = SnowBlossom(
    "fx/ember.png",
    count=60,
    xspeed=(-20, 20),
    yspeed=(-160, -80),      # 负值 = 上升
    fast=True,
)

3. 叠加到场景 / 让它在立绘之前或之后 ​

text
scene bg forest
show sakura                 # 默认叠在当前层
show eileen happy

# 想让粒子在立绘“之后”(更靠后景),用 zorder 或 behind
show sakura zorder 1
show eileen happy zorder 2

也可放进屏幕做全局覆盖(如雨天 HUD):

text
screen weather_rain():
    add "rain"

label start:
    show screen weather_rain

4. SpriteManager:完全自定义的大量粒子 ​

需要粒子之间互动、按规律运动、响应输入时,用 SpriteManager:create() 造粒子, 在 update 回调里逐个改 x/y/zorder。

text
init python:
    import math
    def fireflies_update(st):
        for s in firefly_sprites:
            # 用正弦让萤火虫飘忽游动
            s.x += math.sin(st * 1.3 + s.phase) * 1.5
            s.y += math.cos(st * 1.1 + s.phase) * 1.2
        return 0       # 尽快再次更新

    firefly_sprites = []

label firefly_demo:
    python:
        mgr = SpriteManager(update=fireflies_update)
        glow = Image("fx/firefly.png")
        for i in range(40):
            s = mgr.create(glow)
            s.x = renpy.random.randint(0, config.screen_width)
            s.y = renpy.random.randint(0, config.screen_height)
            s.phase = renpy.random.random() * 6.28   # 自定义字段,错开相位
            firefly_sprites.append(s)
    show expression mgr as fireflies
    "萤火虫在夜里飞舞。"
    hide fireflies

5. 粒子躲避鼠标(官方互动示例改写) ​

SpriteManager 支持 event 回调记录鼠标,update 里让粒子远离鼠标:

text
init python:
    import math
    repulsor_sprites = []
    repulsor_pos = None

    def repulsor_update(st):
        if repulsor_pos is None:
            return 0.01
        px, py = repulsor_pos
        for i in repulsor_sprites:
            vx = i.x - px
            vy = i.y - py
            vl = math.hypot(vx, vy)
            if vl >= 150 or vl == 0:
                continue
            # 越近推得越远
            d = 3.0 * (150 - vl) / 150
            i.x += d * vx / vl
            i.y += d * vy / vl
        return 0.01

    def repulsor_event(ev, x, y, st):
        store.repulsor_pos = (x, y)

label repulsor_demo:
    python:
        repulsor = SpriteManager(update=repulsor_update, event=repulsor_event)
        smile = Image("fx/dot.png")
        for i in range(200):
            s = repulsor.create(smile)
            s.x = renpy.random.randint(2, config.screen_width - 2)
            s.y = renpy.random.randint(2, config.screen_height - 2)
            repulsor_sprites.append(s)
    show expression repulsor as repulsor
    "粒子会躲开你的鼠标。"
    hide repulsor

(改编自官方 Sprites 文档的 repulsor 示例。)

6. 性能提示 ​

  • SnowBlossom/SpriteManager 已为“大量同图”优化:同一 displayable 每帧只渲染一次。
  • count 几百可行,但移动/网页端要实测;雨可多、花瓣可少。
  • 粒子图用小尺寸 PNG(带透明),别用大图。
  • 不需要时记得 hide,别让粒子在整局游戏后台空跑。

常见坑 ​

  • SnowBlossom 第一个参数是可显示物(图片名/Image),不是 image= 关键字。
  • 想要上升效果用负 yspeed;想要横风用非零 xspeed。
  • fast=True 让进场即满屏,否则开头会“从边缘慢慢补满”。
  • 自转/复杂个体运动 → 上 SpriteManager,SnowBlossom 不控制单粒子旋转。

官方参考 ​

在 GenPy 里怎么做 ​

  • 在 GenPy 的代码模式中维护相关 .rpy 文件,先保持语法清晰,再逐步加入本章功能。
  • 用故事图谱、变量、校验或演出编辑器把“能运行”提升到“可维护”。
  • 导出前结合 Ren'Py Lint 和 GenPy 校验结果,确认脚本、素材和发布路径一致。

推荐继续阅读:

Built for GenPy creators.