七夕程序:特效烟花 —— 分析
来源:互联网 发布:yum tcpdump 编辑:程序博客网 时间:2024/05/17 01:10
时隔两个月,我作业总算写完了=w=,最近参加了一个EasyX图形库官方群的活动,要求是做一个有关七夕的作品,我就写了个七夕烟花。
整个程序最重要的部分就是烟花,为了做出真正符合实际的烟花,我加入了重力效果,空气阻力效果,毕竟我做这个程序的时候才初二(写这篇博文的时候也是初二= =),还没学到物理,就用朋友的帮助和自己的想法构造物理效果。
以下是代码:
///////////////////////////////////////////////////// 程序名称:七夕烟花// 编译环境:Visual Studio 2017 / EasyX_2017测试版// 作 者:Allen_益文友 <540809998@qq.com>// 最后修改:2017-8-1// #pragma comment( lib,"winmm.lib")#include <windows.h>#include <graphics.h>#include <string> #include <conio.h>#include <time.h>#include <vector>using namespace std;// 每颗烟花的粒子数量#define PARTICLE_NUMBER 100// 同时存在的最大烟花数#define MAX_FIREWORK_NUMBER 6// 速度struct Speed{ float x; // 表示横向运动速度 float y; // 表示纵向运动速度};// 烟花粒子struct Particle{ float x = 0; // 表示横坐标 float y = 0; // 表示纵坐标 Speed speed; // 表示粒子当前运动速度 bool enable = true; // 表示粒子是否存在};// 烟花struct Firework{ float x; // 烟花爆炸点x坐标 float y; // 烟花爆炸点y坐标 vector<Particle> particles; // 储存了该烟花的粒子群 double R = 255; // 烟花的颜色R double G = 255; // 烟花的颜色G double B = 255; // 烟花的颜色B float radius = 2.0; // 表示烟花伪半径,该值越大,烟花半径越大 int colorChangeBuffer = 0; // 表示颜色变化的缓冲变量 static int number; // 记录了当前存在的烟花数量};int Firework::number = 0; // 重置烟花数量vector<Firework> fws; // 烟花群const double gravity = 0.01; // 重力值const double air = 0.002; // 空气阻力// 全屏模糊函数void Blur(){ static DWORD* pMem = GetImageBuffer(); // 获取显存地址 for (int i = 800; i < 800 * 599; i++) { pMem[i] = RGB( (GetRValue(pMem[i]) + GetRValue(pMem[i - 800]) + GetRValue(pMem[i - 1]) + GetRValue(pMem[i + 1]) + GetRValue(pMem[i + 800])) / 5, (GetGValue(pMem[i]) + GetGValue(pMem[i - 800]) + GetGValue(pMem[i - 1]) + GetGValue(pMem[i + 1]) + GetGValue(pMem[i + 800])) / 5, (GetBValue(pMem[i]) + GetBValue(pMem[i - 800]) + GetBValue(pMem[i - 1]) + GetBValue(pMem[i + 1]) + GetBValue(pMem[i + 800])) / 5); }}// 精准延时函数void HpSleep(int ms){ static clock_t oldclock = clock(); // 静态变量,记录上一次 tick oldclock += ms * CLOCKS_PER_SEC / 1000; // 更新 tick if (clock() > oldclock) // 如果已经超时,无需延时 oldclock = clock(); else while (clock() < oldclock) // 延时 Sleep(1); // 释放 CPU 控制权,降低 CPU 占用率}// 在(x,y)坐标处添加烟花bool AddFirework(short x, short y){ if (Firework::number == MAX_FIREWORK_NUMBER) return false; // 若当前烟花数量达到最大值,返回 false mciSendString(_T("play firework from 0"), NULL, 0, NULL); Firework fw; // 创建烟花 // 设置烟花爆炸点的坐标 fw.x = x; fw.y = y; // 设置烟花颜色 fw.R = rand() % 146 + 110; fw.G = rand() % 146 + 110; fw.B = rand() % 146 + 110; // 随机烟花粒子位置 for (int i = 0; i < PARTICLE_NUMBER; i++) { Particle p; // 创建粒子 // 在圆形范围内随机粒子速度 do { p.speed.x = (rand() % 201) / (200 / fw.radius / fw.radius) - fw.radius; p.speed.y = (rand() % 201) / (200 / fw.radius / fw.radius) - fw.radius; } while ((p.speed.x * p.speed.x + p.speed.y * p.speed.y) >= fw.radius * fw.radius); fw.particles.push_back(p); // 将粒子添加进粒子群 } Firework::number++; // 烟花数量+1 fws.push_back(fw); // 将该烟花添加进烟花群 return true;}// 移动全部烟花粒子void MoveFireworkParticle(){ // 创建临时变量 int x, y; int R; int G; int B; for (int i = 0; i < Firework::number; i++) { for (int j = 0; j < PARTICLE_NUMBER; j++) { // 若粒子不存在,跳过该粒子 if (!fws[i].particles[j].enable) continue; x = int(fws[i].particles[j].x + fws[i].x); y = int(fws[i].particles[j].y + fws[i].y); // 移动粒子位置 fws[i].particles[j].x -= fws[i].particles[j].speed.x; fws[i].particles[j].y -= fws[i].particles[j].speed.y; // 受重力影响的速度变化 fws[i].particles[j].speed.y -= gravity; // 受空气阻力影响的速度变化 if (fws[i].particles[j].speed.x > 0) fws[i].particles[j].speed.x -= air; if (fws[i].particles[j].speed.x < 0) fws[i].particles[j].speed.x += air; // 设置粒子颜色 if (fws[i].colorChangeBuffer++ == 30) { fws[i].R = (fws[i].R - 1 < 0) ? 0 : fws[i].R - 0.4; fws[i].G = (fws[i].G - 1 < 0) ? 0 : fws[i].G - 0.4; fws[i].B = (fws[i].B - 1 < 0) ? 0 : fws[i].B - 0.4; fws[i].colorChangeBuffer = 0; } setfillcolor(RGB(fws[i].R, fws[i].G, fws[i].B)); // 应用颜色 solidcircle(int(fws[i].particles[j].x + fws[i].x), int(fws[i].particles[j].y + fws[i].y), 1); // 绘制粒子 } }}// 清除已经消失的烟花void ClearDisappearFirework(){ vector<Firework>::iterator it; // 创建迭代器 // 找出所有已消失的烟花 for (it = fws.begin(); it != fws.end();) { // 若烟花绘制次数已达到最大生命周期,从烟花群中删除该烟花 if ((*it).R == 0 && (*it).G == 0 && (*it).B == 0) { it = fws.erase(it); Firework::number--; } else ++it; }}int main(){ initgraph(800, 600); // 开启图形界面 BeginBatchDraw(); // 开启批量绘图 srand((unsigned)time(NULL)); // 设置随即种子 SetConsoleTitle(_T("七夕烟花")); // 更改窗口名称 IMAGE Magpiebridge; loadimage(&Magpiebridge, _T("res\\Magpiebridge.jpg")); IMAGE man; loadimage(&man, _T("res\\man.jpg")); IMAGE woman; loadimage(&woman, _T("res\\woman.jpg")); IMAGE woman_; loadimage(&woman_, _T("res\\woman_.jpg")); IMAGE Introduction; loadimage(&Introduction, _T("res\\Introduction.jpg")); // 加载音乐/音效 mciSendString(_T("open res\\music.mp3 alias music"), NULL, 0, NULL); mciSendString(_T("open res\\firework.mp3 alias firework"), NULL, 0, NULL); // 播放背景音乐 mciSendString(_T("play music repeat"), NULL, 0, NULL); putimage(0, 0, &Introduction); // 显示图片 FlushBatchDraw(); // 进行批量绘图 getch(); // 获取按键输入 for (int i = 0; i < 90; i++) { setbkcolor(WHITE); // 设置背景颜色 cleardevice(); // 清除屏幕内容 setcolor(BLACK); // 设置颜色 setbkmode(TRANSPARENT); // 设置背景颜色 settextstyle(20, 0, _T("黑体")); // 设置文字属性 // 绘制文字 outtextxy(0, 0, _T("七夕节这天,牛郎织女又在鹊桥相遇,他们两人十分快乐,还放起了烟花。")); outtextxy(600, 25, _T("(按任何键继续)")); // 绘制文字 putimage(0, 460, &Magpiebridge); // 显示图片 putimage(0 + i, 200, &man); // 显示图片 putimage(400 - i, 200, &woman, SRCAND); // 显示图片 putimage(400 - i, 200, &woman_, SRCPAINT); // 通过掩码图制造透明区 FlushBatchDraw(); // 进行批量绘图 HpSleep(10); // 延时 } // 清空按键缓存区,防止上次按键信息遗留到此getch FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE)); getch(); // 获取按键输入 setbkcolor(BLACK); // 设置背景颜色 cleardevice(); // 清除屏幕内容 FlushBatchDraw(); // 进行批量绘图 // 自动生成烟花的缓冲变量 int autoCreateFirework = 0; while (true) { // 按下鼠标新增烟花 while (MouseHit()) { MOUSEMSG m = GetMouseMsg(); if (m.mkLButton) { AddFirework(m.x, m.y); } } // 按下q键退出程序 if (_kbhit()) { if (_getch() == 'q') break; } // 每隔一段时间自动生成一个烟花 if (autoCreateFirework-- == 0) { AddFirework(rand() % 500 + 100, rand() % 400 + 100); autoCreateFirework = 180; } MoveFireworkParticle(); // 移动烟花 ClearDisappearFirework(); // 删除消失的烟花 Blur(); // 全屏模糊处理 // 刷新视图 setcolor(BLACK); line(0, 0, 800, 0); line(0, 599, 800, 599); FlushBatchDraw(); HpSleep(10); // 延时 } EndBatchDraw(); // 停止批量绘图 closegraph(); // 关闭绘图环境 return 0;}
先讲添加烟花函数
bool AddFirework(short x, short y)
中的随机生成烟花粒子速度:
// 在圆形范围内随机粒子速度do{ p.speed.x = (rand() % 201) / (200 / fw.radius / fw.radius) - fw.radius; p.speed.y = (rand() % 201) / (200 / fw.radius / fw.radius) - fw.radius;} while ((p.speed.x * p.speed.x + p.speed.y * p.speed.y) >= fw.radius * fw.radius);
其中最重要的一行就是
while ((p.speed.x * p.speed.x + p.speed.y * p.speed.y) >= fw.radius * fw.radius);
如果木有这一行,随机生成粒子速度,就会导致烟花是方形的,原因很简单,
假设所有烟花粒子的x轴速度和y轴速度的上限都是1(负半轴同理),如果有3个烟花粒子
好,假设这些速度,都是一秒移动的距离,那么就算算一秒钟,这些烟花粒子都移动多远。
很明显,速度不同,而烟花粒子的运动方向就是右上,所以会变成这个样子:
很明显,补全另外的方向,就成了一个方形qwq,所以需要限制随机生成的速度,形成圆形。
处理物理效果的部分在
void MoveFireworkParticle()
函数中:
// 移动粒子位置fws[i].particles[j].x -= fws[i].particles[j].speed.x;fws[i].particles[j].y -= fws[i].particles[j].speed.y;// 受重力影响的速度变化fws[i].particles[j].speed.y -= gravity;// 受空气阻力影响的速度变化if (fws[i].particles[j].speed.x > 0) fws[i].particles[j].speed.x -= air;if (fws[i].particles[j].speed.x < 0) fws[i].particles[j].speed.x += air;
因为有重力,所以(苹果砸牛顿qwq)y轴速度会不断变小(向负半轴减少),
因为有空气阻力,所以烟花粒子会在烟花刚爆炸的时候速度很快,而后来会不断变慢:
// 受重力影响的速度变化fws[i].particles[j].speed.y -= gravity;// 受空气阻力影响的速度变化if (fws[i].particles[j].speed.x > 0) fws[i].particles[j].speed.x -= air;if (fws[i].particles[j].speed.x < 0) fws[i].particles[j].speed.x += air;
核心代码讲完qwq,表问我七夕剧情部分qwq,我剧情做的很渣qwq。
注:源代码去EasyX贴吧下载
阅读全文
0 0
- 七夕程序:特效烟花 —— 分析
- Android超炫酷烟花程序
- JavaScript 页面特效笔记集【汇总】——特效分析
- jquery实战6:高级特效烟花效果
- HTML5 Canvas烟花特效 场景十分华丽
- 按钮添加简单地烟花特效
- 用p5.js制作烟花特效
- 烟花爆炸色彩效果—ExplosionField
- 传说中的Java烟花程序
- 烟花
- 烟花
- 烟花
- 烟花
- 烟花
- 烟花
- 掌柜的——写在七夕
- 七夕表白程序源码
- [OpenGL] 简单二维粒子系统——烟花,喷水,落叶
- 心路历程
- 添加频道的兴趣爱好
- git好用的命令
- redis多线程排序Demo
- centos 6.8 + pgsql 9.6 + dblink
- 七夕程序:特效烟花 —— 分析
- ViewPager+小圆点_ListView网络请求
- 一个可以判定手机还是PC的PHP函数
- AES加密中的异常
- 字符串的统计
- js实现新增内容滚动播放效果
- 玩转Android二维码
- 你真的会SQL注入攻击吗?(上)
- (HDU