网页
资讯
视频
图片
知道
文库
贴吧
地图
采购
进入贴吧
全吧搜索
吧内搜索
搜贴
搜人
进吧
搜标签
日
一
二
三
四
五
六
签到排名:今日本吧第
个签到,
本吧因你更精彩,明天继续来努力!
本吧签到人数:0
一键签到
成为超级会员,使用一键签到
一键签到
本月漏签
0
次!
0
成为超级会员,赠送8张补签卡
如何使用?
点击日历上漏签日期,即可进行
补签
。
连续签到:
天 累计签到:
天
0
超级会员单次开通12个月以上,赠送连续签到卡3张
使用连续签到卡
04月18日
漏签
0
天
easyx吧
关注:
10,878
贴子:
46,618
看贴
图片
吧主推荐
游戏
6
回复贴,共
1
页
<<返回easyx吧
>0< 加载中...
easyx实现一个粒子发射器,再实现烟花效果。
取消只看楼主
收藏
回复
psjoweb51250
幼儿园
2
该楼层疑似违规已被系统折叠
隐藏此楼
查看此楼
初学C语言的时候,发现了easyx,看群里精品贴,试着模仿,让我发现了新大陆。精品贴里面最吸引我的是几个游戏教程,其次就是表白烟花了。下载了源代码,仔细研究,却发现无能为力。大神写的耦合性太高,里面的模块几乎不能动,我只好用ps切了几张图,改改之后当作宝贝送给了朋友。两年后的今天,慢慢的能力提升了,又想起当年的表白烟花,结合网上的资料自己动手,再次实现了一个简单版,没有大神写的美观。但是这不仅仅是一个烟花,如果稍微修改一下,可玩性很高。后面我还会基于这个代码写一些其他的demo,代码贴上来。写了很详细的注释,便不再重复讲解了。有疑问欢迎留言,欢迎批评指正。
psjoweb51250
幼儿园
2
该楼层疑似违规已被系统折叠
隐藏此楼
查看此楼
代码实现的效果图
psjoweb51250
幼儿园
2
该楼层疑似违规已被系统折叠
隐藏此楼
查看此楼
代码结构如上
psjoweb51250
幼儿园
2
该楼层疑似违规已被系统折叠
隐藏此楼
查看此楼
我现在学的是java,这个代码开始是我学习html5的时候,使用js+canvas实现的,对于c++已经不是很熟练了,都是大学课堂上的一些知识点,依稀还记得,难免有不规范的地方,见谅。下面贴代码:每层一个.cpp
psjoweb51250
幼儿园
2
该楼层疑似违规已被系统折叠
隐藏此楼
查看此楼
Particle.h
#pragma once
//easyx官网介绍的解决outtexy重载问题
#undef UNICODE
#undef _UNICODE
#include<math.h>
#include<time.h>
#include<conio.h>
#include <graphics.h>
#include <list>
#include <tchar.h>
#include <string>
using namespace std;
//此处normal表示正常模式,booming表示爆炸模式,boomed表示已经爆炸
#define NORMAL 0
#define BOOMING 1
#define BOOMED 2
#define WIDTH 640
#define HEIGHT 480
//位置,x,y坐标,此处坐标系参考easyx帮助文档基本概念
struct Pos{
int x;
int y;
};
//速度,水平和垂直
struct Speed{
int x;
int y;
};
//自定义颜色类,记录rgb还有亮度,但是没有在easyx中发现渐变亮度的方法,以后再实现
class MyColor{
public:
int color[4];
//封装set方法,方便设置值
void setColor(int r,int g,int b,int l){
color[0] = r;
color[1] = g;
color[2] = b;
color[3] = l;
}
};
//设置类,这是一个我和你(当前阅读者)的约定,只在这个类里面写常用的配置
class Settings
{
private:
//内部类basic 里面是粒子生成器基本参数
class Basic{
public:
//显示的粒子个数
int p_count ;
//粒子发射的角度,后面要转换成弧度,再计算分速度
int min_angle;
int angle_range;
//速度
int min_speed;
int speed_range;
//生命,时间单位是毫秒,后面计算速度的时候要适当的缩放成秒,不然算出来的数值太大
int min_life ;
int life_range;
//控制粒子大小,以上所有的值都不要设置为0,否则可能出现异常。
int min_size;
int size_range;
};
struct Gravity{
int gx;
int gy;
};
public:
Settings(void);
~Settings(void);
//此处封装一个方法,调用之后就可以自动的将烟花的参数赋值给settings类
void setForFire();
void setForLaunch();
Basic basic;
//自定义的颜色类保存颜色,可以保存多个初始颜色,只需要new MyColor[n]数组就可以
MyColor *startColor;
//返回初始颜色个数
int getStartColorNum(){
return sizeof(startColor)/sizeof(startColor[0]);
}
//结束的颜色,后面可以实现颜色渐变,从初始到结束,当然如果让endColor=startColor就不会渐变了
MyColor *endColor;
//返回结束的颜色个数
int getEndColorNum(){
return sizeof(endColor)/sizeof(endColor[0]);
}
Gravity gravity;
};
//真正的粒子类
class Particle
{
public:
//是否存活标记,死亡的粒子被清扫
bool dead;
Particle();
//有参构造函数,初始化粒子的时候给粒子加入属性
Particle(int x,int y,int speed,int life ,int angle ,int size ,MyColor startColor,MyColor colorStep);
~Particle(void);
int life;
int lived;
int angle;
int size;
Pos pos;
Speed sd;
//保存粒子诞生时的颜色
MyColor color;
//保存粒子渐变颜色的值,它的单位应该是:颜色值/时间
MyColor cStep;
};
//粒子生成器,也是发射器,维护粒子,创造粒子,清扫死亡粒子,显示粒子当前位置和颜色。
class Emitter
{
public:
Emitter(void);
//发射器初始化位置,给当前生成器使用的配置(配置就是一些basic参数和startColor,endColor,重力等参数)
//bm参数需要用到上面defined 的 nomal 或者 booming 两者之一,一个表示普通模式,一个表示爆炸模式。
Emitter(int x,int y,Settings ss,int bm);
~Emitter(void);
//维护粒子
void update();
//获取是否完成爆炸全过程
int getBoomState();
//
void resetBoom();
Pos pos;
private:
Settings thisSet;
//集合容器(容器就是书包、柜子、水桶,可以放东西),集合自带一些方法(增删查改)方便用,具体请百度。
list<Particle> fireParticles;
Speed speed;
//上一次更新时间,这个参数从系统时间获取,记录上次更新时间,方便算时间差。在爆炸模式下,还起控制作用
long lastUpdateTime;
//单个粒子生成需要花费的时间(毫秒),用一秒/粒子总数 就可以。
double eachEmissionLife;
//用于生成粒子的时间,爆炸模式下固定为一秒,普通模式则是计算出来的。
int createEmissionTime;
//模式控制
int boom;
};
class Fire
{
public:
Fire(void);
~Fire(void);
//维护两个发射器对象,一个做发射动画,一个做爆炸动画
void update();
//每次爆炸结束,重置相关参数
void resetRandomXH();
//判断烟花是不是可以爆炸了
bool isTimeToBooming();
private:
Pos pos;
Speed sd;
//爆炸的高度
int boomHeight;
//随机水平位置
int randomWidth;
//这是烟花效果发射器
Emitter fireworks;
//这是烟花爬升阶段发射器
Emitter launch;
//记录更新时间
long lastUpdateTime;
};
psjoweb51250
幼儿园
2
该楼层疑似违规已被系统折叠
隐藏此楼
查看此楼
Emitter.cpp
#include "Particle.h"
Emitter::Emitter(void)
{
}
//初始化发射器对象的位置,当前发射器使用的配置,模式
Emitter::Emitter(int x,int y,Settings ss,int bm){
pos.x = x;
pos.y = y;
thisSet = ss;
//计算单个粒子生成时间
eachEmissionLife = 1000 / thisSet.basic.p_count;
lastUpdateTime = 0;
//可以用于创造粒子的时间
createEmissionTime = 0;
boom = bm;
}
Emitter::~Emitter(void)
{
}
void Emitter::update(){
//如果上一次的更新时间没有被记录,那就记录一下
if(lastUpdateTime==0){
lastUpdateTime = clock();
return ;
}
clock_t now = clock();
//当前时间减去上一次的更新时间,获得中间的时间差
double duration = now - lastUpdateTime;
//判断模式
if(this->boom > NORMAL){
//爆炸模式下创造粒子的时间固定
this->createEmissionTime =1000;
}else{
//普通模式下创造粒子的时间,取决于时间差和上一次剩余的时间
this->createEmissionTime+=duration;
}
//将更新时间记录下来
lastUpdateTime = clock();
//如果粒子生成粒子时间大于生成单个粒子所需要的时间才渲染粒子
if (this->createEmissionTime>this->eachEmissionLife && this->boom<BOOMED)
{
if (this->boom==BOOMING)
{
this->boom = BOOMED;
}
//粒子生成器的粒子生成粒子时间除以单个粒子生成时间,就得出粒子生成器一共要创造多少个粒子
int particleCount = this->createEmissionTime / this->eachEmissionLife;
//粒子生成器用于生成粒子的时间,减去已经用去的生成粒子时间
this->createEmissionTime -= particleCount*this->eachEmissionLife;
while (particleCount--)
{
int life =this->thisSet.basic.min_life + rand() % (this->thisSet.basic.life_range);
int startRand = this->thisSet.getStartColorNum();
MyColor startColor = thisSet.startColor[startRand];
int endRand = thisSet.getEndColorNum();
MyColor endColor= thisSet.endColor[endRand];
MyColor step;
//缩放一万倍,为了保证精度,颜色是整型,不缩放就会因为小数位丢失太多而损失精度。
step.setColor(
(endColor.color[0] - startColor.color[0])*10000/life,
(endColor.color[1] - startColor.color[1])*10000/life,
(endColor.color[2] - startColor.color[2])*10000/life,
(endColor.color[3] - startColor.color[3])*10000/life
);
//根据配置文件生成粒子,并且用集合容器保存下来
this->fireParticles.push_back( Particle(
//this->pos.x,
//this->pos.y,
0,
0,
this->thisSet.basic.min_speed + rand() % (this->thisSet.basic.speed_range),
life,
this->thisSet.basic.min_angle + rand() % (this->thisSet.basic.angle_range),
this->thisSet.basic.min_size + rand() % (this->thisSet.basic.size_range),
startColor,
step
)
);
}
}
list<Particle>::iterator particle;
//getch();
for ( particle=this->fireParticles.begin();particle!=fireParticles.end();)
{
if (particle->dead)
{
//清除死亡的粒子
this->fireParticles.erase(particle++);
continue;
}
//粒子存活时间更新
particle->lived+=duration;
//判断粒子寿命
if (particle->lived > particle->life)
{
particle->dead = true;
particle++;
continue;
}
//加速度,水平模拟风力,垂直模拟重力
particle->sd.x += thisSet.gravity.gx * duration /1000;
particle->sd.y += thisSet.gravity.gy * duration /1000;
//更新粒子坐标
particle->pos.x += particle->sd.x * duration / 1000 ;
particle->pos.y += particle->sd.y * duration / 1000 ;
//缩放一万倍,为了保证精度,颜色是整型,不缩放就会因为小数位丢失太多而损失精度。
//颜色渐变,改变r,g,b,三个值。
particle->color.color[0] += particle->cStep.color[0]*duration / 10000;
particle->color.color[1] += particle->cStep.color[1]*duration / 10000;
particle->color.color[2] += particle->cStep.color[2]*duration / 10000;
particle->color.color[3] += particle->cStep.color[3]*duration / 10000;
/*setfillcolor(
RGB(
particle->color.color[0]+particle->cStep.color[0]*particle->lived/10000,
particle->color.color[1]+particle->cStep.color[1]*particle->lived/10000,
particle->color.color[2]+particle->cStep.color[2]*particle->lived/10000
)
);*/
//根据rgb合成颜色
setcolor(
RGB(
particle->color.color[0],
particle->color.color[1],
particle->color.color[2],
)
);
setfillcolor(
RGB(
particle->color.color[0],
particle->color.color[1],
particle->color.color[2],
)
);
//相对发射器位置。也可以改成独立存在,不受发射器位置影响
int x = particle->pos.x + pos.x;
int y = particle->pos.y + pos.y;
fillcircle(x,y,particle->size);
particle++;
}
}
//这里获取的是爆炸状态是否完全完成,如果完全完成粒子数为0,返回值就是boomed
int Emitter::getBoomState(){
return boom+fireParticles.size();
}
//下一次爆炸需要更新的参数,仅仅爆炸模式下有效果
void Emitter::resetBoom(){
if(boom==NORMAL)
return ;
boom = BOOMING;
lastUpdateTime = 0;
}
psjoweb51250
幼儿园
2
该楼层疑似违规已被系统折叠
隐藏此楼
查看此楼
修复了村长提的部分问题之后效果更好看,顺便修复了自己的一个bug,颜色更丰富了。但是使用全屏模糊就是“肾亏眼花”效果
登录百度账号
扫二维码下载贴吧客户端
下载贴吧APP
看高清直播、视频!
贴吧页面意见反馈
违规贴吧举报反馈通道
贴吧违规信息处理公示