• 用VS软件开发“浪漫烟花“<笔记摘录>


    此处主要讲:如何开发一个连续的烟花弹上升并进行烟花爆炸的程序.

    第一步自然是创建窗口,设置窗口宽度为1200,高度为800(#include )

    	initgraph(1200, 800);//创建窗口,宽度1200,高度800

     第二步我们需要为这个窗口添加背景音乐,这里我们添加了一首"周杰伦的告白气球.mp3",打开并且播放.因为我们并不需要暂停或者关闭,所以便注释掉对应的程序.

    注意,添加音乐的时候要记住添加头文件

    1. #include//媒体头文件
    2. #pragma comment(lib,"winmm.lib")//媒体库文件
    1. mciSendString("open 告白气球.mp3",0,0,0);
    2. mciSendString("play 告白气球.mp3", 0, 0, 0);
    3. //mciSendString("pause 周杰伦 - 告白气球(Live).mp3", 0, 0, 0);
    4. //mciSendString("close 周杰伦 - 告白气球(Live).mp3", 0, 0, 0);

    第三步我们开始在窗口上面添加文本,记不记得学习C++的第一个程序,"hello,world!"

    这里类同,只不过是讲对应的文本输入到窗口对应的位置.程序如下:

    1. settextcolor(YELLOW);//设置字体的颜色
    2. settextstyle(25,0,"微软雅黑");//设置字体的字号
    3. //outtextxy(320,240,"赵哥真帅");//在创建的窗口,(320,240)的位置的输入赵哥真帅
    4. outtextxy(400, 200, "XXXXXXXXXX");
    5. outtextxy(400, 250, "XXXXXXXXXX");
    6. outtextxy(400, 300, "XXXXXXXXXX");
    7. outtextxy(400, 350, "XXXXXXXXXX");
    8. outtextxy(400, 400, "XXXXXXXXXX");
    9. outtextxy(600, 450, "------小子");

    然后在显示的时候,我们可以给这段文本延时5s

    	Sleep(5000);

    文本结束后,就开始进入烟花弹和烟花的爆炸现场.

    第四步,定义烟花弹和烟花

    1. //烟花弹
    2. struct Jet//烟花弹属性
    3. {
    4. int x, y;//当前坐标
    5. int hx, hy;//最高点的坐标
    6. unsigned long t1, t2, dt;//时间来控制速度
    7. IMAGE img;//保存烟花弹的图片
    8. bool isshoot;//烟花弹是否属于正在上升的状态
    9. }jet;
    10. //烟花
    11. struct Fire//从中心往外面进行拓展
    12. {
    13. int r;//当前半径
    14. int maxr;//最大半径
    15. int x, y;//中心点的左边//窗口
    16. int cx, cy;//中心点左边,坐标系不同//图片
    17. int xy[240][240]; //保存图片当中每一个像素点
    18. bool isboom;//是否开始爆炸
    19. bool isdram;//是否开始显示
    20. unsigned long t1, t2, dt; //爆炸的速度
    21. }fire;

    简单解释:烟花弹属性包括了他的当前坐标和最高坐标,因为烟花弹是垂直向上的,所以速度,采用时间t1,t2和dt来进行描述,IMAGE用来保存烟花弹的图片.并定义一个布尔类型isshoot,判断烟花弹是否处于上升状态

    关于IMAGE函数的有关解释,可以参考:EasyX 文档 - IMAGE

    烟花的基本属性在于:要明白烟花爆炸是从一个中心点,向外速度越来越慢地拓展开来的,因此我们定义烟花的当前半径和最大半径,烟花爆炸的点相对于窗口的坐标,和烟花爆炸上面点相对于图片的坐标,及其设定一个二维数组用于保存图片当中每一个像素点.最后定义两个布尔类型,判断烟花是否爆炸和显示.

    第五步 初始化烟花弹和烟花

    1. //初始化烟花弹
    2. void startjet()
    3. {
    4. jet.x = rand() % (1200 - 20);
    5. jet.y = 750;
    6. jet.hx = jet.x;//垂直上升
    7. jet.hy = rand() % 400;//0-399爆炸
    8. jet.t1 = GetTickCount(); //获取系统时间
    9. jet.dt = 10;//dt 10ms
    10. jet.isshoot = true;
    11. loadimage(&jet.img, "jet.jpg", 20, 50);
    12. putimage(jet.x, jet.y, &jet.img, SRCINVERT);
    13. }
    14. //初始化烟花
    15. void startfire() {
    16. fire.r=0;//当前半径
    17. fire.maxr=120;//最大半径
    18. fire.x=0, fire.y=0;//中心点的左边//窗口//等于烟花弹最高点的坐标
    19. fire.cx=120, fire.cy=120;//中心点左边,坐标系不同//图片
    20. fire.isboom=false;//是否开始爆炸
    21. fire.isdram=false;//是否开始显示
    22. fire.t1 = GetTickCount();
    23. fire.dt = 5; //爆炸的速度
    24. fire.xy[239][239]; //保存图片当中每一个像素点
    25. IMAGE fimg;
    26. loadimage(&fimg, "flower.jpg", 240,240);
    27. SetWorkingImage(&fimg);//获取fimg地址的图片
    28. for (int a = 0; a < 240; a++)//把图片的所有像素点定义在一个数组当中
    29. {
    30. for (int b = 0; b < 240; b++)
    31. {
    32. fire.xy[a][b]=getpixel(a, b);//窗口获取(a,b)像素点
    33. }
    34. }
    35. SetWorkingImage();//放开对应的图片
    36. }

    其次对应上面定义的烟花和烟花弹的结构,对其进行初始状态定义.此处要注意,烟花和烟花弹图片显示的方式不同,烟花弹是作为一个整体,垂直上升的,而烟花是从一个点,爆炸开来的,显示的是每一个范围的像素图.

    第六步 发射烟花弹

    1. void shootjet()
    2. {
    3. //biubiubiu
    4. jet.t2 = GetTickCount();//t2
    5. if (jet.t2 - jet.t1 > jet.dt && jet.isshoot == true)
    6. {
    7. putimage(jet.x, jet.y, &jet.img, SRCINVERT);
    8. if (jet.y > jet.hy)//停止在这个烟花的最高位置附近,然后要准备进行爆炸
    9. jet.y -= 5;
    10. putimage(jet.x, jet.y, &jet.img, SRCINVERT);//y-5之后再演示烟花弹下一个位置
    11. if (jet.y <= jet.hy)//到达最高点了
    12. {
    13. //擦除烟花弹
    14. putimage(jet.x, jet.y, &jet.img, SRCINVERT);
    15. fire.isboom = true;//开始爆炸烟花
    16. jet.isshoot = false;
    17. fire.x = jet.x;
    18. fire.y = jet.y+10;
    19. //showfire(pMem);
    20. }
    21. if (jet.isshoot == false)
    22. {
    23. //再次初始化烟花弹
    24. startjet();
    25. //fire.isdram = false;
    26. }
    27. jet.t1 = jet.t2;
    28. }
    29. }

    当到达最高点的时候,要将烟花弹擦除,并且记录下此时的坐标,将其赋给烟花相对于窗口的中心点坐标,开始爆炸烟花,如果烟花弹的上升状态转换为false了,那么便再设定一个新的发射烟花弹函数,也就是回溯的调用,最后要记住循环完,将t2的数值赋值给t1;确保能够一直循环运行下去.

    运行到这里,就可以看到一个又一个烟花弹上升并擦除的界面了.

    第七步  烟花爆炸

    先设定一个时间数组,用来控制自内向外爆炸的时间长度,越往外面速度越慢

    1. //爆炸烟花
    2. void showfire(DWORD *pMem)
    3. {
    4. //dt数组
    5. //爆炸速度:在半径小的时候爆炸特别快
    6. //半径越大,爆炸越来越慢
    7. int drt[12] = { 5,5,5,6,6,15,25,25,25,55,55,65 };//12个为什么?120%10
    8. fire.t2 = GetTickCount();
    9. if (fire.t2 - fire.t1 > fire.dt && fire.isboom == true)
    10. {
    11. if (fire.r < fire.maxr)
    12. {
    13. fire.r++;//半径不断地变大
    14. fire.dt = drt[fire.r / 10];
    15. fire.isdram = true;
    16. }
    17. if (fire.r >= fire.maxr - 1)
    18. {
    19. fire.isdram = false;
    20. fire.isboom = false;
    21. fire.dt = 5;
    22. fire.t1 = GetTickCount();
    23. fire.r = 0;
    24. }
    25. fire.t1 = fire.t2;
    26. }
    27. if (fire.isdram == true)//可以开始绘制
    28. {
    29. //6282Π
    30. for (double a = 0; a <= 6.28; a += 0.01)
    31. {
    32. //相对于图片左上角的坐标
    33. int x1 = fire.cx + fire.r * cos(a);
    34. int y1 = fire.cy - fire.r * sin(a);
    35. //x1 y1 628个来自于图片的像素点坐标<240
    36. fire.xy[x1][y1];//存储上面的像素点坐标
    37. if (x1 > 0 && x1 < 240 && y1>0 && y1 < 240 ) //图片像素是240*240,所以只输出像素内的点
    38. {
    39. int b = fire.xy[x1][y1] & 0xff;
    40. int g = (fire.xy[x1][y1] >> 8) & 0xff;
    41. int r = (fire.xy[x1][y1] >> 16);
    42. //烟花像素点在窗口上的坐标
    43. int xx = fire.x + fire.r * cos(a);
    44. int yy = fire.y - fire.r * sin(a);
    45. // 较暗的像素点不输出、防止越界
    46. if (r > 0x20 && g > 0x20 && b > 0x20 && xx > 0 && xx < 1200 && yy > 0 && yy < 800)
    47. pMem[yy * 1200 + xx] = BGR(fire.xy[x1][y1]); // 显存操作绘制烟花
    48. }
    49. }
    50. }
    51. fire.isdram = false;
    52. }

    如果fire.isdram==true的时候,也就是可以开始绘制爆炸烟花了.循环当中采用了数学函数,可以定义到每一个像素点的坐标,然后再根据前面烟花弹停止上升的最高点,来确定烟花像素点在窗口上的坐标.设定一个条件判断,如果像素点较暗,则不输出,其他像素点输出.

    最后在每一次循环结束的时候要将isdram设置成false

    最后,运行主函数

    1. int main()
    2. {
    3. srand(time(0));
    4. initgraph(1200, 800);//创建窗口,宽度1200,高度800
    5. mciSendString("open 告白气球.mp3",0,0,0);
    6. mciSendString("play 告白气球.mp3", 0, 0, 0);
    7. //mciSendString("pause 周杰伦 - 告白气球(Live).mp3", 0, 0, 0);
    8. //mciSendString("close 周杰伦 - 告白气球(Live).mp3", 0, 0, 0);
    9. //mci send string
    10. settextcolor(YELLOW);//设置字体的颜色
    11. settextstyle(25,0,"微软雅黑");//设置字体的字号
    12. //outtextxy(320,240,"赵哥真帅");//在创建的窗口,(320,240)的位置的输入赵哥真帅
    13. outtextxy(400, 200, "XXXXXXXXXX");
    14. outtextxy(400, 250, "XXXXXXXXXX");
    15. outtextxy(400, 300, "XXXXXXXXXX");
    16. outtextxy(400, 350, "XXXXXXXXXX");
    17. outtextxy(400, 400, "XXXXXXXXXX");
    18. outtextxy(600, 450, "------小子");
    19. int uuu=getchar();//按回车键继续
    20. Sleep(5000);
    21. //DWORD st1 = timeGetTime(); // 播放花样计时
    22. DWORD* pMem = GetImageBuffer(); // 获取窗口显存指针
    23. //初始化烟花弹
    24. startjet();
    25. //初始化烟花
    26. startfire();
    27. while (1)
    28. {
    29. Sleep(1);
    30. // 随机选择 4000 个像素点擦除
    31. for (int clr = 0; clr < 2000; clr++)
    32. {
    33. for (int j = 0; j < 2; j++)
    34. {
    35. int px1 = rand() % 1200;
    36. int py1 = rand() % 800;
    37. if (py1 < 799) // 防止越界
    38. pMem[py1 * 1200 + px1] = pMem[py1 * 1200 + px1 + 1] = BLACK; // 对显存赋值擦出像素点
    39. //Style(st1);
    40. }
    41. shootjet();
    42. showfire(pMem);
    43. }
    44. //Style(st1);
    45. FlushBatchDraw(); // 显示前面的所有绘图操作
    46. }
    47. while (1);
    48. return 0;
    49. }

    总代码和相关素材如下:

    1. #pragma warning(disable:4996)//忽略4996错误提示
    2. #pragma comment(linker,"/entry:mainCRTStartup /subsystem:windows")
    3. #include <graphics.h>
    4. #include <stdio.h>
    5. #include <conio.h>
    6. #include <easyx.h>//图形界面库
    7. #include<time.h>
    8. #include<math.h>
    9. #include<string.h>
    10. //歌曲需要的头文件
    11. #include<mmsystem.h>//媒体头文件
    12. #pragma comment(lib,"winmm.lib")//媒体库文件
    13. //烟花弹
    14. struct Jet//烟花弹属性
    15. {
    16. int x, y;//当前坐标
    17. int hx, hy;//最高点的坐标
    18. unsigned long t1, t2, dt;//时间来控制速度
    19. IMAGE img;//保存烟花弹的图片
    20. bool isshoot;//烟花弹是否属于正在上升的状态
    21. }jet;
    22. //烟花
    23. struct Fire//从中心往外面进行拓展
    24. {
    25. int r;//当前半径
    26. int maxr;//最大半径
    27. int x, y;//中心点的左边//窗口
    28. int cx, cy;//中心点左边,坐标系不同//图片
    29. int xy[240][240]; //保存图片当中每一个像素点
    30. bool isboom;//是否开始爆炸
    31. bool isdram;//是否开始显示
    32. unsigned long t1, t2, dt; //爆炸的速度
    33. }fire;
    34. //初始化烟花弹
    35. void startjet()
    36. {
    37. jet.x = rand() % (1200 - 20);
    38. jet.y = 750;
    39. jet.hx = jet.x;//垂直上升
    40. jet.hy = rand() % 400;//0-399爆炸
    41. jet.t1 = GetTickCount(); //获取系统时间
    42. jet.dt = 10;//dt 10ms
    43. jet.isshoot = true;
    44. loadimage(&jet.img, "jet.jpg", 20, 50);
    45. putimage(jet.x, jet.y, &jet.img, SRCINVERT);
    46. }
    47. //初始化烟花
    48. void startfire() {
    49. fire.r=0;//当前半径
    50. fire.maxr=120;//最大半径
    51. fire.x=0, fire.y=0;//中心点的左边//窗口//等于烟花弹最高点的坐标
    52. fire.cx=120, fire.cy=120;//中心点左边,坐标系不同//图片
    53. fire.isboom=false;//是否开始爆炸
    54. fire.isdram=false;//是否开始显示
    55. fire.t1 = GetTickCount();
    56. fire.dt = 5; //爆炸的速度
    57. fire.xy[239][239]; //保存图片当中每一个像素点
    58. IMAGE fimg;
    59. loadimage(&fimg, "flower.jpg", 240,240);
    60. SetWorkingImage(&fimg);//获取fimg地址的图片
    61. for (int a = 0; a < 240; a++)//把图片的所有像素点定义在一个数组当中
    62. {
    63. for (int b = 0; b < 240; b++)
    64. {
    65. fire.xy[a][b]=getpixel(a, b);//窗口获取(a,b)像素点
    66. }
    67. }
    68. SetWorkingImage();//放开对应的图片
    69. }
    70. //发射烟花弹
    71. void shootjet()
    72. {
    73. //biubiubiu
    74. jet.t2 = GetTickCount();//t2
    75. if (jet.t2 - jet.t1 > jet.dt && jet.isshoot == true)
    76. {
    77. putimage(jet.x, jet.y, &jet.img, SRCINVERT);
    78. if (jet.y > jet.hy)//停止在这个烟花的最高位置附近,然后要准备进行爆炸
    79. jet.y -= 5;
    80. putimage(jet.x, jet.y, &jet.img, SRCINVERT);//y-5之后再演示烟花弹下一个位置
    81. if (jet.y <= jet.hy)//到达最高点了
    82. {
    83. //擦除烟花弹
    84. putimage(jet.x, jet.y, &jet.img, SRCINVERT);
    85. fire.isboom = true;//开始爆炸烟花
    86. jet.isshoot = false;
    87. fire.x = jet.x;
    88. fire.y = jet.y+10;
    89. //showfire(pMem);
    90. }
    91. if (jet.isshoot == false)
    92. {
    93. //再次初始化烟花弹
    94. startjet();
    95. //fire.isdram = false;
    96. }
    97. jet.t1 = jet.t2;
    98. }
    99. }
    100. //爆炸烟花
    101. void showfire(DWORD *pMem)
    102. {
    103. //dt数组
    104. //爆炸速度:在半径小的时候爆炸特别快
    105. //半径越大,爆炸越来越慢
    106. int drt[12] = { 5,5,5,6,6,15,25,25,25,55,55,65 };//12个为什么?120%10
    107. fire.t2 = GetTickCount();
    108. if (fire.t2 - fire.t1 > fire.dt && fire.isboom == true)
    109. {
    110. if (fire.r < fire.maxr)
    111. {
    112. fire.r++;//半径不断地变大
    113. fire.dt = drt[fire.r / 10];
    114. fire.isdram = true;
    115. }
    116. if (fire.r >= fire.maxr - 1)
    117. {
    118. fire.isdram = false;
    119. fire.isboom = false;
    120. fire.dt = 5;
    121. fire.t1 = GetTickCount();
    122. fire.r = 0;
    123. }
    124. fire.t1 = fire.t2;
    125. }
    126. if (fire.isdram == true)//可以开始绘制
    127. {
    128. //6282Π
    129. for (double a = 0; a <= 6.28; a += 0.01)
    130. {
    131. //相对于图片左上角的坐标
    132. int x1 = fire.cx + fire.r * cos(a);
    133. int y1 = fire.cy - fire.r * sin(a);
    134. //x1 y1 628个来自于图片的像素点坐标<240
    135. fire.xy[x1][y1];//存储上面的像素点坐标
    136. if (x1 > 0 && x1 < 240 && y1>0 && y1 < 240 ) //图片像素是240*240,所以只输出像素内的点
    137. {
    138. int b = fire.xy[x1][y1] & 0xff;
    139. int g = (fire.xy[x1][y1] >> 8) & 0xff;
    140. int r = (fire.xy[x1][y1] >> 16);
    141. //烟花像素点在窗口上的坐标
    142. int xx = fire.x + fire.r * cos(a);
    143. int yy = fire.y - fire.r * sin(a);
    144. // 较暗的像素点不输出、防止越界
    145. if (r > 0x20 && g > 0x20 && b > 0x20 && xx > 0 && xx < 1200 && yy > 0 && yy < 800)
    146. pMem[yy * 1200 + xx] = BGR(fire.xy[x1][y1]); // 显存操作绘制烟花
    147. }
    148. }
    149. }
    150. fire.isdram = false;
    151. }
    152. // 显示花样 //本程序不显示
    153. void Style(DWORD& st1)
    154. {
    155. DWORD st2 = timeGetTime();
    156. if (st2 - st1 > 2000) // 一首歌的时间
    157. {
    158. // 心形坐标
    159. int x[13] = { 60, 75, 91, 100, 95, 75, 60, 45, 25, 15, 25, 41, 60 };
    160. int y[13] = { 65, 53, 40, 22, 5, 4, 20, 4, 5, 22, 40, 53, 65 };
    161. for (int i = 0; i < 13; i++)
    162. {
    163. //cleardevice();
    164. /**** 规律分布烟花弹 ***/
    165. jet.x = x[i] * 10;
    166. jet.y = (y[i] + 75) * 10;
    167. jet.hx = jet.x;
    168. jet.hy = y[i] * 10;
    169. jet.isshoot = true;
    170. jet.dt = 5;
    171. putimage(jet.x, jet.y, &jet.img, SRCINVERT); // 显示烟花弹
    172. /**** 设置烟花参数 ***/
    173. fire.x = jet.x + 10;
    174. fire.y = jet.hy;
    175. //fire.isdram = false;
    176. //fire.r = 0;
    177. /**** 播放发射声音 ***/
    178. /*char c1[50], c2[30], c3[30];
    179. sprintf(c1, "open ./fire/shoot.mp3 alias s%d", i);
    180. sprintf(c2, "play s%d", i);
    181. sprintf(c3, "close n%d", i);
    182. mciSendString(c3, 0, 0, 0);
    183. mciSendString(c1, 0, 0, 0);
    184. mciSendString(c2, 0, 0, 0);*/
    185. }
    186. st1 = st2;
    187. }
    188. }
    189. int main()
    190. {
    191. srand(time(0));
    192. initgraph(1200, 800);//创建窗口,宽度1200,高度800
    193. mciSendString("open 告白气球.mp3",0,0,0);
    194. mciSendString("play 告白气球.mp3", 0, 0, 0);
    195. //mciSendString("pause 周杰伦 - 告白气球(Live).mp3", 0, 0, 0);
    196. //mciSendString("close 周杰伦 - 告白气球(Live).mp3", 0, 0, 0);
    197. //mci send string
    198. settextcolor(YELLOW);//设置字体的颜色
    199. settextstyle(25,0,"微软雅黑");//设置字体的字号
    200. //outtextxy(320,240,"赵哥真帅");//在创建的窗口,(320,240)的位置的输入赵哥真帅
    201. outtextxy(400, 200, "XXXXXXXXXX");
    202. outtextxy(400, 250, "XXXXXXXXXX");
    203. outtextxy(400, 300, "XXXXXXXXXX");
    204. outtextxy(400, 350, "XXXXXXXXXX");
    205. outtextxy(400, 400, "XXXXXXXXXX");
    206. outtextxy(600, 450, "------小子");
    207. int uuu=getchar();//按回车键继续
    208. Sleep(5000);
    209. //DWORD st1 = timeGetTime(); // 播放花样计时
    210. DWORD* pMem = GetImageBuffer(); // 获取窗口显存指针
    211. //初始化烟花弹
    212. startjet();
    213. //初始化烟花
    214. startfire();
    215. while (1)
    216. {
    217. Sleep(1);
    218. // 随机选择 4000 个像素点擦除
    219. for (int clr = 0; clr < 2000; clr++)
    220. {
    221. for (int j = 0; j < 2; j++)
    222. {
    223. int px1 = rand() % 1200;
    224. int py1 = rand() % 800;
    225. if (py1 < 799) // 防止越界
    226. pMem[py1 * 1200 + px1] = pMem[py1 * 1200 + px1 + 1] = BLACK; // 对显存赋值擦出像素点
    227. //Style(st1);
    228. }
    229. shootjet();
    230. showfire(pMem);
    231. }
    232. //Style(st1);
    233. FlushBatchDraw(); // 显示前面的所有绘图操作
    234. }
    235. while (1);
    236. return 0;
    237. }

  • 相关阅读:
    WPF 依赖属性原理、 附加属性
    sql 脚本 WITH 作用
    事务+事务并发+事务隔离级别【Interview Question】
    DevTools failed to parse SourceMap 警告解决方法
    【Qt控件之微调框、进度条】QSpinBox、QDoubleSpinBox、QDial、QProgressBar介绍及使用
    python的str.find()用法及实例
    异地局域网对接:异地组网原理与实操
    期货开户交易要控制自己的消极情绪
    【Python】利用matplotlib在Pycharm中显示本地图片
    JAVA毕业设计Vue网上书籍购买商城登录计算机源码+lw文档+系统+调试部署+数据库
  • 原文地址:https://blog.csdn.net/Lukegood/article/details/128115946