Cocos2d-x 2D粒子系统详解

Cocos2d-x 2D粒子系统

声明:本文使用的是cocos2d-x-3.17的代码

文章中的提到的测试代码下载地址https://gitee.com/Kyle12/Cocos2dRenderStudy

这里分析的是Cocos2d中的2d粒子系统,包括粒子系统中的各个参数,以及粒子的更新,粒子的运动。Cocos2d-x中类ParticleSystem实现了对粒子的控制,类ParticleSystemQuad实现了粒子的绘制。在CCParticleExamples中的各种粒子特效都是通过调整ParticleSystem中的各种参数得到的。

粒子系统ParticleSystem

粒子系统类ParticleSystem并本身没有粒子的绘制,其主要实现了粒子的更新,包括增加新粒子,删除死亡粒子,更新粒子状态(粒子的位置、颜色、大小、旋转等等)。ParticleSystem类结如下:

粒子数据与粒子系统数据

粒子数据

粒子数据是指单独一个粒子独有的数据,包括粒子的位置、速度、颜色、大小、旋转量、生存时间等等,这些数据全部存储在ParticleSystem:: _particleData中。这些数据会在更新粒子状态时改变,粒子的更新是有一定规律的,所以粒子数据也是有规律的变化,并不会随机的改变。另外粒子数据包含了所有的绘制粒子所需要的数据。

粒子系统数据

粒子系统数据是用来生成粒子的数据,这些数据控制了粒子的初始状态,存放在ParticleSystem类的成员变量中。因为粒子需要一定的随机性,粒子的更新并不会随机变化,粒子随机是随机设置粒子的初始状态。粒子初始状态是由粒子系统数据控制的,所以粒子系统的数据要有一定的变化量。为了实现这个变化量,ParticleSystem类中有很多命名以Var结尾的变量,这些变量就代表了初始粒子数据的随机变化量。例如:_life/_lifeVar代表粒子的生存时间,如果_life=5,_lifeVar=1,那么生成的粒子生存时间随机范围为[5-1, 5+1]。Cocos2d中的各种粒子特效都是通过调整粒子系统数据得到的,不同的粒子系统数据可以产生不同的粒子效果。

 

粒子数量:粒子系统可以控制粒子的最大数量,粒子系统粒子数量到达最大时则暂时不发射粒子(生成新粒子),如果有粒子死亡导致粒子数量减少则又会发射粒子。可以通过函数ParticleSystem::stopSystem停止发射粒子,但已发射的粒子不受影响会继续运动,直到耗尽生存时间。

粒子的运动

Cocos2d粒子系统支持两种粒子运动方式,重力模式(GRAVITY)和放射模式(RADIUS)。两者的粒子系统数据分别存放在ParticleSystem::modeA和ParticleSystem::modeB,两者的粒子数据存放在_particleData.modeA和_particleData.modeB。ParticleSystem类继承值Node类,Node类实现Cocos2d的坐标系统,所以粒子系统有自己的坐标系,粒子运动位置的更新都是在粒子系统的坐标系下完成的。

 

Cocos2d在线粒子编辑器Effecthub,可以编辑粒子设置粒子系统的各个参数。

Effecthub编辑的粒子会在编辑器上有一个位置,这个位置最终成为粒子系统在父节点上的位置。如果绘制通过Effecthub编辑的粒子系统,没有显示在屏幕上,有可能是因为这个问题,这时候需要将编辑好的粒子移动的坐下角,也就是坐标系0,0处。如下图:

  

重力模式

粒子系统数据和粒子数据中重力模式参数

 

重力gravity是一个二维向量,对于同一粒子系统中的所有粒子都使用同一个重力加速度,所以粒子数据中不需要存储重力。

速度speed/speedVar是一个float数,在粒子数据中速度却是一个二维向量。单一的float是没有方向的,所以要转换成二维向量,还需要一个方向,这个方向由ParticleSystem:: _angle/ _angleVar控制。以下代码是ParticleSystem::addParticles设置粒子速度的代码:

float a = CC_DEGREES_TO_RADIANS_angle + _angleVar * RANDOM_M11(&RANDSEED) );

Vec2 v(cosfa ), sinfa ));

float s = modeA.speed + modeA.speedVar * RANDOM_M11(&RANDSEED);

Vec2 dir = v * s;

_particleData.modeA.dirX[i] = dir.x;//v * s ;

_particleData.modeA.dirY[i] = dir.y;

经向加速度radialAccel/radialAccelVar是一个float值,径向加速度方向为,粒子位置坐标与粒子系统坐标原点的连线,正数为远离原点的方向。

垂直加速度tangentialAccel/tangentialAccelVar,也叫切向加速度,方向和径向加速度垂直。

经向加速度和垂直加速度方向会随着粒子位置的改变而改变。

 

重力模式粒子位置更新

粒子状态的更新是由ParticleSystem::update函数完成,位置更新的代码如下:

particle_point tmp, radial = {0.0f, 0.0f}, tangential;
// radial acceleration
if (_particleData.posx[i] || _particleData.posy[i])
{
    normalize_point(_particleData.posx[i], _particleData.posy[i], &radial);
}
tangential = radial;
radial.x *= _particleData.modeA.radialAccel[i];
radial.y *= _particleData.modeA.radialAccel[i];
                
