cocos2dx的粒子系统有三种位置类型。对我来说最经常使用的算是FREE了,由于这样的粒子。一旦发射,位置就不会再尾随粒子系统的Node(包含其父Node)。移动粒子系统的话,能够形成所谓的“拖尾”,看起来更自然。


free粒子的位置,仍然是在粒子系统下的本地空间坐标(尽管从理论上,free粒子一旦发射,就应当成为世界空间的一元。其坐标变换跟粒子系统的节点、发射器不再有关系)。由于影响器的參数,是在粒子系统的本地空间设置。

渲染粒子的时候,须要把粒子的位置。从本地空间变换到世界空间。假设粒子系统节点的位置发生变化。会反应到这一变换过程中,结果就是粒子会跟着节点一起移动,无法形成“拖尾”的效果。

为了实现free粒子在世界空间自由运动的效果。cocos2dx的做法是。在每一帧更新粒子坐标(在本地空间)后,给坐标作一次修正,然后用修正后的坐标,參与渲染的计算。这次修正的作用,就是要抵消掉粒子系统节点或者其父节点的位置变化,使得粒子看起来就像是世界空间中自由运动一样。


比方说,某个粒子系统P,直接挂在scene下,坐标是(100。200),发射了一颗粒子,粒子在P下的坐标是(0。0)。那么粒子在整个scene下的坐标就是(100。200)。

如果粒子水平向右移动10,那么它在P下的坐标就成了(10。0)。而在scene下则是(110,200)。

假设在同一时候。P向左移动了50,坐标变成(50,200),那么粒子在P下的坐标不变。仍然是(10,0)。但在scene下则是(60。200)。

对于free粒子来说,则不能受P向左移动50的影响,须要保持在scene下(110。200)的位置。

cocos2dx所作的修正,就是在发射粒子时,计算并记下此刻粒子系统的世界坐标(上例中的(100, 200))。

然后。在每帧更新粒子坐标时,再次计算这时粒子系统的世界坐标(上例的(50, 200)),相减的差值。加到粒子上。这样粒子在P下的坐标就是(60,0),变换到scene下后就是(110,200)。这个修正后的坐标(60,0),不会被记录下来,下一帧会又一次依据P的新坐标再修正。


假设没特别的需求,这是ok的。可是假设粒子系统或者其父层节点进行缩放、旋转、倾斜之类的操作。就会发现,当粒子系统在移动的时候,粒子乱套了。

由于cocos2dx是用世界空间的坐标差值。来修正一个本地空间的坐标。而这两个空间,一旦參照的坐标尺寸不一致,就会发生混乱。

以上面的样例,如果P被缩放为(0.5,0.5)。因为P在移动后。本身的坐标还是(50,200),对粒子进行修正的时候。差值仍然是(50,0),那么粒子被修正后,在P下的坐标还是(60,0)。然后,当把粒子变换到世界空间时。因为P的缩放比例(0.5,0.5),所以粒子的世界坐标实际上是 x = 60 * 0.5 + 50 = 80。y = 0 * 0.5 + 200 = 200,结果就是(80。200),而不是预期的(110,200)。


眼下我的解决方式,不正确free粒子作修正,而是依照理论的方式,每一帧直接计算粒子的世界坐标。

详细来说:

1、初始化一个粒子时,记录下此时粒子系统相对于世界的变换矩阵。这个矩阵能够把一个粒子系统本地坐标,变换成世界坐标;另外,这个矩阵是每一个粒子独有的;

2、每一帧仍然计算粒子在粒子系统中的本地坐标,但在用它计算4个顶点坐标时,乘上步骤1得到的矩阵;

3、步骤2得到的顶点坐标。实际上是在世界空间的坐标。所以,须要禁用掉visit(或者draw)里面,对粒子坐标的变换。忽略掉作为參数传入的transform,用一个单位矩阵取代。

这样就大功告成了。