廢話不多說,先上代碼 其實沒啥好說的
參考文獻: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 音樂播放器時:播放設備,快進設備 快退 暫停