// tangential acceleration
std::swap(tangential.x, tangential.y); // 交换后x变量乘以-1得到径向加速度的垂直方向
tangential.x *= - _particleData.modeA.tangentialAccel[i];
tangential.y *= _particleData.modeA.tangentialAccel[i];
                
// (gravity + radial + tangential) * dt
tmp.x = radial.x + tangential.x + modeA.gravity.x;
tmp.y = radial.y + tangential.y + modeA.gravity.y;
tmp.x *= dt; tmp.y *= dt;
//先更新粒子速度
_particleData.modeA.dirX[i] += tmp.x;
_particleData.modeA.dirY[i] += tmp.y;
  
// 更新粒子位置
tmp.x = _particleData.modeA.dirX[i] * dt * _yCoordFlipped;
tmp.y = _particleData.modeA.dirY[i] * dt * _yCoordFlipped;
_particleData.posx[i] += tmp.x;
_particleData.posy[i] += tmp.y;

 

放射模式

粒子系统数据和粒子数据放射模式参数

 

放射模式下可以把粒子数据中的radius和angle看着一个极坐标,两者分别代表极经和极角。放射模式下会有两个圆,一个有起始半径控制,一个由最终半径控制,点的极经会在生存时间内从起始半径变化到最终半径,粒子的极角每秒会变化量由rotatePerSecond/rotatePerSecondVar控制。

粒子的初始角度(极角)是由ParticleSystem:: _angle/ _angleVar控制。发射模式粒子运动图如下:

 

放射模式粒子位置更新

//更新机坐标系,使用 += 
for (int i = 0; i < _particleCount; ++i)
{
    _particleData.modeB.angle[i] += _particleData.modeB.degreesPerSecond[i] * dt;
}
for (int i = 0; i < _particleCount; ++i)
{
    _particleData.modeB.radius[i] += _particleData.modeB.deltaRadius[i] * dt;
}
//将极坐标转换为直角坐标,使用 = 
for (int i = 0; i < _particleCount; ++i)
{
   _particleData.posx[i]=- cosf(_particleData.modeB.angle[i]) * _particleData.modeB.radius[i];
}
for (int i = 0; i < _particleCount; ++i)
{
    _particleData.posy[i] = - sinf(_particleData.modeB.angle[i]) * _particleData.modeB.radius[i] * _yCoordFlipped;
}

 

粒子的位置

粒子位置与粒子系统位置

粒子系统ParticleSystem类继承值Node类,Node类实现Cocos2d的坐标系统,所以粒子系统有自己的位置(粒子系统位置),也有自己的坐标系,粒子运动位置的更新都是在粒子系统的坐标系下完成的。粒子系统位置指的是粒子系统在其父节点上的位置,粒子位置是粒子在粒子系统坐标系下的位置。

粒子数据中的位置坐标_particleData.posx/posy记录的是粒子在粒子系统坐标系下的位置。当粒子发射后,粒子位置坐标_particleData.posx/posy会按照重力模式或者放射模式更新,更新的时候并不会与粒子系统位置有关,也就是说粒子系统位置的改变不会影响粒子的位置数据的更新。

位置模式

粒子系统支持三种位置模式,三种位置模式,FREE自由模式、RELATIVE相对模式、GROUPED独立模式。

FREE自由模式,粒子系统可以保证发射后的粒子相对于世界坐标系下移动,不会因为粒子系统位置的改变而改变。

RELATIVE相对模式,粒子系统可以保证发射后的粒子相对于粒子系统父节坐标系下移动,当粒子系统父节点移动时,粒子跟着移动,但粒子系统的移动不影响粒子位置。

GROUPED独立模式,粒子系统可以保证发射后的粒子当粒子系统移动是粒子跟着移动。

 

实际上位置模式并不会影响_particleData.posx/posy的更新,位置模式会影响粒子位置初始偏移_particleData. startPosX/startPosY,具体影响如下:

在绘制粒子时可以通过粒子的初始位置偏移量,以及绘制时粒子系统为位置偏移来计算粒子最终的偏移。

粒子位置模式测试程序,完整代码ParticlePositionScene.cpp/ParticlePositionScene.h对应主程序菜单:“"Test Particle System”->“Position Type Test”。

 

 

 

粒子绘制ParticleSystemQuad

粒子系统类ParticleSystem本身并没有实现粒子的绘制,其主要是提供绘制粒子的数据,cocos2d中实现粒子绘制的类为ParticleSystemQuad。ParticleSystemQuad类继承至ParticleSystem,会根据粒子系统类中的数据绘制粒子。

 

ParticleSystemQuad结构如下:

 

正如类名中的Quad,ParticleSystemQuad类绘制粒子的方式是绘制正方形,使用的绘制QuadCommand命令。QuadCommad继承至TrianglesCommand,Cocos2d的Render类会把QuadCommand当作TrianglesCommand处理。TrianglesCommand正是精灵类Sprite的处理命令,也就是说绘制时每个粒子相当于一个精灵Sprite,一个粒子需要绘制六个点两个三角形。这种绘制效率并不高,实际上OpenGL中可以使用点精灵来绘制粒子,这种情况下每个粒子只相当于一个点。Cocos2d中完全可以通过重写ParticleSystem类来实现用点精灵绘制的粒子系统。

 

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值