服务器之家:专注于服务器技术及软件下载分享
分类导航

PHP教程|ASP.NET教程|Java教程|ASP教程|编程技术|正则表达式|C/C++|IOS|C#|Swift|Android|VB|R语言|JavaScript|易语言|vb.net|

服务器之家 - 编程语言 - C/C++ - 非常漂亮的新年祝福!C语言实现漂亮的烟花效果

非常漂亮的新年祝福!C语言实现漂亮的烟花效果

2021-06-21 14:10C语言教程网 C/C++

非常漂亮的新年祝福!这篇文章主要介绍了C语言实现漂亮的烟花效果,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

本文实例为大家分享了C语言实现漂亮的烟花效果展示的具体代码,供大家参考,具体内容如下

程序名称:祝福烟花,祝福朋友
编译环境:VC++6.0 && easyx(立冬版) 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
#include <graphics.h>
#include <conio.h>
#include <iostream.h>
#include <math.h>
#include <time.h>
#include <stdio.h>
#include <Mmsystem.h> // 使用该计时器必须包含的文件
#pragma comment ( lib, "Winmm.lib" )
 
/***** 宏定义区 ******/
 
#define NUM 13 // 烟花种类数量宏定义
 
/***** 结构定义区 **********/
 
// 烟花结构
struct FIRE
{
 int r;  // 当前爆炸半径
 int max_r; // 爆炸中心距离边缘最大半径
 int x, y; // 爆炸中心在窗口的坐标
 int cen_x, cen_y; // 爆炸中心相对图片左上角的坐标
 int width, height; // 图片的宽高
 int xy[240][240]; // 储存图片像素点
 
 bool show; // 是否绽放
 bool draw; // 开始输出像素点
 DWORD t1, t2, dt; // 绽放速度
}Fire[NUM];
 
// 烟花弹结构
struct JET
{
 int x, y; // 喷射点坐标
 int hx, hy; // 最高点坐标------将赋值给 FIRE 里面的 x, y
 int height; // 烟花高度
 bool shoot; // 是否可以发射
 
 DWORD t1, t2, dt; // 发射速度
 IMAGE img[2]; // 储存花弹一亮一暗图片
 byte n : 1; // 图片下标
}Jet[NUM];
 
// happy birthday 艺术字结构
struct HAPPY // 储存 Happy Birthday 艺术字图片
{
 int x, y; // 每个字的图片的左上角坐标
 IMAGE img; // 储存单个字图片
 static int num; // 字母序号
}Happy[NUM];
int HAPPY::num = 0;
 
// For.2012の夭女 结构
struct WISH  // 滚动祝福图片结构
{
 int x, y; // 图片左上角坐标
 DWORD t1, t2, dt; // 图片运动时间间隔
 IMAGE img; // 储存图片
 int dxy; // 每次的移动量
 byte dir : 1; // 限制两个滚动方向
}Wish;
 
/**** 函数申明区 ****/
 
