最早接触这个概念是在去年的圣诞节的时候,那个时候手机淘宝首页出了一个页面下雪的动画,当时觉得蛮炫酷的,而且以为实现起来蛮难的,后来自己查了资料才知道“粒子特效”这个概念,今天就来简单聊聊它吧。
粒子特效
粒子系统表示三维计算机图形学中模拟一些特定的模糊现象的技术,而这些现象用其它传统的渲染技术难以实现的真实感的游戏图形。经常使用粒子系统模拟的现象有火、爆炸、烟、水流、火花、落叶、云、雾、雪、尘、流星尾迹或者象发光轨迹这样的抽象视觉效果等等。
以上定义来自维基百科,详细的解释点击这里.
在 iOS 系统当中的实现
粒子特效由两个部分组成,一个是发射器,主要负责粒子的生成和发射,另一个是粒子单元,用于描述粒子的状态。在 iOS 系统当中这两部分分别由 CAEmitterLayer(发射器)和 CAEmitterCell(组成)。
具体使用可以查看以下代码:
1 | //雪花动画 |
粒子特效的叠加
通过上面的代码和注释、以及苹果的注释,我相信大部分人都已掌握了粒子效果的基本使用,下面我们来谈谈粒子特效叠加的问题。
在 CAEmitterCell.h 当中我们可以看到这样一段描述
1 | /* An array containing the sub-cells of this cell, or nil (the default |
这段描述说明了当设置粒子单元(CAEmitterCell *)的 emitterCells 时,每个粒子会充当一个发射器的角色,发射对应粒子,形成粒子特效的叠加。
将 rocket.emitterCells = [NSArray arrayWithObject:burst];修改为 rocket.emitterCells = [NSArray arrayWithObject: spark];就可以看到如下图对应的叠加效果了。

取消叠加
看了粒子特效的叠加,你可能还会有这样一个想法,我能不能取消某个时间段的叠加,只让发射的粒子在最后的时间作为发射器产生粒子效果呢,类似于发射一颗礼炮,在礼炮到达空中时爆炸,而不是像现在这样一路炸上天呢。

实例代码的 fireworks 部分就实现了这样的效果,下面我们来分析一下他的思路
fireworks 部分的基本思路是这样的,给发射的粒子 A 附加一个新的粒子效果 B,B 的效果是在 A 生命周期的结尾发射一个生命周期极短的粒子,在 B 粒子极短的生命周期内,发射爆炸效果的粒子 C,这样看起来的效果就是 A 被发射出去,在其生命周期的结尾发射了一个爆炸的粒子 C,用户并没有意识到 B 粒子的存在,从而达到取消叠加的效果。
如何在代码中实现这种取消叠加的效果
birthRate 粒子每秒钟产生粒子的个数,决定了粒子产生的间隔,而且并不是一开始就发射粒子,而是要从开始过相应的时间间隔才发送粒子。所以我们只需要将 B 粒子的生成间隔设定为 A 粒子的生存长度即可,这样就实现了在 A 粒子即将结束的时候发射 B 粒子。
fireworks 部分的代码也可以这样表示
1 | burst.birthRate = 1.0/rocket.lifetime; |
取消叠加的坑
你做了取消叠加部分的操作,发现 A 粒子生命周期结束时并没有出现爆炸效果的粒子 C,这个时候问题出现在哪里呢?
原因就是刚好在 A 生命周期的结尾要发射单个粒子 B 的时候,A died,然后 B 就没发射出来……
这个时候你需要将 A 的生命周期比原来加长一点,要比 B 的生成间隔时间长那么一小点,代码实现上为:
1 | CGFloat rocketLifeTime = 1.0f; |
或者
1 | burst.birthRate = 1.0f/(rocket.lifetime-0.01f); |
补充:粒子属性的继承
如果发射器是粒子的话,它的相应属性,会继承给它发射出的子粒子。比如说粒子 A 设置了 redSpeed 属性,粒子 B redSpeed 的默认值会和 A 相同,除非 B 自己设置一个 redSpeed 的数值。
参考博文: