主函数
int main()
{
initgraph(1200, 800);//
DWORD tt1 = GetTickCount();
DWORD* pmem = GetImageBuffer();//获取显存指针
load();//加载图片
//初始化数据(先初始化烟花弹 )
for (int i = 0; i < NUM; i++)
{
init(i);
}
BeginBatchDraw();//开始批量绘制
while (1)
{
Sleep(10);//擦除时间
for (int c = 0;c < 1000;c++)
{
for (int r = 0; r < 2; r++)//保证每次擦除两千的像素点
{
//随机找两千个窗口的点
int px1 = rand() % 1200;
int py1 = rand() % 800;
if (py1 < 799)//防止越界
{
pmem[py1 * 1200 + px1] = pmem[py1*1200 + px1 + 1] = BLACK;//擦除 -》 将像素点变成背景色 (黑色)
}
}
}
choise(tt1);
shoot();
firedraw(pmem);//显出指针
FlushBatchDraw();//结束批量绘制
}
getchar();//可不需要
return 0;
}
头文件 结构体
#include <stdio.h>
#include <graphics.h>
#include <windows.h>
#include <math.h>
#include <time.h>
#include<stdlib.h>
#include <mmsystem.h>
#pragma comment(lib,"winmm.lib")//库文件
#define NUM 13
//烟花
struct Fire
{
int x, y;//烟花在窗口里面爆炸的坐标
int r;//烟花爆炸的当前半径
int max_r;//烟花爆炸最大半径
int cen_x, cen_y;//图片坐标系中的中心位置
int xy[240][240];//240*240的像素数组,图片的像素点保存在这里
bool show;//烟花是否开始爆炸 表示可不可以爆炸
bool draw;//开始绘制 表示是否爆炸
DWORD t1, t2, dt;//单位时间 帧数 爆炸的速度
//unsigned long = DWORD 4字节
}fire[NUM];//
struct Jet
{
int x, y; //烟花弹的坐标 当前的坐标
int hx, hy;//烟花弹最高的坐标
bool shoot;//用一个数组来存放烟花弹的数据
//烟花弹的状态 是否发射的状态 true false
unsigned long t1, t2, dt; //速度 dt = t2 - t2 可用DWORD 代替
IMAGE img[2];//两张图片 一明一亮 img[0]表示暗色 img[1]亮色
//模拟一闪一闪的效果
byte n : 1;//typedef unsigned char byte;
//C语言结构体 位段 一个位 1/8字节 假设n++(01010010100)要么是零 要么是一
//img[n++]//一闪一闪
}jet[NUM];
加载图片
void load()
{
mciSendString(L"open ./bk1.mp3 alias music", 0, 0, 0);
mciSendString(L"play music", 0, 0, 0);//播放背景音乐
srand(time(NULL));//初始化随机种子
IMAGE bigimg;//一整张图片加载进来
loadimage(&bigimg, L"./shoot.jpg", 200, 50);
//把shoot.jpg保存在bigimg
SetWorkingImage(&bigimg);//十个烟花弹的图片
for (int i = 0; i < NUM; i++)
{
int n = rand() % 5;
getimage(&jet[i].img[0],n*20,0,20,50);//随机将前面的5张的任意一张图片保存到。。
getimage(&jet[i].img[1],(n + 5)*20,0,20,50);
}
SetWorkingImage(NULL);//把工作区域回到窗口
IMAGE flower, stepimg;//定义两张图片 一大一小
loadimage(&flower, L"./flower.jpg", 3120, 240);//3120 240(高度) 13张
//工作区 默认工作区是窗口
//flower.jpg这个图片中有13朵烟花
//getimage(&stepimg,);
for (int i = 0; i < NUM; i++)
{
SetWorkingImage(&flower);//在flower图片上,裁图片
getimage(&stepimg, i * 240, 0, 240, 240);//裁剪第一朵烟花 获取
SetWorkingImage(&stepimg);//小图片搞事情(ke ke )
for (int a = 0; a < 240; a++)
{
for (int b = 0; b < 240; b++)
{
fire[i].xy[a][b] = getpixel(a, b);//获取小图片上的每一个像素,存放在xy数组
}
}
}
SetWorkingImage(NULL);//工作区回到窗口
//return 0;
}
数据的初始化
//初始化
void init(int i)
{
//初始化烟花弹的数据
jet[i].x = 0;
jet[i].y = 0;
jet[i].hx = 0;
jet[i].hy = 0;
jet[i].t1 = GetTickCount();//获取系统时间
jet[i].t2 = 0;
jet[i].dt = rand()%10 + 1;//单位时间 1ms - 10ms
jet[i].n = 0;
jet[i].shoot = false;
fire[i].x = rand() % 1200;
fire[i].y = rand() % 800;
fire[i].r = 0;
fire[i].max_r = 120;//图片的宽度240 240
fire[i].cen_x = 120;
fire[i].cen_y = 120;
//fire[i].xy[240][240];
fire[i].show = false; //不能一上来就爆炸啊
fire[i].draw = false;
fire[i].t1 = GetTickCount();//获取系统的时间
//fire[i].t2;
fire[i].dt = 5;//爆炸的间隔 5毫秒
fire[i].xy[240][240];//矩阵 像素点
}
最核心的地方
//最核心的地方
void firedraw(DWORD* pmem)//显存指针
{
//逻辑
for (int i = 0; i < NUM; i++)
{
fire[i].t2 = GetTickCount();//GetTickCount:获取系统的时间
//“detat = t2 - t1”“
if (fire[i].t2 - fire[i].t1 >= fire[i].dt && fire[i].show == true)
{
//r不能超过max_r
if (fire[i].r < fire[i].max_r)
{
fire[i].r++;//半径不断变大 半径变大 烟花变大
fire[i].draw = true;//可以绘制
}
//万一超过 爆炸结束
if (fire[i].r >= fire[i].max_r - 1)
{
fire[i].draw = false;
init(i);//爆炸结束给内存初始化,等待下一次爆炸
}
//重置时间 否则永远t2-t1不为5(只有一次为5)
fire[i].t1 = fire[i].t2;
}
//如果是可以绘制的状态
if (fire[i].draw = true)
{
// 绘制不是贴图 而是输出像素点
// 像素点 就是颜色(颜色:32位的数据)
// 00000000 00000000 00000000 00000000
// a透明度 red green blue
for (double a = 0; a <= 6.28; a += 0.01)
{
//x1 y1 图片坐标系的坐标
int x1 = fire[i].cen_x + fire[i].r * cos(a);//这是初中数学就不讲了
//三角函数
int y1 = fire[i].cen_y - fire[i].r * sin(a);
//编程坐标系 与数学不一样
//以半径r得到圆弧上的每一个x和y
if (x1 > 0 && x1 < 240 && y1 > 0 && y1 < 240)
{
//分开32位数据 颜色 00000000 00000000 00000000
//点不能超出图片的该范围以外
int b = fire[i].xy[x1][y1] & 0xff;//blue
int g = (fire[i].xy[x1][y1] >> 8) & 0xff;//green
int r = (fire[i].xy[x1][y1] >> 16);//red
// 像素转移 小图片->工作区
int xx = fire[i].x + fire[i].r * cos(a);
int yy = fire[i].y - fire[i].r * sin(a);
//xx yy 窗口坐标系的坐标
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]);
// 移像素点 图片 =》 窗口
}
}
}
//总共得到628个圆弧上的点
fire[i].draw = false;
}
}
}
choise
//选择 出现 一点时间间隔
void choise(DWORD tt1)
{
DWORD tt2 = GetTickCount();
if (tt2 - tt1 > 100)//保证时间间隔
{
int i = rand() % NUM;
if ( jet[i].shoot == false && fire[i].show == false)//未发射状态 空闲
{
//数据重新规划一下
jet[i].x = rand()% (1200 - 20);
jet[i].y = rand()% (100 + 600);
jet[i].hx = jet[i].x;
jet[i].hy = rand()% 400;
jet[i].shoot = true;//可以发色
putimage(jet[i].x, jet[i].y,&jet[i].img[jet[i].n], SRCINVERT);//这个SRCINVERT 很重要
}
tt1 = tt2;//重置一下时间
}
}
shoot
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);//n++
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);
//把它的坐标传递个烟花
//这里很重要
fire[i].x = jet[i].hx;
fire[i].y = jet[i].hy;
fire[i].show = true;
//它的使命完成
jet[i].shoot = false;
}
jet[i].t1 = jet[i].t2;
}
}
}
源代码
#include <stdio.h>
#include <graphics.h>
#include <windows.h>
#include <math.h>
#include <time.h>
#include<stdlib.h>
#include <mmsystem.h>
#pragma comment(lib,"winmm.lib")
/*
1.把程序里面的元素用数据类型表示
//两个坐标桌面窗口的坐标,图片的坐标
单个烟花的大小240*240
2.初始化
*/
#define NUM 13
//烟花
struct Fire
{
int x, y;//烟花在窗口里面爆炸的坐标
int r;//烟花爆炸的当前半径
int max_r;//烟花爆炸最大半径
int cen_x, cen_y;//图片坐标系中的中心位置
int xy[240][240];//240*240的像素数组,图片的像素点保存在这里
bool show;//烟花是否开始爆炸 表示可不可以爆炸
bool draw;//开始绘制 表示是否爆炸
DWORD t1, t2, dt;//单位时间 帧数 爆炸的速度
//unsigned long = DWORD 4字节
}fire[NUM];
struct Jet
{
int x, y; //烟花弹的坐标 当前的坐标
int hx, hy;//烟花弹最高的坐标
bool shoot;//用一个数组来存放烟花弹的数据
//烟花弹的状态 是否发射的状态 true false
unsigned long t1, t2, dt; //速度 dt = t2 - t2
IMAGE img[2];//两张图片 一明一亮 img[0]表示暗色 img[1]亮色
//模拟一闪一闪的效果
byte n : 1;//typedef unsigned char byte;
//C语言结构体 位段 一个位 1/8字节 假设n++(01010010100)要么是零 要么是一
//img[n++]//一闪一闪
}jet[NUM];
void load()
{
mciSendString(L"open ./bk1.mp3 alias music", 0, 0, 0);
mciSendString(L"play music", 0, 0, 0);
srand(time(NULL));
IMAGE bigimg;//一整张图片加载进来
loadimage(&bigimg, L"./shoot.jpg", 200, 50);
//把shoot.jpg保存在bigimg
SetWorkingImage(&bigimg);//十个烟花弹的图片
for (int i = 0; i < NUM; i++)
{
int n = rand() % 5;
getimage(&jet[i].img[0],n*20,0,20,50);//随机将前面的5张的任意一张图片保存到。。
getimage(&jet[i].img[1],(n + 5)*20,0,20,50);
}
SetWorkingImage(NULL);//把工作区域回到窗口
IMAGE flower, stepimg;
loadimage(&flower, L"./flower.jpg", 3120, 240);//3120 240(高度) 13张
//工作区 默认工作区是窗口
//flower.jpg这个图片中有13朵烟花
//getimage(&stepimg,);
for (int i = 0; i < NUM; i++)
{
SetWorkingImage(&flower);//在flower图片上,裁图片
getimage(&stepimg, i * 240, 0, 240, 240);//裁剪第一朵烟花 获取
SetWorkingImage(&stepimg);//小图片搞事情
for (int a = 0; a < 240; a++)
{
for (int b = 0; b < 240; b++)
{
fire[i].xy[a][b] = getpixel(a, b);//获取小图片上的每一个像素,存放在xy数组
}
}
}
SetWorkingImage(NULL);//工作区回到窗口
//return 0;
}
//初始化
void init(int i)
{
//初始化烟花弹的数据
jet[i].x = 0;
jet[i].y = 0;
jet[i].hx = 0;
jet[i].hy = 0;
jet[i].t1 = GetTickCount();
jet[i].t2 = 0;
jet[i].dt = rand()%10 + 1;//单位时间 1ms - 10ms
jet[i].n = 0;
jet[i].shoot = false;
fire[i].x = rand() % 1200;
fire[i].y = rand() % 800;
fire[i].r = 0;
fire[i].max_r = 120;//图片的宽度240 240
fire[i].cen_x = 120;
fire[i].cen_y = 120;
//fire[i].xy[240][240];
fire[i].show = false; //***********
fire[i].draw = false;
fire[i].t1 = GetTickCount();//获取系统的时间
//fire[i].t2;
fire[i].dt = 5;//爆炸的间隔 5毫秒
fire[i].xy[240][240];
}
//最核心的地方
void firedraw(DWORD* pmem)//显存指针
{
//逻辑
for (int i = 0; i < NUM; i++)
{
fire[i].t2 = GetTickCount();//GetTickCount:获取系统的时间
//“detat = t2 - t1”
if (fire[i].t2 - fire[i].t1 >= fire[i].dt && fire[i].show == true)
{
//r不能超过max_r
if (fire[i].r < fire[i].max_r)
{
fire[i].r++;//半径不断变大
fire[i].draw = true;//可以绘制
}
//万一超过 爆炸结束
if (fire[i].r >= fire[i].max_r - 1)
{
fire[i].draw = false;
init(i);//爆炸结束给内存初始化,等待下一次爆炸
}
//重置时间 否则永远t2-t1不为5(只有一次为5)
fire[i].t1 = fire[i].t2;
}
//如果是可以绘制的状态
if (fire[i].draw = true)
{
// 绘制不是贴图 而是输出像素点
// 像素点 就是颜色(颜色:32位的数据)
// 00000000 00000000 00000000 00000000
// a透明度 red green blue
for (double a = 0; a <= 6.28; a += 0.01)
{
//x1 y1 图片坐标系的坐标
int x1 = fire[i].cen_x + fire[i].r * cos(a);
int y1 = fire[i].cen_y - fire[i].r * sin(a);
//编程坐标系 与数学不一样
//以半径r得到圆弧上的每一个x和y
if (x1 > 0 && x1 < 240 && y1 > 0 && y1 < 240)
{
//分开32位数据 颜色 00000000 00000000 00000000
//点不能超出图片的该范围以外
int b = fire[i].xy[x1][y1] & 0xff;//blue
int g = (fire[i].xy[x1][y1] >> 8) & 0xff;//green
int r = (fire[i].xy[x1][y1] >> 16);//red
// 像素转移 小图片->工作区
int xx = fire[i].x + fire[i].r * cos(a);
int yy = fire[i].y - fire[i].r * sin(a);
//xx yy 窗口坐标系的坐标
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]);
// 移像素点 图片 =》 窗口
}
}
}
//628个圆弧上的点
fire[i].draw = false;
}
}
}
//选择 出现 一点时间间隔
void choise(DWORD tt1)
{
DWORD tt2 = GetTickCount();
if (tt2 - tt1 > 100)//保证时间间隔
{
int i = rand() % NUM;
if ( jet[i].shoot == false && fire[i].show == false)//未发射状态 空闲
{
//数据重新规划一下
jet[i].x = rand()% (1200 - 20);
jet[i].y = rand()% (100 + 600);
jet[i].hx = jet[i].x;
jet[i].hy = rand()% 400;
jet[i].shoot = true;
putimage(jet[i].x, jet[i].y,&jet[i].img[jet[i].n], SRCINVERT);
}
tt1 = tt2;
}
}
/*
-----------------------------------X
1
1
1
1
1
1
1
1
1
Y
*/
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);//n++
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);
//把它的坐标传递个烟花
fire[i].x = jet[i].hx;
fire[i].y = jet[i].hy;
fire[i].show = true;
//它的使命完成
jet[i].shoot = false;
}
jet[i].t1 = jet[i].t2;
}
}
}
int main()
{
initgraph(1200, 800);
DWORD tt1 = GetTickCount();
DWORD* pmem = GetImageBuffer();//获取显存指针
load();
for (int i = 0; i < NUM; i++)
{
init(i);
}
BeginBatchDraw();
while (1)
{
Sleep(10);//擦除时间
for (int c = 0;c < 1000;c++)
{
for (int r = 0; r < 2; r++)//保证每次擦除两千的像素点
{
//随机找两千个窗口的点
int px1 = rand() % 1200;
int py1 = rand() % 800;
if (py1 < 799)//防止越界
{
pmem[py1 * 1200 + px1] = pmem[py1*1200 + px1 + 1] = BLACK;
}
}
}
choise(tt1);
shoot();
firedraw(pmem);
FlushBatchDraw();
}
getchar();
return 0;
}
一些数据类型
typedef unsigned long DWORD;//4字节typedef int BOOL;typedef unsigned char BYTE;typedef unsigned short WORD;
参考资源
[【C/C++】程序员表白神器!c语言实现浪漫烟花表白,撩妹新技能你get了嘛?_哔哩哔哩_bilibili]
(https://www.bilibili.com/video/BV1Jy4y1B7YV?spm_id_from=333.999.0.0)
[【C/C++】C语言实现浪漫烟花表白程序,表白必备的满天花海!_哔哩哔哩_bilibili](https://www.bilibili.com/video/BV1Zy4y1r7dL/)
</mmsystem.h></stdlib.h></time.h></math.h></windows.h></graphics.h></stdio.h></mmsystem.h></stdlib.h></time.h></math.h></windows.h></graphics.h></stdio.h>
代码下载链接:
https://pan.baidu.com/s/1yGbsojDQii3kLRYjFJUhdw
提取码:m7oa
请发表评论