//定义粒子系统状态
#define PARTICLE_STATE_DEAD 0
#define PARTICLE_STATE_ALIVE 1
//定义粒子的类型
#define PARTICLE_TYPE_FLICKER 0
#define PARTICLE_TYPE_FADE 1
//定义粒子颜色
#define PARTICLE_COLOR_RED 0
#define PARTICLE_COLOR_GREEN 1
#define PARTICLE_COLOR_BLUE 2
#define PARTICLE_COLOR_WHITE 3
//定义粒子数
#define MAX_PARTICLES 512
//颜色调色板索引范围
#define COLOR_RED_START 32
#define COLOR_RED_END 47
#define COLOR_GREEN_START 96
#define COLOR_GREEN_END 111
#define COLOR_BLUE_START 144
#define COLOR_BLUE_END 159
#define COLOR_WHITE_START 16
#define COLOR_WHITE_END 31
//风力与重力影响x轴和y轴上速度大小
const float particle_wind = 0.0f;
const float particle_gravity = 0.0f;
typedef struct tagPARTCLE
{
int state; //粒子状态
int type; //粒子效果类型
int x,y; //位置
int xv,yv; //粒子速度
int curr_color; //当前颜色
int start_color; //开始颜色调色板索引
int end_color; //结束颜色调色板索引
int counter; //生命周期,帧数
int max_count; //最大生命周数
}PARTICLE, *PARTICLE_PTR;
class Particle {
public:
PARTICLE particles[MAX_PARTICLES];
Particle() { Init_Reset_Particles(); }
public:
void Init_Reset_Particles(void);
void Start_Particle(int type, int color, int count,
float x, float y, float xv, float yv);
void Process_Particles(void);
void Draw_Particles(void);
//模拟粒子爆炸效果
void Start_Particle_Explosion(int type, int color, int count,
int x, int y, int xv, int yv, int num_particles);
void Start_Particle_Ring(int type, int color, int count,
int x, int y, int xv, int yv, int num_particles);
};
#include "particle.h"
void Particle::Init_Reset_Particles(void)
{
for (int index=0; index<MAX_PARTICLES; ++index)
{
particles[index].state = PARTICLE_STATE_DEAD;
particles[index].type = PARTICLE_TYPE_FADE;
particles[index].x = 0;
particles[index].y = 0;
particles[index].xv = 0;
particles[index].yv = 0;
particles[index].curr_color = 0;
particles[index].start_color= 0;
particles[index].end_color = 0;
particles[index].counter = 0;
particles[index].max_count = 0;
}
}
void Particle::Start_Particle(int type, int color, int count,
float x, float y, float xv, float yv)
{
int pindex = -1; // index of particle
// first find open particle
for (int index=0; index < MAX_PARTICLES; index++)
{
if (particles[index].state == PARTICLE_STATE_DEAD)
{
// set index
pindex = index;
break;
} // end if
}
// did we find one
if (pindex==-1)
return;
// set general state info
particles[pindex].state = PARTICLE_STATE_ALIVE;
particles[pindex].type = type;
particles[pindex].x = x;
particles[pindex].y = y;
particles[pindex].xv = xv;
particles[pindex].yv = yv;
particles[pindex].counter = 0;
particles[pindex].max_count = count;
// set color ranges, always the same
switch(color)
{
case PARTICLE_COLOR_RED:
{
particles[pindex].start_color = COLOR_RED_START;
particles[pindex].end_color = COLOR_RED_END;
} break;
case PARTICLE_COLOR_GREEN:
{
particles[pindex].start_color = COLOR_GREEN_START;
particles[pindex].end_color = COLOR_GREEN_END;
} break;
case PARTICLE_COLOR_BLUE:
{
particles[pindex].start_color = COLOR_BLUE_START;
particles[pindex].end_color = COLOR_BLUE_END;
} break;
case PARTICLE_COLOR_WHITE:
{
particles[pindex].start_color = COLOR_WHITE_START;
particles[pindex].end_color = COLOR_WHITE_END;
} break;
break;
} // end switch
// what type of particle is being requested
if (type == PARTICLE_TYPE_FLICKER)
{
// set current color
particles[pindex].curr_color = RAND_RANGE(particles[pindex].start_color, particles[pindex].end_color);
} // end if
else
{
// particle is fade type
// set current color
particles[pindex].curr_color = particles[pindex].start_color;
} // end if
}
void Particle::Process_Particles(void)
{
for (int index=0; index<MAX_PARTICLES; index++)
{
if (particles[index].state == PARTICLE_STATE_ALIVE)
{
particles[index].x+=particles[index].xv;
particles[index].y+=particles[index].yv;
particles[index].xv+=particle_wind;
particles[index].yv+=particle_gravity;
if (particles[index].type==PARTICLE_TYPE_FLICKER)
{
particles[index].curr_color = RAND_RANGE(particles[index].start_color,
particles[index].end_color);
if (++particles[index].counter >= particles[index].max_count)
{
particles[index].state = PARTICLE_STATE_DEAD;
}
}
else
{
if (++particles[index].counter >= particles[index].max_count)
{
particles[index].counter = 0;
if (++particles[index].curr_color>particles[index].end_color)
{
particles[index].state = PARTICLE_STATE_DEAD;
}
}
}
//屏幕边界测试
if (particles[index].x>SCREEN_WIDTH ||
particles[index].x<0 ||
particles[index].y>SCREEN_HEIGHT||
particles[index].y<0)
{
particles[index].state = PARTICLE_STATE_DEAD;
}
}
}
}
void Particle::Draw_Particles(void)
{
DDraw_Lock_Back_Surface();
for (int index=0; index<MAX_PARTICLES; index++)
{
if (particles[index].state==PARTICLE_STATE_ALIVE)
{
int x = particles[index].x;
int y = particles[index].y;
if (x>=SCREEN_WIDTH || x<0 || y>=SCREEN_HEIGHT || y<0)
continue;
Draw_Pixel(x,y,particles[index].curr_color,back_buffer, back_lpitch);
}
}
DDraw_Unlock_Back_Surface();
}
void Particle::Start_Particle_Explosion(int type, int color, int count,
int x, int y, int xv, int yv, int num_particles)
{
while(--num_particles >=0)
{
int ang=rand()%360;
float vel = 2+rand()%4;
Start_Particle(type, color, count,
x+RAND_RANGE(-50,50), y+RAND_RANGE(-50,50),
xv+cos_look[ang]*vel, yv+sin_look[ang]*vel);
}
}
void Particle::Start_Particle_Ring(int type, int color, int count,
int x, int y, int xv, int yv, int num_particles)
{
// this function starts a particle explosion at the given position and velocity
// note the use of look up tables for sin,cos
// compute random velocity on outside of loop
float vel = 200+rand()%4;
while(--num_particles >=0)
{
// compute random trajectory angle
int ang = rand()%360;
// start the particle
Start_Particle(type,color,count,
x,y,
xv+cos_look[ang]*vel,
yv+sin_look[ang]*vel);
} // end while
}