嘿,朋友们!今天来给大家讲讲一段挺有意思的C++代码呀,这段代码主要是用来实现一个烟花效果展示的程序哦,下面咱们一点点来看哈。
效果
1. 开头包含的那些头文件
#include <graphics.h>
#include <conio.h>
#include <math.h>
#include <time.h>
#include <stdio.h>
#include<string>
#include <mmsystem.h>
#pragma comment ( lib, "Winmm.lib" )
这里面包含了好多头文件呢。像 <graphics.h>
是和图形绘制相关的,能帮咱们在屏幕上画出各种图形呀;<conio.h>
可以用来处理控制台的输入输出相关操作;<math.h>
就提供了像三角函数这些数学运算的功能;<time.h>
能获取时间相关信息;<stdio.h>
用于标准输入输出操作;<string>
是处理字符串的;而 <mmsystem.h>
以及后面关联的 Winmm.lib
呢,是和多媒体操作有关的,比如播放声音之类的操作都会用到哦。
2. 烟花结构体定义
struct Fire
{
int r; // 当前爆炸半径
int max_r; // 爆炸中心距离边缘最大半径
int x, y; // 爆炸中心在窗口的坐标
int cent2LeftTopX, cent2LeftTopY; // 爆炸中心相对图片左上角的坐标
int width, height; // 图片的宽高
int pix[240][240]; // 储存图片像素点
bool show; // 是否绽放
bool draw; // 开始输出像素点
DWORD t1, t2, dt; // 绽放速度
}fires[NUM];
- 解析:
r
:当前烟花的爆炸半径,随着时间逐渐增大。max_r
:烟花爆炸的最大半径,达到该值后烟花消失。x, y
:烟花爆炸的中心点在窗口中的坐标。cent2LeftTopX, cent2LeftTopY
:爆炸中心相对于图片左上角的坐标,用于计算像素点的位置。width, height
:烟花的图片宽度和高度。pix[240][240]
:存储烟花图片的像素点颜色数据。show
:表示烟花是否正在绽放。draw
:表示是否开始绘制烟花的像素点。t1, t2, dt
:用于控制烟花绽放的时间间隔。
3. 烟花弹结构体定义
struct Bullet
{
int x, y; // 烟花弹的当前坐标
int topX, topY; // 最高点坐标------将赋值给 FIRE 里面的 x, y
int height; // 烟花高度
bool shoot; // 是否可以发射
DWORD t1, t2, dt; // 发射速度
IMAGE img[2]; // 储存花弹一亮一暗图片
unsigned char n : 1; // 图片下标 n++
}bullets[NUM];
- 解析:
x, y
:烟花弹的当前坐标。topX, topY
:烟花弹的最高点坐标,烟花弹升空到该点后爆炸。height
:烟花弹的发射高度。shoot
:表示烟花弹是否可以发射。t1, t2, dt
:用于控制烟花弹发射的时间间隔。img[2]
:存储烟花弹的两张图片(一亮一暗),用于实现闪烁效果。n
:用于切换烟花弹的图片,实现闪烁效果。
4. 初始化烟花和烟花弹
void initFire(int i)
{
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 };
/**** 初始化烟花 *****/
fires[i].x = 0;
fires[i].y = 0;
fires[i].width = 240;
fires[i].height = 240;
fires[i].max_r = r[i];
fires[i].cent2LeftTopX = x[i];
fires[i].cent2LeftTopY = y[i];
fires[i].show = false;
fires[i].dt = 5;
fires[i].t1 = timeGetTime();
fires[i].r = 0;
fires[i].draw = false;
/**** 初始化烟花弹 *****/
bullets[i].t1 = timeGetTime();
bullets[i].dt = rand() % 10;
bullets[i].n = 0;
bullets[i].shoot = false;
}
- 解析:
- 该函数用于初始化指定索引的烟花和烟花弹的状态。
r[]
,x[]
,y[]
:分别存储了烟花的最大半径、爆炸中心相对于图片左上角的坐标。fires[i]
:初始化烟花的各个属性,包括坐标、宽高、最大半径、时间间隔等。bullets[i]
:初始化烟花弹的各个属性,包括时间间隔、图片下标、发射状态等。
5. 加载烟花图片
void loadFireImages()
{
IMAGE fm, gm;
loadimage(&fm, "fire/flower.jpg");
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++)
fires[i].pix[a][b] = getpixel(a, b);
}
IMAGE sm;
loadimage(&sm, "fire/shoot.jpg");
for (int i = 0; i < 13; i++)
{
SetWorkingImage(&sm);
int n = rand() % 5;
getimage(&bullets[i].img[0], n * 20, 0, 20, 50);
getimage(&bullets[i].img[1], (n + 5) * 20, 0, 20, 50);
}
SetWorkingImage();
}
- 解析:
- 该函数加载烟花的图片数据,并将其像素点存储在
fires[i].pix
中。 loadimage(&fm, "fire/flower.jpg")
:加载烟花的图片。getimage(&gm, i * 240, 0, 240, 240)
:从大图中截取每个烟花的图片。getpixel(a, b)
:获取图片中每个像素点的颜色值,并存储在fires[i].pix[a][b]
中。- 烟花弹的图片也以类似的方式加载,并存储在
bullets[i].img
中。
- 该函数加载烟花的图片数据,并将其像素点存储在
6. 绘制烟花
void drawFire(int i) {
if (!fires[i].draw) {
return;
}
for (double a = 0; a <= 6.28; a += 0.01)
{
int x1 = (int)(fires[i].cent2LeftTopX + fires[i].r * cos(a));
int y1 = (int)(fires[i].cent2LeftTopY - fires[i].r * sin(a));
if (x1 > 0 && x1 < fires[i].width && y1 > 0 && y1 < fires[i].height)
{
int b = fires[i].pix[x1][y1] & 0xff;
int g = (fires[i].pix[x1][y1] >> 8) & 0xff;
int r = (fires[i].pix[x1][y1] >> 16);
int xx = (int)(fires[i].x + fires[i].r * cos(a));
int yy = (int)(fires[i].y - fires[i].r * sin(a));
if (r > 0x20 && g > 0x20 && b > 0x20 && xx > 0 && xx < 1200 && yy > 0 && yy < 800)
pMem[yy * 1200 + xx] = BGR(fires[i].pix[x1][y1]);
}
}
fires[i].draw = false;
}
- 解析:
- 该函数根据烟花的当前状态绘制烟花。
- 通过遍历角度
a
(从0到2π),计算每个像素点的位置(x1, y1)
。 - 如果像素点在图片范围内,则获取其颜色值,并将其绘制到屏幕上。
pMem[yy * 1200 + xx]
:直接操作显存,将像素点的颜色值写入显存。
7. 烟花弹升空
void shoot() {
for (int i = 0; i < 13; i++) {
bullets[i].t2 = timeGetTime();
if (bullets[i].t2 - bullets[i].t1 > bullets[i].dt && bullets[i].shoot == true) {
putimage(bullets[i].x, bullets[i].y, &bullets[i].img[bullets[i].n], SRCINVERT);
if (bullets[i].y > bullets[i].topY) {
bullets[i].n++;
bullets[i].y -= 5;
}
putimage(bullets[i].x, bullets[i].y, &bullets[i].img[bullets[i].n], SRCINVERT);
if ((bullets[i].y - bullets[i].topY) * 4 < bullets[i].height)
bullets[i].dt = rand() % 4 + 10;
if (bullets[i].y <= bullets[i].topY) {
putimage(bullets[i].x, bullets[i].y, &bullets[i].img[bullets[i].n], SRCINVERT);
fires[i].x = bullets[i].topX + 10;
fires[i].y = bullets[i].topY;
fires[i].show = true;
bullets[i].shoot = false;
char c1[64], c2[64];
sprintf_s(c1, "close s%d", i);
sprintf_s(c2, "play f%d", i);
mciSendString(c1, 0, 0, 0);
mciSendString(c2, 0, 0, 0);
sprintf_s(c1, sizeof(c1), "open fire/shoot.mp3 alias s%d", i);
mciSendString(c1, 0, 0, 0);
}
bullets[i].t1 = bullets[i].t2;
}
}
}
- 解析:
- 该函数控制烟花弹的升空过程。
- 根据时间间隔更新烟花弹的位置,并在达到最高点时触发烟花的绽放。
putimage
:用于绘制烟花弹的图片,SRCINVERT
模式实现图片的闪烁效果。- 当烟花弹达到最高点时,设置烟花的状态为绽放,并播放爆炸音效。
8. 主循环
while(1)
{
Sleep(10);
clearImage();
chose(t1);
shoot();
showFire();
heartFire(ht1);
FlushBatchDraw();
}
- 解析:
- 主循环不断运行,直到用户按下按键退出。
Sleep(10)
:控制帧率,每10毫秒更新一次。clearImage()
:随机擦除屏幕上的像素点,模拟烟花绽放后的残留效果。chose(t1)
:选择并发射烟花弹。shoot()
:控制烟花弹的升空。showFire()
:控制烟花的绽放。heartFire(ht1)
:每隔20秒触发一次心形烟花效果。FlushBatchDraw()
:将绘制结果刷新到屏幕上。
9.总结
这段代码展示了如何使用结构体和数组来管理多个烟花和烟花弹的状态,并通过时间间隔控制烟花的发射、升空和绽放过程。程序还实现了心形烟花和倒计时等特效,展示了如何使用EasyX图形库来实现复杂的图形动画效果。
10 . 完整代码
链接戳这里直达
提取码: 2025