废话不多说,先上代码 其实没啥好说的
参考文献:https://zhuanlan.zhihu.com/p/333503066
(3条消息) 3分钟用C语言教你写个‘浪漫烟花‘---特别漂亮_尘客-追梦的博客-CSDN博客
用c语言编写动态烟花的方法 - 编程语言 - 亿速云 (yisu.com)
视频文献:【C/C++】C语言实现浪漫烟花表白程序,表白必备的满天花海!_哔哩哔哩_bilibili
【C语言链表】尽毕生所学教会你C语言链表,看完保准会。_哔哩哔哩_bilibili
//编写环境vs2019
#include<graphics.h>
#include<time.h>
#include<stdlib.h>
#include<math.h>
#include<windows.h>
#pragma comment(lib,"winmm.lib")
#define NUM 10
//烟花弹
struct jet
{
int x, y;
int hx, hy;
bool shoot;
DWORD t1, t2, dt;
IMAGE img[2];
byte n : 1;
}jet[NUM];
//烟花
struct Fire
{
int x, y;
int r;
int max_r;
int cen_x, cen_y;
int width, height;
int xy[240][240];
bool draw;
bool show;
DWORD t1, t2, dt;
}fire[NUM];
void FireInit(int i)
{
jet[i].t1 = GetTickCount();
jet[i].shoot = false;
jet[i].dt = 10;
jet[i].n = 0;
//初始化烟花
fire[i].show = false; //未引爆
fire[i].r = 0;
fire[i].dt = 5; //上升时间
fire[i].t1 = GetTickCount();
fire[i].max_r = rand() % 50 + 100;
fire[i].cen_x = rand() % 30 + 80;
fire[i].cen_y = rand() % 30 + 80;
fire[i].width = 240;
fire[i].height = 240;
}
//加载
void Load()
{
//加载烟花弹
IMAGE jetimg;
loadimage(&jetimg, L"./fire/shoot.jpg", 200, 50);
SetWorkingImage(&jetimg);
for (int i = 0; i < NUM; i++)
{
int n = rand() % 5; //01234
getimage(&jet[i].img[0], n * 20, 0, 20, 50);
getimage(&jet[i].img[1], (n + 5) * 20, 0, 20, 50);
}
SetWorkingImage(NULL);
//加载烟花
IMAGE fireimage, Fireimage;
loadimage(&Fireimage, L"./fire/flower.jpg", 3120, 240);
for (int i = 0; i < NUM; i++)
{
SetWorkingImage(&Fireimage);
getimage(&fireimage, i * 240, 0, 240, 240);
SetWorkingImage(&fireimage);
for (int a = 0; a < 240; a++)
{
for (int b = 0; b < 240; b++)
{
fire[i].xy[a][b] = getpixel(a, b);
}
}
}
SetWorkingImage(NULL);
}
//选择烟花弹
void ChoiceJet(DWORD& t1)
{
DWORD t2 = GetTickCount();
if (t2 - t1 > 100)
{
int i = rand() % 10;
if (jet[i].shoot == false && fire[i].show == false)
{
jet[i].x = rand() % 1000;
jet[i].y = rand() % 100 + 450;
jet[i].hx = jet[i].x;
jet[i].hy = rand() % 300;
jet[i].shoot = true;
putimage(jet[i].x, jet[i].y, &jet[i].img[jet[i].n], SRCINVERT);
}
t1 = t2;
}
}
//判断发射
void Shoot()
{
for (int i = 0; i < NUM; i++)
{
jet[i].t2 = GetTickCount();
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);
if (jet[i].y <= jet[i].hy)
{
putimage(jet[i].x, jet[i].y, &jet[i].img[jet[i].n], SRCINVERT);
jet[i].shoot = false;
fire[i].x = jet[i].hx;
fire[i].y = jet[i].hy;
fire[i].show = true;
}
}
jet[i].t1 = jet[i].t2;
}
}
//显示烟花
void ShowFire(DWORD* pMem)
{
int drt[16] = { 5,5,5,5,5,10,25,25,25,25,55,55,55,55,55,65 };
for (int i = 0; i < NUM; i++)
{
fire[i].t2 = GetTickCount();
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;
FireInit(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 < 1000 && yy >0 && yy < 600)
{
pMem[yy * 1000 + xx] = BGR(fire[i].xy[x1][y1]);
}
fire[i].draw = false;
}
}
}
}
}
}
//主函数
int main()
{
initgraph(1000, 600);
srand((unsigned int)time(NULL));
mciSendString(L"open ./fire/bk1.mp3 alias music", 0, 0, 0);
mciSendString(L"play music", 0, 0, 0);
DWORD t1 = GetTickCount();
DWORD* pMem = GetImageBuffer();
for (int i = 0; i < NUM; i++)
{
FireInit(i);
}
Load();
BeginBatchDraw();
while (1)
{
for (int clr = 0; clr < 200; clr++)
{
int px1 = rand() % 1000;
int py1 = rand() % 600;
if (py1 < 599)
{
pMem[py1 * 1000 + px1] = pMem[py1 * 1000 + px1 + 1] = BLACK;
}
}
ChoiceJet(t1);
Shoot();
ShowFire(pMem);
FlushBatchDraw();
}
system("pause");
return 0;
}
好好听讲 开讲
基本代码
<graphics.h>
头文件需要自己下载。
下载网址:https://easyx.cn/
graphics.h
实例
#include<stdio.h>
#include<graphics.h>
#include<conio.h>
int main()
{
initgraph(700,700);//初始化窗口 也就是设定我们的程序框大小
setcolor(RED);//设置绘图的颜色
circle(200,200,100);//圆心(200,200),半径100
rectangle(200,200,400,400);//绘制一个矩形
line(200,200,500,500);//画线
getch();
closegraph;//关闭绘图程序界面
}
头文件与结构体
#include<graphics.h>//图形界面
#include<time.h>
#include<stdlib.h>
#include<math.h>
#include<windows.h>
#pragma comment(lib,"winmm.lib")//可能会报错
#define NUM 10//烟花弹个数
//烟花弹
struct jet
{
int x, y;//烟花弹坐标
int hx, hy;//烟花弹最高点坐标
bool shoot; //记录烟花弹是否处于发射
DWORD t1, t2, dt;//t1发射时间;t2引爆时间;dt:间隔时间
IMAGE img[2];//用来存图片。两张(一明一暗)
byte n : 1;
}jet[NUM];
//烟花
struct Fire
{
int x, y;//烟花的坐标
int r; //烟花的半径
int max_r; //烟花的最大半径
int cen_x, cen_y; //中心距离左上角的距离(也就是中心距理原点的距离)
int width, height; //烟花的长和宽
int xy[240][240]; //像素,矩阵
bool draw; //记录是否画出
bool show; //记录是否显示
DWORD t1, t2, dt; //发射时间 引爆时间 间隔时间
}fire[NUM];
bool类型
C语言并没有彻底从语法上支持“真”和“假”,只是用 0 和非 0 来代表。这点在 C++ 中得到了改善,C++ 新增了 bool 类型(布尔类型),它一般占用 1 个字节长度。bool 类型只有两个取值,true 和 false:true 表示“真”,false 表示“假”。
bool 是类型名字,也是 C++ 中的关键字,它的用法和 int、char、long 是一样的,请看下面的例子:
#include <iostream>
using namespace std;
int main(){
int a, b;
bool flag; //定义布尔变量
cin>>a>>b;
flag = a > b;
cout<<"flag = "<<flag<<endl;
return 0
}
10 20
flag = 0
遗憾的是,在 C++ 中使用 cout 输出 bool 变量的值时还是用数字 1 和 0 表示,而不是 true 或 false。Java、PHP、JavaScript 等也都支持bool类型,但输出结果为 true 或 false,我武断地认为这样更科学。
你也可以使用 true 或 false 显式地对 bool 变量赋值,例如:
#include <iostream>
using namespace std;
int main(){
bool flag = true;
if(flag){
cout<<"true"<<endl;
}else{
cout<<"false"<<endl;
}
flag = false;
if(flag){
cout<<"true"<<endl;
}else{
cout<<"false"<<endl;
}
return 0;
}
运行结果:
true
false
注意,true 和 false 是 C++ 中的关键字,true 表示“真”,false 表示“假”。
DOWRD类型
在Visual C++ 6.0中,BYTE与WORD,DWORD本质上都是一种无符号整型,它们在WINDEF.H中被定义,定义如下:
typedef unsigned char BYTE;
typedef unsigned short WORD;
typedef unsigned long DWORD;
也就是说BYTE是无符号的char型(char型本质上也是一种1个字节的整型),WORD是无符号short型,DWORD是无符号long型。
而在Visual C++ 6.0中,char型长度为1字节,short型长度为2字节,int和long型长度都为4字节,因此可以认为BYTE与WORD,DWORD定义的变量分别获得了1字节,2字节,4字节内存,正与BYTE与WORD,DWORD的字面意义相符。
即:BYTE=unsigned char(完全等同)
WORD=unsigned short(完全等同)
DWORD=unsigned long(完全等同)
IMAGE
IMAGE img[2]
存入了两张图片。//IMAGE是一个关于存入图片的结构体,只是开辟了一个空间让图片可以存进去,但还没存进去。
byte n : 1;
BYTE=unsigned char(完全等同)
C结构体 位段 //n 变量 1个位 0,1 n++ 0,1,0,1
函数统计
void ChoiceJet()//用来选择烟花弹
void FireInit()//对程序进行初始化
void Load()//加载
void shoot()//判断发射
void ShowFire()//显示烟花
主函数
int main()
{
//初始界面(1000,600)
initgraph(1000, 600);
//初始化种子,使用rand前一定要初始化,不然之后rand出的数都相同
srand((unsigned int)time(NULL));
mciSendString(L"open ./fire/bk1.mp3 alias music", 0, 0, 0); //send(发送) string(字符串 // 音乐要放在程序代码文件夹更目录下
mciSendString(L"play music", 0, 0, 0);
DWORD t1 = GetTickCount();
DWORD* pMem = GetImageBuffer();
for (int i = 0; i < NUM; i++)
{
FireInit(i);
}
Load();
BeginBatchDraw();
while (1)
{
// 随机选择像素点擦除
for (int clr = 0; clr < 200; clr++)
{
int px1 = rand() % 1000;
int py1 = rand() % 600;
// 防止越界
if (py1 < 599)
{
//对显存赋值擦除像素点
pMem[py1 * 1000 + px1] = pMem[py1 * 1000 + px1 + 1] = BLACK;
}
}
ChoiceJet(t1);
Shoot();
ShowFire(pMem);
FlushBatchDraw();
}
/*
putimage(0, 0, &jet[3].img[0]);
putimage(100, 0, &jet[3].img[1]);
*/
system("pause");
return 0;
}
mciSendString()函数
mciSendString(L"open ./fire/bk1.mp3 alias music", 0, 0, 0); //send(发送) string(字符串)
mciSendSrting()函数只支持打开MP3音频文件,若需要打开wav音频文件可以使用PlaySound函数
当使用mciSendSrting()函数时,一定要确定好文件的位置,文件夹名用/号隔开,向我这里的文件就在当前文件的根目录下,音乐的全名便是叫做bk1.MP3。bk1.MP3 alias music的意思是给bk1取一个叫做music的别名
mciSendString(L"play music", 0, 0, 0);的意思是播放别名为music的音乐。后面三个参0,0,0则表示默认
//0,0,0 音乐播放器时:播放设备,快进设备 快退 暂停