第28课 - 粒子引擎


更新时间:2014年2月14日


粒子引擎可以用来创建一些效果,比如火焰,烟雾,或者在本课中的火花轨迹。这里我们将建立一个非常简单的粒子引擎,使火花环绕着小点。
class Particle
{
    private:
    //坐标
    int x, y;
    
    //当前动画的帧
    int frame;
    
    //粒子的类型
    SDL_Surface *type;
    
    public:
    //构造函数
    Particle( int X, int Y );
    
    //显示粒子
    void show();

    //检查粒子是否死亡
    bool is_dead();
};
粒子仅仅都是微型的动画。我们需要在点的周围加上一组微小的闪光的火花,看上去就像这样:
所以我们将创建一个粒子类并给点加上一组粒子。

这些火花粒子真的很简单。它们有坐标,动画中的一帧以及一个表面。

在函数方面,它们有个构造函数,一个显示火花的函数,以及一个检查火花是否仍然存活的函数。
//点
class Dot
{
    private:
    //坐标
    int x, y;
    
    //点的速度
    int xVel, yVel;
    
    //粒子
    Particle *particles[ TOTAL_PARTICLES ];
    
    public:
    //初始化
    Dot();
    
    //清理粒子
    ~Dot();
    
    //处理按键
    void handle_input();
    
    //移动点
    void move();
    
    //显示粒子
    void show_particles();
    
    //显示点
    void show();
};
这里我们有老朋友Dot类,经过修改,它能包含那些粒子。
bool init()
{
    //初始化所有SDL子系统
    if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 )
    {
        return false;    
    }
    
    //设置屏幕
    screen = SDL_SetVideoMode( SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_BPP, SDL_SWSURFACE );
    
    //如果设置屏幕时出错
    if( screen == NULL )
    {
        return false;    
    }
    
    //设置窗口标题
    SDL_WM_SetCaption( "Particle Test", NULL );
    
    //设置随机数种子
    srand( SDL_GetTicks() );
    
    //如果所有初始化成功
    return true;
}
因为我们将需要随机数,将其用于我们的粒子引擎,所以我们在初始化函数中用当前时间(这是一种常见做法)来设定随机数种子。
Particle::Particle( int X, int Y )
{
    //设置坐标
    x = X - 5 + ( rand() % 25 );
    y = Y - 5 + ( rand() % 25 );
    
    //初始化动画
    frame = rand() % 5;
    
    //设置类型
    switch( rand() % 3 )
    {
        case 0: type = red; break;
        case 1: type = green; break;
        case 2: type = blue; break;
    }
}
这是我们的粒子类的构造函数。

参数"X" and "Y"将会是点的坐标。我们获取这个参数并将粒子放在点的附近的一个随机位置。

然后我们将动画的帧初始化为0到4之间的一个随机数。这是因为我们想让每个粒子的动画异步进行。

然后我们设置表面类型为红、绿或蓝粒子表面。这也是随机地指定的。
void Particle::show()
{
    //显示图像
    apply_surface( x, y, type, screen );
    
    //显示微光
    if( frame % 2 == 0 )
    {
        apply_surface( x, y, shimmer, screen );    
    }
    
    //运行动画
    frame++;
}
这是我们的火花的show()函数。

我们所做的是:先显示我们的表面,然后如果帧数可以被2整除,就在红、绿或蓝表面的上面显示微光表面。微光表面只是一个半透明的白色表面。这样会使得粒子呈现闪烁的动画。
bool Particle::is_dead()
{
    if( frame > 10 )
    {
        return true;    
    }
    
    return false;
}
这里我们有一个函数用于检查粒子是否死亡。

一个粒子在它的动画经过10帧后被认定为死亡。
Dot::Dot()
{
    //初始化坐标
    x = 0;
    y = 0;
    
    //初始化速度
    xVel = 0;
    yVel = 0;
    
    //初始化粒子
    for( int p = 0; p < TOTAL_PARTICLES; p++ )
    {
        particles[ p ] = new Particle( x, y );
    }
}

Dot::~Dot()
{
    //删除粒子
    for( int p = 0; p < TOTAL_PARTICLES; p++ )
    {
        delete particles[ p ];
    }
}
这里是Dot类的构造函数和析构函数。这里Dot类唯一的变化时我们在构造函数内生成了粒子并在析构函数中去除了它们。
void Dot::show()
{
    //显示点
    apply_surface( x, y, dot, screen );
    
    //显示粒子
    show_particles();
}
这里你可以看到我们修改了点的show()函数来显示粒子。
void Dot::show_particles()
{
    //遍历粒子
    for( int p = 0; p < TOTAL_PARTICLES; p++ )
    {
        //删除并替换死亡的粒子
        if( particles[ p ]->is_dead() == true )
        {
            delete particles[ p ];
            
            particles[ p ] = new Particle( x, y );
        }
    }
    
    //显示粒子
    for( int p = 0; p < TOTAL_PARTICLES; p++ )
    {
        particles[ p ]->show();
    }
}
当我们显示粒子时,我们首先遍历它们,删除并替换死亡的粒子。

所有死亡的粒子都被替换后,我们在点的上面显示粒子。

这是一个有关粒子引擎的十分具有极简抽象派风格的例子,但其中包含了粒子引擎的最基本的技术。你可以通过创建更多细致的动画,添加速度、加速度、旋转等属性,或者使粒子之间可以互相交互,来构建更加高级并且更加漂亮的粒子。

动手实验吧,看看你可以创造什么样的效果。

本课所用的多媒体文件和源代码可从此处下载

下一课:平铺