出于速度的考虑,MyPfire运行在8bit模式下,使用了一个由黑到蓝,然后由蓝到白逐渐过渡的调色板。
运行程序后,你会看见大量发光的粒子在屏幕上运动,如果仔细观察一下就不难发现它们的运动规律:每一个粒子都有一定的生命周期,在这个周期内以一定的角加速度运动,同时,速度逐渐变慢。那么,我们不难定义出这样一个粒子结构
struct CParticle
{
float m_x; //当前x坐标
float m_y; //当前y坐标
float m_Angle; //方向
float m_Speed; //速度
float m_AngleAdjustment;//角加速度
float m_Life; //生命值
float m_Decay; //衰减速度
};
当一个粒子诞生时,我们需要对它进行一些必要的初始化,对于不同的效果,初始化的内容也是不一样的,下面是一种最简单的运动粒子的初始化:
void InitParticle(CParticle& particle, float x, float y)
{
particle.m_x = x;
particle.m_y = y;
particle.m_Speed = 1 + (Rnd( ) * 3);
particle.m_Angle = Rnd( ) * 2*pi;
particle.m_AngleAdjustment = -1/40.0f+Rnd( ) / 20;
particle.m_Life = 1.0f;
particle.m_Decay = 0.01f+Rnd( ) / 20;
}
可以看出,其中有许多参数带有一定的随机性,这样即可以保证每个粒子的坐标、速度或角加速度在一定范围内分布,也可以保证整体效果永远不会以相同的面貌出现。有了这些初始数据,我们就可以计算出粒子的运动轨迹:
void MoveParticle(CParticle& particle)
{
if (particle.m_Life <= 0)
return;
particle.m_x += (float)cos(particle.m_Angle) * particle.m_Speed;
particle.m_y += (float)sin(particle.m_Angle) * particle.m_Speed;
particle.m_Angle += particle.m_AngleAdjustment;
particle.m_Life -= particle.m_Decay;
}
每一次调用MoveParticle函数,即可获得该粒子的新坐标,同时粒子的生命值降低。如果粒子生命值>0,设置粒子在新坐标象素的颜色为255(调色板最大值),如果粒子生命值小于0,表明粒子已经死亡,不予显示,这样,就能够模拟出大量粒子的运动轨迹了。
实际上,MyPfire 程序在应用Partical System方面也就是上面这三段代码,但仅仅这些还是不够的,因为要显示出发光粒子拖着一条长尾巴的效果,还需要对图象进行一些特殊的处理才行。 Blur算法即是完成这个目的。Blur,模糊的意思,最简单的Blur算法是取该象素前后左右四个象素的平均值,代码如下:
for (y=1; y< height-1; y++)
for (x=1; x< width-1; x++)
{
pixel(x,y) = ( (pixel(x,y-1) + pixel(x-1, y) + pixel(x+1,y)+ pixel (x,y+1) ) << 2;
}
上面只是MyPfire程序中的一些原理性的描述和未经优化的代码,在具体编程中,还会有以下一些需要考虑和注意的问题:
1、对于大量粒子的管理,最好构造一个效果类(CEffect)封装起来,并且用预分配内存的数组形式储存,而不要用动态链表结构,因为数组的遍历比链表快得多,而且大量的new和delete也会极大的影响速度。
2、对粒子的初始状态和运动施以不同的规则,可以构造出不同的粒子火焰效果,烟火即可用这种方法实现。
3、对于调色板的灵活运用可以使程序更加富予色彩。如对调色板进行分段,可同时显示出不同颜色的粒子火焰;对调色板进行循环,显示出火焰整体色彩的变换。
4、Blur的算法有很多种,还可以实现Blur的同时向某个方向移动的效果,或是实现如火焰般的效果。
http://dev.21tx.com/game/index_1.html