找回密码
 立即注册

QQ登录

只需一步,快速开始

查看: 6885|回复: 0

[转载] Ren'Py引擎从入门到放弃(支线3)——简单粒子效果

[复制链接]
发表于 2019-4-25 19:05:50 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
本帖最后由 BuErShen 于 2019-4-25 18:27 编辑

Ren'Py引擎从入门到放弃(支线3)——简单粒子效果

世上无难事,只要肯放弃。

支线系列是独立于基础之外的内容,会引用一些外部平台大佬的内容,感觉有困难的同学可以暂时不(fang)看(qi)。

本篇内容将讲解一个简单的 粒子系统。请善用官方文档的搜索功能,能解决大部分疑问。

第一个问题:粒子是什么?

答:在大多数游戏引擎和动画设计软件中,都有一种叫做 particle的对象,一般翻译成“粒子”。通常粒子都是小光点或者小图片,通常会设计成从某个发射点“出生”,经过一段时间之后“死亡”。

第二个问题:Ren'Py中如何使用粒子?

答:Ren'Py比较奇葩,自带的粒子系统不叫 particle而是 sprite……这很容易跟其他软件中的 sprite(精灵)混淆。翻译文档的时候也挺纠结……

Ren'Py自带的 SpriteSpritemanager两个类,以及一个 SnowBlossom函数。总体来说偏向底层,所以可以根据需要自己编写粒子效果。

这篇暂时不讲Ren'Py自带的这部分内容~

第三个问题:那说什么粒子?


答:以下内容参考了Ren'Py的 Wiki上Particle Burst,以及 lemmasoft论坛大佬 Xela的帖子(他也贡献了Ren'Py引擎的部分代码)。

先上代码:
[RenPy] 纯文本查看 复制代码
transform particle(d, delay, speed=1.0, around=(config.screen_width/2, config.screen_height/2), angle=0, radius=200):
    d
    pause delay
    subpixel True
    around around
    radius 0
    linear speed radius radius angle angle

init python:
    class ParticleBurst(renpy.Displayable):
        def __init__(self, displayable, interval=(0.02, 0.04), speed=(0.15, 0.3), around=(config.screen_width/2, config.screen_height/2), angle=(0, 360), radius=(50, 75), particles=None, mouse_sparkle_mode=False, **kwargs):
            """Creates a burst of displayable...

            @params:
            - displayable: Anything that can be shown in Ren'Py (expects a single displayable or a container of displayable to randomly draw from).
            - interval: Time between bursts in seconds (expects a tuple with two floats to get randoms between them).
            - speed: Speed of the particle (same rule as above).
            - angle: Area delimiter (expects a tuple with two integers to get randoms between them) with full circle burst by default. (0, 180) for example will limit the burst only upwards creating sort of a fountain.
            - radius: Distance delimiter (same rule as above).
            - around: Position of the displayable (expects a tuple with x/y integers). Burst will be focused around this position.
            - particles: Amount of particle to go through, endless by default.
            - mouse_sparkle_mode: Focuses the burst around a mouse poiner overriding "around" property.

            This is far better customizable than the original ParticleBurst and is much easier to expand further if an required..
            """
            super(ParticleBurst, self).__init__(**kwargs)
            self.d = [renpy.easy.displayable(d) for d in displayable] if isinstance(displayable, (set, list, tuple)) else [renpy.easy.displayable(displayable)]
            self.interval = interval
            self.speed = speed
            self.around = around
            self.angle = angle
            self.radius = radius
            self.particles = particles
            self.msm = mouse_sparkle_mode

        def render(self, width, height, st, at):

            rp = store.renpy

            if not st:
                self.next = 0
                self.particle = 0
                self.shown = {}

            render = rp.Render(width, height)

            if not (self.particles and self.particle >= self.particles) and self.next <= st:
                speed = rp.random.uniform(self.speed[0], self.speed[1])
                angle = rp.random.randrange(self.angle[0], self.angle[1])
                radius = rp.random.randrange(self.radius[0], self.radius[1])
                if not self.msm:
                    self.shown[st + speed] = particle(rp.random.choice(self.d), st, speed, self.around, angle, radius)
                else:
                    self.shown[st + speed] = particle(rp.random.choice(self.d), st, speed, rp.get_mouse_pos(), angle, radius)
                self.next = st + rp.random.uniform(self.interval[0], self.interval[1])
                if self.particles:
                    self.particle = self.particle + 1

            for d in self.shown.keys():
                if d < st:
                    del(self.shown[d])
                else:
                    d = self.shown[d]
                    render.blit(d.render(width, height, st, at), (d.xpos, d.ypos))

            rp.redraw(self, 0)

            return render

        def visit(self):
            return self.d

这段代码的风格比较……古典~开头的 变换(transform)是我们可以根据自己需求修改的部分。后面大段Python语句可以不管,反正能用就行……然后使用下面的脚本就可以显示效果了:
[RenPy] 纯文本查看 复制代码
# 定义粒子元素,particle.png是要使用的例子图片
image particle = "particle.png"

# 定义粒子喷射图像
image boom = ParticleBurst("particle", mouse_sparkle_mode=False)

# 在某段脚本中显示粒子喷射图像
label start:
    show boom

效果如图。
显示粒子喷射图像.gif
很明显,粒子是顺时针螺旋型喷射的。也就是说,单个粒子只是随着时间变化,不断增加自身特性(property)中 radiusangle的值。如果我们修改一部分内容,就可以实现类似烟花的效果:
[RenPy] 纯文本查看 复制代码
image boom = ParticleBurst("particle", speed=(0.15, 0.5), angle=(-90, 90), radius=(50,200))

当然,这里的 particle参数是一切可视组件(displayable),所以我们还可以用图像处理器或者ATL制造各种效果。比如我把图片换掉,然后用im.MatrixColor制造色调分离效果:
[RenPy] 纯文本查看 复制代码
image particle colored = im.MatrixColor(
    "particle.png",
    im.matrix.colorize("#ff4a12", "#ffcfac"))

色调分离效果.gif

预告部分:可能会有一个补充章节……



“Ren'Py引擎从入门到放弃”系列教程
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|RenPy中文空间 ( 苏ICP备17067825号|苏公网安备 32092302000068号 )

GMT+8, 2024-4-26 08:21 , Processed in 0.070744 second(s), 16 queries , File On.

Powered by Discuz! X3.5

© 2001-2024 Discuz! Team.

快速回复 返回顶部 返回列表