世上无难事,只要肯放弃。
支线系列是独立于基础之外的内容,会引用一些外部平台大佬的内容,感觉有困难的同学可以暂时不(fang)看(qi)。
本篇内容将讲解一个简单的粒子系统。请善用官方文档的搜索功能,能解决大部分疑问。
第一个问题:粒子是什么?
答:在大多数游戏引擎和动画设计软件中,都有一种叫做particle的对象,一般翻译成“粒子”。通常粒子都是小光点或者小图片,通常会设计成从某个发射点“出生”,经过一段时间之后“死亡”。
第二个问题:Ren'Py中如何使用粒子?
答:Ren'Py比较奇葩,自带的粒子系统不叫particle而是sprite……这很容易跟其他软件中的sprite(精灵)混淆。翻译文档的时候也挺纠结……
Ren'Py自带的Sprite和Spritemanager两个类,以及一个SnowBlossom函数。总体来说偏向底层,所以可以根据需要自己编写粒子效果。
这篇暂时不讲Ren'Py自带的这部分内容~
第三个问题:那说什么粒子?
答:以下内容参考了Ren'Py的Wiki上Particle Burst,以及lemmasoft论坛大佬Xela的帖子(他也贡献了Ren'Py引擎的部分代码)。
先上代码:
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语句可以不管,反正能用就行……然后使用下面的脚本就可以显示效果了:
# 定义粒子元素,particle.png是要使用的例子图片
image particle = "particle.png"
# 定义粒子喷射图像
image boom = ParticleBurst("particle", mouse_sparkle_mode=False)
# 在某段脚本中显示粒子喷射图像
label start:
show boom
效果如图。
很明显,粒子是顺时针螺旋型喷射的。也就是说,单个粒子只是随着时间变化,不断增加自身特性(property)中radius和angle的值。如果我们修改一部分内容,就可以实现类似烟花的效果:
image boom = ParticleBurst("particle", speed=(0.15, 0.5), angle=(-90, 90), radius=(50,200))
当然,这里的particle参数是一切可视组件(displayable),所以我们还可以用图像处理器或者ATL制造各种效果。比如我把图片换掉,然后用im.MatrixColor制造色调分离效果:
image particle colored = im.MatrixColor(
"particle.png",
im.matrix.colorize("#ff4a12", "#ffcfac"))
预告部分:可能会有一个补充章节……