void Init ( int ); // 初始化烟花
void Load ( ); // 加载烟花图片
void Shoot ( ); // 发射烟花
void Chose ( DWORD& ); // 筛选烟花
void Wishing( ); // 滚动祝福
void Style ( DWORD& ); // 发射样式
void Show ( DWORD* ); // 绽放烟花
 
 
// 主函数
void main()
{
 initgraph( 1200, 800 );
 srand( time(0) );
 
 // 播放背景音乐
 mciSendString( "open ./fire/bk.mp3 alias bk", 0, 0, 0 );
 mciSendString( "play bk repeat", 0, 0, 0 );
 
 setfillstyle( 0 );
 setfont ( 36, 0, "楷体" );
 setcolor ( YELLOW );
 outtextxy ( 370, 100, "yy滺滺__出厂 .... ^_^" );
 
 DWORD t1 = timeGetTime(); // 筛选烟花计时
 DWORD st1 = timeGetTime(); // 播放花样计时
 DWORD* pMem = GetImageBuffer(); // 获取窗口显存指针
 
 for ( int i = 0; i < NUM; i++ ) // 初始化烟花
 {
 Init( i );
 }
 Load();  // 将烟花图片信息加载进相应结构中
 BeginBatchDraw();  // 开始批量绘图
 
 while ( !kbhit() )
 {
 Sleep( 10 );
 
 // 随机选择 4000 个像素点擦除
 for ( int clr = 0; clr < 1000; clr++ )
 {
 for ( int j = 0; j < 2; j++ )
 {
 int px1 = rand() % 1200;
 int py1 = rand() % 800;
 
 if ( py1 < 799 ) // 防止越界
  pMem[py1 * 1200 + px1] = pMem[py1 * 1200 + px1 + 1] = BLACK; // 对显存赋值擦出像素点
 }
 }
 Chose ( t1 ); // 筛选烟花
 Shoot ( ); // 发射烟花
 Show ( pMem ); // 绽放烟花
 Wishing ( ); // 滚动字符
 Style ( st1 ); // 花样发射
 FlushBatchDraw( ); // 显示前面的所有绘图操作
 }
}
 
 
// 初始化烟花参数
void Init( int i )
{
 // 分别为:烟花中心到图片边缘的最远距离、烟花中心到图片左上角的距离 (x、y) 两个分量
 int r[13] = { 120, 120, 155, 123, 130, 147, 138, 138, 130, 135, 140, 132, 155 };
 int x[13] = { 120, 120, 110, 117, 110, 93, 102, 102, 110, 105, 100, 108, 110 };
 int y[13] = { 120, 120, 85, 118, 120, 103, 105, 110, 110, 120, 120, 104, 85 };
 
 /**** 初始化烟花 *****/
 
 Fire[i].x = 0; // 烟花中心坐标
 Fire[i].y = 0;
 Fire[i].width = 240; // 图片宽
 Fire[i].height = 240; // 图片高
 Fire[i].max_r = r[i]; // 最大半径
 Fire[i].cen_x = x[i]; // 中心距左上角距离
 Fire[i].cen_y = y[i];
 Fire[i].show = false; // 是否绽放
 Fire[i].dt = 5; // 绽放时间间隔
 Fire[i].t1 = timeGetTime();
 Fire[i].r = 0; // 从 0 开始绽放
 
 /**** 初始化烟花弹 *****/
 
 Jet[i].x = -240; // 烟花弹左上角坐标
 Jet[i].y = -240;
 Jet[i].hx = -240; // 烟花弹发射最高点坐标
 Jet[i].hy = -240;
 Jet[i].height = 0; // 发射高度
 Jet[i].t1 = timeGetTime();
 Jet[i].dt = rand() % 10; // 发射速度时间间隔
 Jet[i].n = 0; // 烟花弹闪烁图片下标
 Jet[i].shoot = false; // 是否发射
}
 
 
// 加载图片
void Load()
{
/**** 储存烟花的像素点颜色 ****/
 IMAGE fm, gm;
 loadimage( &fm, "./fire/flower.jpg", 3120, 240 );
 
 for ( int i = 0; i < 13; i++ )
 {
 SetWorkingImage( &fm );
 getimage( &gm, i * 240, 0, 240, 240 );
 SetWorkingImage( &gm );
 
 for ( int a = 0; a < 240; a++ )
 for ( int b = 0; b < 240; b++ )
 Fire[i].xy[a][b] = getpixel( a, b );
 }
 
/**** 加载烟花弹 ************/
 IMAGE sm;
 loadimage( &sm, "./fire/shoot.jpg", 200, 50 );
 
 for ( i = 0; i < 13; i++ )
 {
 SetWorkingImage( &sm );
 int n = rand() % 5;
 
 getimage( &Jet[i].img[0], n * 20, 0, 20, 50 ); // 暗
 getimage( &Jet[i].img[1], (n + 5) * 20, 0, 20, 50 ); // 亮
 }
 
/***** 加载 Happy Birthday 图片 ********/
 IMAGE hm;
 loadimage( &hm, "./fire/happy.jpg", 689, 115 );
 SetWorkingImage( &hm );
 
 for ( i = 0; i < 13; i++ )
 {
 Happy[i].x = i * 90;
 Happy[i].y = rand() % 100 + 500;
 getimage( &Happy[i].img, i * 53, 0, 53, 115 );
 }
 
/***** 加载 For.2012の夭女 图片 *********/
 Wish.x = 0;
 Wish.y = 100;
 Wish.t1 = timeGetTime();
 Wish.dt = 46;
 Wish.dir = 0;
 Wish.dxy = rand() % 8 + 1;
 loadimage( &Wish.img, "./fire/yaojing.jpg", 490, 100 );
 putimage( Wish.x, Wish.y, &Wish.img, SRCINVERT );
 
 SetWorkingImage(); // 设置回绘图窗口
}
 
 
// 在一定范围内筛选可发射的烟花,并初始化发射参数,输出烟花弹到屏幕,播放声音
void Chose( DWORD& t1 )
{
 DWORD t2 = timeGetTime();
 
 if ( t2 - t1 > 100 )
 {
 int n = rand() % 20;
 
 if ( n < 13 && Jet[n].shoot == false && Fire[n].show == false )
 {
 /**** 重置烟花弹,预备发射 *****/
 Jet[n].x = rand() % 1200;
 Jet[n].y = rand() % 100 + 600;
 Jet[n].hx = Jet[n].x;
 Jet[n].hy = rand() % 400;
 Jet[n].height = Jet[n].y - Jet[n].hy;
 Jet[n].shoot = true;
 putimage( Jet[n].x, Jet[n].y, &Jet[n].img[Jet[n].n], SRCINVERT );
 
 /**** 播放每个烟花弹的声音 *****/
 char c1[50], c2[30], c3[30];
 sprintf( c1, "open ./fire/shoot.mp3 alias s%d", n );
 sprintf( c2, "play s%d", n );
 sprintf( c3, "close n%d", n );
 
 mciSendString( c3, 0, 0, 0 );
 mciSendString( c1, 0, 0, 0 );
 mciSendString( c2, 0, 0, 0 );
 }
 t1 = t2;
 }
}
 
 
// 扫描烟花弹并发射
void Shoot()
{
 for ( int i = 0; i < 13; i++ )
 {
 Jet[i].t2 = timeGetTime();
 
 if ( Jet[i].t2 - Jet[i].t1 > Jet[i].dt && Jet[i].shoot == true )
 {
 /**** 烟花弹的上升 *****/
 putimage( Jet[i].x, Jet[i].y, &Jet[i].img[Jet[i].n], SRCINVERT );
 
 if ( Jet[i].y > Jet[i].hy )
 {
 Jet[i].n++;
 Jet[i].y -= 5;
 }
 
 putimage( Jet[i].x, Jet[i].y, &Jet[i].img[Jet[i].n], SRCINVERT );
 
 /**** 上升到高度的 3 / 4,减速 *****/
 if ( (Jet[i].y - Jet[i].hy) * 4 < Jet[i].height )
 Jet[i].dt = rand() % 4 + 10 ;
 
 /**** 上升到最大高度 *****/
 if ( Jet[i].y <= Jet[i].hy )
 {
 // 播放爆炸声
 char c1[50], c2[30], c3[30];
 sprintf( c1, "open ./fire/bomb.wav alias n%d", i );
 sprintf( c2, "play n%d", i );
 sprintf( c3, "close s%d", i );
 
 mciSendString( c3, 0, 0, 0 );
 mciSendString( c1, 0, 0, 0 );
 mciSendString( c2, 0, 0, 0 );
 
 putimage( Jet[i].x, Jet[i].y, &Jet[i].img[Jet[i].n], SRCINVERT ); // 擦掉烟花弹
 Fire[i].x = Jet[i].hx + 10;   // 在烟花弹中间爆炸
 Fire[i].y = Jet[i].hy;   // 在最高点绽放
 Fire[i].show = true// 开始绽放
 Jet[i].shoot = false// 停止发射
 
 // 显示对应字母
 putimage( Happy[HAPPY::num].x, Happy[HAPPY::num].y, &Happy[HAPPY::num].img, SRCINVERT );
 HAPPY::num++;
 
 if ( HAPPY::num > 12 )
  HAPPY::num = 0;
 }
 Jet[i].t1 = Jet[i].t2;
 }
 }
}
 
 
// 制作水平、竖直移动的图片
void Wishing()
{
 Wish.t2 = timeGetTime();
 
 if ( Wish.t2 - Wish.t1 > Wish.dt )
 {
 /**** 图片的移动 *****/
 putimage( Wish.x, Wish.y, &Wish.img, SRCINVERT );
 
 if ( Wish.dir == 0 )
 Wish.x += Wish.dxy;
 else
 Wish.y -= Wish.dxy;
 
 putimage( Wish.x, Wish.y, &Wish.img, SRCINVERT );
 
 /**** 图片出界后 *****/
 if ( Wish.x > 1200 || Wish.y < 0 )
 {
 Wish.dir = rand() % 2; // 获取随机方向
 
 if ( Wish.dir == 0 ) // 如果左右运动
 {
 Wish.y = rand() % 700; // 初始位置
 Wish.x = -490;
 Wish.dxy = rand() % 7 + 1; // 随机运动分量
 }
 else  // 上下运动
 {
 Wish.dxy = rand() % 7 + 1;
 Wish.x = rand() % 700;
 Wish.y = 800;
 }
 }
 Wish.t1 = Wish.t2;
 }
}
 
 
// 显示花样
void Style( DWORD& st1 )
{
 DWORD st2 = timeGetTime();
 
 if ( st2 - st1 > 266000 ) // 一首歌的时间
 {
 // 心形坐标
 int x[13] = { 60, 75, 91, 100, 95, 75, 60, 45, 25, 15, 25, 41, 60 };
 int y[13] = { 65, 53, 40, 22, 5, 4, 20, 4, 5, 22, 40, 53, 65 };
 for ( int i = 0; i < NUM; i++ )
 {
 cleardevice();
 /**** 规律分布烟花弹 ***/
 Jet[i].x = x[i] * 10;
 Jet[i].y = ( y[i] + 75 ) * 10;
 Jet[i].hx = Jet[i].x;
 Jet[i].hy = y[i] * 10;
 Jet[i].height = Jet[i].y - Jet[i].hy;
 Jet[i].shoot = true;
 Jet[i].dt = 7;
 putimage( Jet[i].x, Jet[i].y, &Jet[i].img[Jet[i].n], SRCINVERT ); // 显示烟花弹
 
 /**** 设置烟花参数 ***/
 Fire[i].x = Jet[i].x + 10;
 Fire[i].y = Jet[i].hy;
 Fire[i].show = false;
 Fire[i].r = 0;
 
 /**** 播放发射声音 ***/
 char c1[50], c2[30], c3[30];
 sprintf( c1, "open ./fire/shoot.mp3 alias s%d", i );
 sprintf( c2, "play s%d", i );
 sprintf( c3, "close n%d", i );
 
 mciSendString( c3, 0, 0, 0 );
 mciSendString( c1, 0, 0, 0 );
 mciSendString( c2, 0, 0, 0 );
 }
 st1 = st2;
 }
}
 
 
// 绽放烟花
void Show( DWORD* pMem )
{
 // 烟花个阶段绽放时间间隔,制作变速绽放效果
 int drt[16] = { 5, 5, 5, 5, 5, 6, 25, 25, 25, 25, 55, 55, 55, 55, 55 };
 
 for ( int i = 0; i < NUM; i++ )
 {
 Fire[i].t2 = timeGetTime();
 
 // 增加爆炸半径,绽放烟花,增加时间间隔做变速效果
 if ( Fire[i].t2 - Fire[i].t1 > Fire[i].dt && Fire[i].show == true )
 {
 if ( Fire[i].r < Fire[i].max_r )
 {
 Fire[i].r++;
 Fire[i].dt = drt[Fire[i].r / 10];
 Fire[i].draw = true;
 }
 
 if ( Fire[i].r >= Fire[i].max_r - 1 )
 {
 Fire[i].draw = false;
 Init( i );
 }
 Fire[i].t1 = Fire[i].t2;
 }
 
 // 如果该号炮花可爆炸,根据当前爆炸半径画烟花,颜色值接近黑色的不输出。
 if ( Fire[i].draw )
 {
 for ( double a = 0; a <= 6.28; a += 0.01 )
 {
 int x1 = (int)( Fire[i].cen_x + Fire[i].r * cos(a) ); // 相对于图片左上角的坐标
 int y1 = (int)( Fire[i].cen_y - Fire[i].r * sin(a) );
 
 if ( x1 > 0 && x1 < Fire[i].width && y1 > 0 && y1 < Fire[i].height ) // 只输出图片内的像素点
 {
  int b = Fire[i].xy[x1][y1] & 0xff;
  int g = ( Fire[i].xy[x1][y1] >> 8 ) & 0xff;
  int r = ( Fire[i].xy[x1][y1] >> 16 );
 
  // 烟花像素点在窗口上的坐标
  int xx = (int)( Fire[i].x + Fire[i].r * cos(a) );
  int yy = (int)( Fire[i].y - Fire[i].r * sin(a) );
 
  // 较暗的像素点不输出、防止越界
  if ( r > 0x20 && g > 0x20 && b > 0x20 && xx > 0 && xx < 1200 && yy > 0 && yy < 800 )
  pMem[yy * 1200 + xx] = BGR( Fire[i].xy[x1][y1] ); // 显存操作绘制烟花
 }
 }
 Fire[i].draw = false;
 }
 }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持服务器之家。

延伸 · 阅读

精彩推荐