C++編寫浪漫煙花


主函數


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;
}

shoot

flower

一些數據類型

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM