资讯专栏INFORMATION COLUMN

用C语言来写“烟花”,快拿去给心中的那个人看

Flink_China / 3345人阅读

摘要:想要学习资料以及其他项目的源码的可以加群了解。想要对程序员的未来发展有兴趣的也可加群闲聊。

你向窗外看烟火,我在窗边看你,这时,你比烟花好看的多,你的眼眸倒映满天的烟火,我的瞳孔倒影你闪光的眼色,这时,我比烟花寂寞

嗨!这里是狐狸~~

我之前有发过一篇有关程序员相亲的文章,今天突然翻起,又陷入了沉思,现在不会大家都觉得程序员不懂浪漫吧,真的大错特错,今天就让你们看看什么是程序员的浪漫!

 我们今天就来写写《烟花》表白程序,不要惊讶,不要激动,学会了快去拿给心中的那个人看!!!

煽情的话就不要我说了吧,直接上代码

一、结构体

首先当然是我们的老朋友结构体,其中艺术字结构体不用我多说,该写什么内容自己应该知道哈

</>复制代码

  1. // 烟花结构struct FIRE{
  2. int r;
  3. // 当前爆炸半径
  4. int max_r;
  5. // 爆炸中心距离边缘最大半径
  6. int x, y;
  7. // 爆炸中心在窗口的坐标
  8. int cen_x, cen_y;
  9. // 爆炸中心相对图片左上角的坐标
  10. int width, height;
  11. // 图片的宽高
  12. int xy[240][240];
  13. // 储存图片像素点
  14. bool show;
  15. // 是否绽放
  16. bool draw;
  17. // 开始输出像素点
  18. DWORD t1, t2, dt;
  19. // 绽放速度}Fire[NUM];// 烟花弹结构struct JET{
  20. int x, y;
  21. // 喷射点坐标
  22. int hx, hy;
  23. // 最高点坐标------将赋值给 FIRE 里面的 x, y
  24. int height;
  25. // 烟花高度
  26. bool shoot;
  27. // 是否可以发射
  28. DWORD t1, t2, dt;
  29. // 发射速度
  30. IMAGE img[2];
  31. // 储存花弹一亮一暗图片
  32. byte n : 1;
  33. // 图片下标}Jet[NUM];// happy birthday 艺术字结构struct HAPPY
  34. // 储存 Happy Birthday 艺术字图片{
  35. int x, y;
  36. // 每个字的图片的左上角坐标
  37. IMAGE img;
  38. // 储存单个字图片
  39. static int num;
  40. // 字母序号}Happy[NUM];

二、初始化

初始化烟花参数,把一切准备工作完成好

</>复制代码

  1. // 初始化烟花参数void Init( int i ){
  2. // 分别为:烟花中心到图片边缘的最远距离、烟花中心到图片左上角的距离 (x、y) 两个分量
  3. int r[13] = { 120, 120, 155, 123, 130, 147, 138, 138, 130, 135, 140, 132, 155 };
  4. int x[13] = { 120, 120, 110, 117, 110, 93, 102, 102, 110, 105, 100, 108, 110 };
  5. int y[13] = { 120, 120, 85, 118, 120, 103, 105, 110, 110, 120, 120, 104, 85 };
  6. /**** 初始化烟花 *****/
  7. Fire[i].x
  8. = 0;
  9. // 烟花中心坐标
  10. Fire[i].y
  11. = 0;
  12. Fire[i].width
  13. = 240;
  14. // 图片宽
  15. Fire[i].height
  16. = 240;
  17. // 图片高
  18. Fire[i].max_r
  19. = r[i];
  20. // 最大半径
  21. Fire[i].cen_x
  22. = x[i];
  23. // 中心距左上角距离
  24. Fire[i].cen_y
  25. = y[i];
  26. Fire[i].show
  27. = false;
  28. // 是否绽放
  29. Fire[i].dt
  30. = 5;
  31. // 绽放时间间隔
  32. Fire[i].t1
  33. = timeGetTime();
  34. Fire[i].r
  35. = 0;
  36. // 从 0 开始绽放
  37. /**** 初始化烟花弹 *****/
  38. Jet[i].x
  39. = -240;
  40. // 烟花弹左上角坐标
  41. Jet[i].y
  42. = -240;
  43. Jet[i].hx
  44. = -240;
  45. // 烟花弹发射最高点坐标
  46. Jet[i].hy
  47. = -240;
  48. Jet[i].height
  49. = 0;
  50. // 发射高度
  51. Jet[i].t1
  52. = timeGetTime();
  53. Jet[i].dt
  54. = rand() % 10;
  55. // 发射速度时间间隔
  56. Jet[i].n
  57. = 0;
  58. // 烟花弹闪烁图片下标
  59. Jet[i].shoot
  60. = false;
  61. // 是否发射}

三、烟花加载函数

加载图片,储存烟花的像素点颜色

</>复制代码

  1. // 加载图片void Load(){/**** 储存烟花的像素点颜色 ****/
  2. IMAGE fm, gm;
  3. loadimage( &fm, "./fire/flower.jpg", 3120, 240 );
  4. for ( int i = 0; i < 13; i++ )
  5. {
  6. SetWorkingImage( &fm );
  7. getimage( &gm, i * 240, 0, 240, 240 );
  8. SetWorkingImage( &gm );
  9. for ( int a = 0; a < 240; a++ )
  10. for ( int b = 0; b < 240; b++ )
  11. Fire[i].xy[a][b] = getpixel( a, b );
  12. }
  13. IMAGE sm;
  14. loadimage( &sm, "./fire/shoot.jpg", 200, 50 );
  15. for ( i = 0; i < 13; i++ )
  16. {
  17. SetWorkingImage( &sm );
  18. int n = rand() % 5;
  19. getimage( &Jet[i].img[0], n * 20, 0, 20, 50 );
  20. getimage( &Jet[i].img[1], (n + 5) * 20, 0, 20, 50 );
  21. }
  22. IMAGE hm;
  23. loadimage( &hm, "./fire/happy.jpg", 689, 115 );
  24. SetWorkingImage( &hm );
  25. for ( i = 0; i < 13; i++ )
  26. {
  27. Happy[i].x = i * 90;
  28. Happy[i].y = rand() % 100 + 500;
  29. getimage( &Happy[i].img, i * 53, 0, 53, 115 );
  30. }
  31. Wish.x
  32. = 0;
  33. Wish.y
  34. = 100;
  35. Wish.t1
  36. = timeGetTime();
  37. Wish.dt
  38. = 46;
  39. Wish.dir
  40. = 0;
  41. Wish.dxy
  42. = rand() % 8 + 1;
  43. loadimage( &Wish.img, "./fire/yaojing.jpg", 490, 100 );
  44. putimage( Wish.x, Wish.y, &Wish.img, SRCINVERT );
  45. SetWorkingImage();}

四、烟花发射函数

扫描烟花弹并发射,控制开始与停止发射

</>复制代码

  1. // 扫描烟花弹并发射void Shoot(){
  2. for ( int i = 0; i < 13; i++ )
  3. {
  4. Jet[i].t2 = timeGetTime();
  5. if ( Jet[i].t2 - Jet[i].t1 > Jet[i].dt && Jet[i].shoot == true )
  6. {
  7. /**** 烟花弹的上升 *****/
  8. putimage( Jet[i].x, Jet[i].y, &Jet[i].img[Jet[i].n], SRCINVERT );
  9. if ( Jet[i].y > Jet[i].hy )
  10. {
  11. Jet[i].n++;
  12. Jet[i].y -= 5;
  13. }
  14. putimage( Jet[i].x, Jet[i].y, &Jet[i].img[Jet[i].n], SRCINVERT );
  15. /**** 上升到高度的 3 / 4,减速 *****/
  16. if ( (Jet[i].y - Jet[i].hy) * 4 < Jet[i].height )
  17. Jet[i].dt = rand() % 4 + 10 ;
  18. /**** 上升到最大高度 *****/
  19. if ( Jet[i].y <= Jet[i].hy )
  20. {
  21. // 播放爆炸声
  22. char c1[50], c2[30], c3[30];
  23. sprintf( c1, "open ./fire/bomb.wav alias n%d", i );
  24. sprintf( c2, "play n%d", i );
  25. sprintf( c3, "close s%d", i );
  26. mciSendString( c3, 0, 0, 0 );
  27. mciSendString( c1, 0, 0, 0 );
  28. mciSendString( c2, 0, 0, 0 );
  29. putimage( Jet[i].x, Jet[i].y, &Jet[i].img[Jet[i].n], SRCINVERT );
  30. // 擦掉烟花弹
  31. Fire[i].x = Jet[i].hx + 10;
  32. // 在烟花弹中间爆炸
  33. Fire[i].y = Jet[i].hy;
  34. // 在最高点绽放
  35. Fire[i].show = true;
  36. // 开始绽放
  37. Jet[i].shoot = false;
  38. // 停止发射
  39. // 显示对应字母
  40. putimage( Happy[HAPPY::num].x, Happy[HAPPY::num].y, &Happy[HAPPY::num].img, SRCINVERT );
  41. HAPPY::num++;
  42. if ( HAPPY::num > 12 )
  43. HAPPY::num = 0;
  44. }
  45. Jet[i].t1 = Jet[i].t2;
  46. }
  47. }}

五、烟花显示函数

显示花样,如何让烟花变得更好看

</>复制代码

  1. // 显示花样void Style( DWORD& st1 ){
  2. DWORD st2 = timeGetTime();
  3. if ( st2 - st1 > 266000 )
  4. // 一首歌的时间
  5. {
  6. // 心形坐标
  7. int x[13] = { 60, 75, 91, 100, 95, 75, 60, 45, 25, 15, 25, 41, 60 };
  8. int y[13] = { 65, 53, 40, 22, 5, 4, 20, 4, 5, 22, 40, 53, 65 };
  9. for ( int i = 0; i < NUM; i++ )
  10. {
  11. cleardevice();
  12. /**** 规律分布烟花弹 ***/
  13. Jet[i].x
  14. = x[i] * 10;
  15. Jet[i].y
  16. = ( y[i] + 75 ) * 10;
  17. Jet[i].hx
  18. = Jet[i].x;
  19. Jet[i].hy
  20. = y[i] * 10;
  21. Jet[i].height
  22. = Jet[i].y - Jet[i].hy;
  23. Jet[i].shoot
  24. = true;
  25. Jet[i].dt
  26. = 7;
  27. putimage( Jet[i].x, Jet[i].y, &Jet[i].img[Jet[i].n], SRCINVERT );
  28. // 显示烟花弹
  29. /**** 设置烟花参数 ***/
  30. Fire[i].x
  31. = Jet[i].x + 10;
  32. Fire[i].y
  33. = Jet[i].hy;
  34. Fire[i].show
  35. = false;
  36. Fire[i].r
  37. = 0;
  38. /**** 播放发射声音 ***/
  39. char c1[50], c2[30], c3[30];
  40. sprintf( c1, "open ./fire/shoot.mp3 alias s%d", i );
  41. sprintf( c2, "play s%d", i );
  42. sprintf( c3, "close n%d", i );
  43. mciSendString( c3, 0, 0, 0 );
  44. mciSendString( c1, 0, 0, 0 );
  45. mciSendString( c2, 0, 0, 0 );
  46. }
  47. st1 = st2;
  48. }}

六、烟花绽放函数

绽放烟花,烟花个阶段绽放时间间隔,制作变速绽放效果等等,这里大家也可以自己去优化,去增加自己的东西

</>复制代码

  1. // 绽放烟花void Show( DWORD* pMem ){
  2. // 烟花个阶段绽放时间间隔,制作变速绽放效果
  3. int drt[16] = { 5, 5, 5, 5, 5, 6, 25, 25, 25, 25, 55, 55, 55, 55, 55 };
  4. for ( int i = 0; i < NUM; i++ )
  5. {
  6. Fire[i].t2 = timeGetTime();
  7. // 增加爆炸半径,绽放烟花,增加时间间隔做变速效果
  8. if ( Fire[i].t2 - Fire[i].t1 > Fire[i].dt && Fire[i].show == true )
  9. {
  10. if ( Fire[i].r < Fire[i].max_r )
  11. {
  12. Fire[i].r++;
  13. Fire[i].dt = drt[Fire[i].r / 10];
  14. Fire[i].draw = true;
  15. }
  16. if ( Fire[i].r >= Fire[i].max_r - 1 )
  17. {
  18. Fire[i].draw = false;
  19. Init( i );
  20. }
  21. Fire[i].t1 = Fire[i].t2;
  22. }
  23. // 如果该号炮花可爆炸,根据当前爆炸半径画烟花,颜色值接近黑色的不输出。
  24. if ( Fire[i].draw )
  25. {
  26. for ( double a = 0; a <= 6.28; a += 0.01 )
  27. {
  28. int x1 = (int)( Fire[i].cen_x + Fire[i].r * cos(a) );
  29. // 相对于图片左上角的坐标
  30. int y1 = (int)( Fire[i].cen_y - Fire[i].r * sin(a) );
  31. if ( x1 > 0 && x1 < Fire[i].width && y1 > 0 && y1 < Fire[i].height )
  32. // 只输出图片内的像素点
  33. {
  34. int b = Fire[i].xy[x1][y1] & 0xff;
  35. int g = ( Fire[i].xy[x1][y1] >> 8 ) & 0xff;
  36. int r = ( Fire[i].xy[x1][y1] >> 16 );
  37. // 烟花像素点在窗口上的坐标
  38. int xx = (int)( Fire[i].x + Fire[i].r * cos(a) );
  39. int yy = (int)( Fire[i].y - Fire[i].r * sin(a) );
  40. // 较暗的像素点不输出、防止越界
  41. if ( r > 0x20 && g > 0x20 && b > 0x20 && xx > 0 && xx < 1200 && yy > 0 && yy < 800 )
  42. pMem[yy * 1200 + xx] = BGR( Fire[i].xy[x1][y1] );
  43. // 显存操作绘制烟花
  44. }
  45. }
  46. Fire[i].draw = false;
  47. }
  48. }}

七、主函数

</>复制代码

  1. // 主函数void main(){
  2. initgraph( 1200, 800 );
  3. srand( time(0) );
  4. // 播放背景音乐
  5. mciSendString( "open ./fire/bk.mp3 alias bk", 0, 0, 0 );
  6. mciSendString( "play bk repeat", 0, 0, 0 );
  7. setfillstyle( 0
  8. );
  9. setfont
  10. ( 36, 0, "楷体"
  11. );
  12. setcolor
  13. ( YELLOW );
  14. outtextxy
  15. ( 370, 100, "yy滺滺__出厂 .... ^_^" );
  16. DWORD t1
  17. = timeGetTime();
  18. // 筛选烟花计时
  19. DWORD st1
  20. = timeGetTime();
  21. // 播放花样计时
  22. DWORD* pMem = GetImageBuffer();
  23. // 获取窗口显存指针
  24. for ( int i = 0; i < NUM; i++ )
  25. // 初始化烟花
  26. {
  27. Init( i );
  28. }
  29. Load();
  30. // 将烟花图片信息加载进相应结构中
  31. BeginBatchDraw();
  32. // 开始批量绘图
  33. while ( !kbhit() )
  34. {
  35. Sleep( 10 );
  36. // 随机选择 4000 个像素点擦除
  37. for ( int clr = 0; clr < 1000; clr++ )
  38. {
  39. for ( int j = 0; j < 2; j++ )
  40. {
  41. int px1 = rand() % 1200;
  42. int py1 = rand() % 800;
  43. if ( py1 < 799 )
  44. // 防止越界
  45. pMem[py1 * 1200 + px1] = pMem[py1 * 1200 + px1 + 1] = BLACK;
  46. // 对显存赋值擦出像素点
  47. }
  48. }
  49. Chose
  50. ( t1
  51. );
  52. // 筛选烟花
  53. Shoot
  54. (
  55. );
  56. // 发射烟花
  57. Show
  58. ( pMem
  59. );
  60. // 绽放烟花
  61. Wishing
  62. (
  63. );
  64. // 滚动字符
  65. Style
  66. ( st1
  67. );
  68. // 花样发射
  69. FlushBatchDraw(
  70. );
  71. // 显示前面的所有绘图操作
  72. }}

总结

好了,大家学废了嘛,这不是很难,效果还不错,大家可以尝试的去写一下,程序员的浪漫不止于此哦,哈哈哈,如果急切的想给心中的某个人看可以进群直接领取,当然啦,最好还是自己去写,去完成,网上的素材也是一大把,如何去优化,去改良就要看自己的本领了!嘻嘻,希望大家可以在这里得到自己想要的知识以及快乐吧,也希望大家可以给UP主一个关注,非常感谢大家了!!!

对了,说一件特别重要的事

我特意为此编了一个短视频,为了让大家知道程序员的浪漫我是豁出去了,希望大家可以给予我以及还在单身的程序员们一点小小的赞,谢谢大家了!!!

视频入口:

烟花再美也不及你https://www.bilibili.com/video/BV1XS4y1d7CQ/

后续UP主还会发布更多的项目源码以及学习资料,希望大家可以持续关注,有什么问题可以回帖留言,我尽量回答。想要C/C++学习资料以及其他项目的源码的可以加群【1083227756】了解。想要对程序员的未来发展有兴趣的也可加群闲聊。也可以关注微信公众号:【狐狸的编码时光】,希望和大家一起学习进步!!!
点击下方链接进群领取学习资料以及项目源码和素材

进群领取https://jq.qq.com/?_wv=1027&k=sttR3REF

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/123737.html

相关文章

  • (css/js)如何起个好名字

    摘要:就会给起名表示求和函数,渐渐地知道最好用英语给变量或者是函数名起名字,尽管有时候英语不好,那就翻翻有道吧。所以有一段时间的命名是很长的两三个单词的驼峰法命名。 什么鬼,又不知道怎么命名class了直接进入正文 记得大一学C语言的时候,那个时候根本没把这当回事吧。所谓的混沌阶段变量名,函数名,随意吧,那个时候写简单地c程序,就好像写着玩,就算复杂点得也不过一二百行,所以变量名什么的,可能...

    Rainie 评论0 收藏0
  • 编程界也有修仙秘籍?程序员码字3年终得《JavaScript 百炼成仙》

    摘要:百炼成仙走红该书于年月出版,作者杨逸飞是一名从事开发六年的程序员,写过诸多技术博客。作者在博客上对粉丝提出关于百炼成仙的问题进行了统一回复,该博文持续占据热榜第二,热度达。 刚接触编程的小伙伴,估计都想过把枯燥无聊的编程教材变成小说读的念头,这不,说曹操曹操就来了,真的有程序员用写修仙小说的...

    zzbo 评论0 收藏0
  • CSS transform-origin理解

    摘要:前言最近做的一个烟花动画,就是烟花散开的动画,在动画的实现过程中,主要在烟花旋转过程中卡住了,后来发现主要对属性理解不深,特地找了个例子来练习,加深了对属性的理解。 前言 最近做的一个烟花动画,就是烟花散开的动画,在动画的实现过程中,主要在烟花旋转过程中卡住了,后来发现主要对transform-origin属性理解不深,特地找了个例子来练习,加深了对属性的理解。 transform-...

    付永刚 评论0 收藏0
  • 程序员鱼皮 表情包网站项目学习

    摘要:我们可以来看看数据库这个字段就是判断我们的这条数据是否是有效的,表示这条数据是有效的,表示这条数据是无效的。 ? 技术栈 后端 Java 8开发框架:SpringB...

    Yangder 评论0 收藏0

发表评论

0条评论

Flink_China

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<