C++ 祝福烟花小程序(源码)


/********************************************************
*                                                       *
*   程序名称:祝福烟花,祝福朋友                      *
*   编译环境:VC++6.0 && easyx(立冬版)                  *
*   作者相关:night chen                             *
*   最后修改:2016.07.05                                 *
*                                                       *
********************************************************/
#include <graphics.h>
#include <conio.h>
#include <iostream.h>
#include <math.h>
#include <time.h>
#include <stdio.h>
#include <Mmsystem.h>         // 使用该计时器必须包含的文件
#pragma comment ( lib , "Winmm.lib" )

/***** 宏定义区 ******/

#define NUM       13            // 烟花种类数量宏定义

/***** 结构定义区 **********/

// 烟花结构
struct FIRE
{
     int r;                   // 当前爆炸半径
     int max_r;               // 爆炸中心距离边缘最大半径
     int x, y;                // 爆炸中心在窗口的坐标
     int cen_x, cen_y;        // 爆炸中心相对图片左上角的坐标
     int width, height;       // 图片的宽高
     int xy[ 240 ][ 240 ];        // 储存图片像素点

     bool show;               // 是否绽放
     bool draw;               // 开始输出像素点
    DWORD t1, t2, dt;        // 绽放速度
}Fire[NUM];

// 烟花弹结构
struct JET
{
     int x, y;                // 喷射点坐标
     int hx, hy;              // 最高点坐标------将赋值给 FIRE 里面的 x, y
     int height;              // 烟花高度
     bool shoot;              // 是否可以发射

    DWORD t1, t2, dt;        // 发射速度
    IMAGE img[ 2 ];            // 储存花弹一亮一暗图片
    byte n : 1 ;              // 图片下标
}Jet[NUM];

// zhufu1 结构函数
struct zhufu1                 // 储存 zhufu1 艺术字图片
{
     int x, y;                // 每个字的图片的左上角坐标
    IMAGE img;               // 储存单个字图片
     static int num;          // 字母序号
}zhufu1[NUM];
int zhufu1::num = 0 ;

// zhufu 结构
struct WISH                   // 滚动祝福图片结构
{
     int x, y;                // 图片左上角坐标
    DWORD t1, t2, dt;        // 图片运动时间间隔
    IMAGE img;               // 储存图片
     int dxy;                 // 每次的移动量
    byte dir : 1 ;            // 限制两个滚动方向
}Wish;

/**** 函数申明区 ****/

void Init    ( int     );      // 初始化烟花
void Load    (        );      // 加载烟花图片
void Shoot   (        );      // 发射烟花
void Chose   ( DWORD & );      // 筛选烟花
void Wishing (        );      // 滚动祝福
void Style   ( DWORD & );      // 发射样式
void Show    ( DWORD * );      // 绽放烟花
void welcome     ();
void zhufu_z     ();            //祝福语

// 主函数
void main ()
{
     initgraph ( 1200 , 800 );
     srand ( time ( 0 ) );

     // 播放背景音乐
     mciSendString ( "open ./fire/bk.mp3 alias bk" , 0 , 0 , 0 );
     mciSendString ( "play bk repeat" , 0 , 0 , 0 );

welcome ();                           //显示欢迎界面
     zhufu_z ();                          //祝福语


/*加载初始化 bj 图片*/
            IMAGE bj;
     loadimage ( & bj, "./fire/bj.jpg" , 1920 , 1020 );
     putimage ( 0 , 0 , & bj);


    DWORD t1     = timeGetTime ();         // 筛选烟花计时
    DWORD st1    = timeGetTime ();         // 播放花样计时
    DWORD * pMem = GetImageBuffer ();      // 获取窗口显存指针

     for ( int i = 0 ; i < NUM; i ++ )      // 初始化烟花
    {
         Init ( i );
    }
     Load ();                              // 将烟花图片信息加载进相应结构中
     BeginBatchDraw ();                    // 开始批量绘图

     while ( ! kbhit () )
    {
         Sleep ( 10 );

         // 随机选择 4000 个像素点擦除
         for ( int clr = 0 ; clr < 1000 ; clr ++ )
        {
             for ( int j = 0 ; j < 2 ; j ++ )
            {
                 int px1 = rand () % 1200 ;
                 int py1 = rand () % 800 ;

                 if ( py1 < 799 )                 // 防止越界
                    pMem[py1 * 1200 + px1] = pMem[py1 * 1200 + px1 + 1 ] = BLACK;     // 对显存赋值擦出像素点
            }
        }
         Chose    ( t1    );       // 筛选烟花
         Shoot    (       );       // 发射烟花
         Show     ( pMem  );       // 绽放烟花
         Wishing  (       );       // 滚动字符
         Style    ( st1   );       // 花样发射
         FlushBatchDraw ( );       // 显示前面的所有绘图操作
    }
}


// 初始化烟花参数
void Init ( int i )
{
     // 分别为:烟花中心到图片边缘的最远距离、烟花中心到图片左上角的距离 (x、y) 两个分量
     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   };

     /**** 初始化烟花 *****/

    Fire[i]. x         = 0 ;                 // 烟花中心坐标
    Fire[i]. y         = 0 ;
    Fire[i]. width     = 240 ;               // 图片宽
    Fire[i]. height    = 240 ;               // 图片高
    Fire[i]. max_r     = r[i];              // 最大半径
    Fire[i]. cen_x     = x[i];              // 中心距左上角距离
    Fire[i]. cen_y     = y[i];
    Fire[i]. show      = false ;             // 是否绽放
    Fire[i]. dt        = 5 ;                 // 绽放时间间隔
    Fire[i]. t1        = timeGetTime ();
    Fire[i]. r         = 0 ;                 // 从 0 开始绽放

     /**** 初始化烟花弹 *****/

    Jet[i]. x          = - 240 ;              // 烟花弹左上角坐标
    Jet[i]. y          = - 240 ;
    Jet[i]. hx         = - 240 ;              // 烟花弹发射最高点坐标
    Jet[i]. hy         = - 240 ;
    Jet[i]. height     = 0 ;                 // 发射高度
    Jet[i]. t1         = timeGetTime ();
    Jet[i]. dt         = rand () % 10 ;       // 发射速度时间间隔
    Jet[i]. n          = 0 ;                 // 烟花弹闪烁图片下标
    Jet[i]. shoot      = false ;             // 是否发射
}


// 加载图片
void Load ()
{
/**** 储存烟花的像素点颜色 ****/
    IMAGE fm, gm;
     loadimage ( & fm, "./fire/flower.jpg" , 3120 , 240 );

     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 ++ )
                Fire[i]. xy [a][b] = getpixel ( a, b );
    }

/**** 加载烟花弹 ************/
    IMAGE sm;
     loadimage ( & sm, "./fire/shoot.jpg" , 200 , 50 );

     for ( i = 0 ; i < 13 ; i ++ )
    {
         SetWorkingImage ( & sm );
         int n = rand () % 5 ;

         getimage ( & Jet[i]. img [ 0 ], n * 20 , 0 , 20 , 50 );           // 暗
         getimage ( & Jet[i]. img [ 1 ], (n + 5 ) * 20 , 0 , 20 , 50 );     // 亮
    }

/***** 加载 祝福字体 图片 ********/
    IMAGE hm;   
     loadimage ( & hm, "./fire/zhufu1.jpg" , 689 , 115 );
     SetWorkingImage ( & hm );

     for ( i = 0 ; i < 13 ; i ++ )
    {
        zhufu1[i]. x = 350 + i * 40 ;
        zhufu1[i]. y = rand () % 100 + 500 ;
         getimage ( & zhufu1[i]. img , i * 22 , 0 , 22 , 115 );
    }

/***** 加载 zhufu 图片 *********/
    Wish. x        = 0 ;
    Wish. y        = 100 ;
    Wish. t1       = timeGetTime ();
    Wish. dt       = 46 ;
    Wish. dir      = 0 ;
    Wish. dxy      = rand () % 8 + 1 ;
    loadimage ( & Wish. img , "./fire/zhufu.jpg" , 490 , 100 );
     putimage ( Wish. x , Wish. y , & Wish. img , SRCINVERT );

     SetWorkingImage ();       // 设置回绘图窗口
}


// 在一定范围内筛选可发射的烟花,并初始化发射参数,输出烟花弹到屏幕,播放声音
void Chose ( DWORD & t1 )
{
    DWORD t2 = timeGetTime ();

     if ( t2 - t1 > 100 )
    {
         int n = rand () % 20 ;

         if ( n < 13 && Jet[n]. shoot == false && Fire[n]. show == false )
        {
             /**** 重置烟花弹,预备发射 *****/
            Jet[n]. x          = rand () % 1200 ;
            Jet[n]. y          = rand () % 100 + 600 ;
            Jet[n]. hx         = Jet[n]. x ;
            Jet[n]. hy         = rand () % 400 ;
            Jet[n]. height     = Jet[n]. y - Jet[n]. hy ;
            Jet[n]. shoot      = true ;
             putimage ( Jet[n]. x , Jet[n]. y , & Jet[n]. img [Jet[n]. n ], SRCINVERT );

             /**** 播放每个烟花弹的声音 *****/
             char c1[ 50 ], c2[ 30 ], c3[ 30 ];
             sprintf ( c1, "open ./fire/shoot.mp3 alias s%d" , n );
             sprintf ( c2, "play s%d" , n );
             sprintf ( c3, "close n%d" , n );

             mciSendString ( c3, 0 , 0 , 0 );
             mciSendString ( c1, 0 , 0 , 0 );
             mciSendString ( c2, 0 , 0 , 0 );
        }
        t1 = t2;
    }
}


// 扫描烟花弹并发射
void Shoot ()
{
     for ( int i = 0 ; i < 13 ; i ++ )
    {
        Jet[i]. t2 = timeGetTime ();

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

             /**** 上升到高度的 3 / 4,减速 *****/
             if ( (Jet[i]. y - Jet[i]. hy ) * 4 < Jet[i]. height )
                Jet[i]. dt = rand () % 4 + 10 ;

             /**** 上升到最大高度 *****/
             if ( Jet[i]. y <= Jet[i]. hy )
            {
                 // 播放爆炸声
                 char c1[ 50 ], c2[ 30 ], c3[ 30 ];
                 sprintf ( c1, "open ./fire/bomb.wav alias n%d" , i );
                 sprintf ( c2, "play n%d" , i );
                 sprintf ( c3, "close s%d" , i );

                 mciSendString ( c3, 0 , 0 , 0 );
                 mciSendString ( c1, 0 , 0 , 0 );
                 mciSendString ( c2, 0 , 0 , 0 );

                 putimage ( Jet[i]. x , Jet[i]. y , & Jet[i]. img [Jet[i]. n ], SRCINVERT );    // 擦掉烟花弹
                Fire[i]. x = Jet[i]. hx + 10 ;                                          // 在烟花弹中间爆炸
                Fire[i]. y = Jet[i]. hy ;                                               // 在最高点绽放
                Fire[i]. show = true ;                     // 开始绽放

                /*小星星*/
                IMAGE zm;
                 loadimage ( & zm, "./fire/xx.jpg" );
                 putimage (Fire[i]. x - 15 , Fire[i]. y - 15 , & zm);

                Jet[i]. shoot = false ;                    // 停止发射

                 // 显示对应字母
                 putimage ( zhufu1[zhufu1::num]. x , zhufu1[zhufu1::num]. y , & zhufu1[zhufu1::num]. img , SRCINVERT );
                zhufu1::num ++ ;

                 if ( zhufu1::num > 12 )
                    zhufu1::num = 0 ;
            }
            Jet[i]. t1 = Jet[i]. t2 ;
        }
    }
}


void welcome ()
{
     // 输出开始界面
    IMAGE cs;
     loadimage ( & cs, "./fire/bf.gif " );
     putimage ( 0 , 0 , & cs);

    
     setcolor (YELLOW);
     setfont ( 64 , 0 , "黑体" );
     outtextxy ( 400 , 100 , "祝福烟花演示" );
     setcolor (WHITE);
     setfont ( 32 , 0 , "宋体" );
     outtextxy ( 100 , 200 , "" );
     outtextxy ( 100 , 240 , "改写:NIGHT CHEN" );
     outtextxy ( 480 , 320 , "生命不息" );
     outtextxy ( 480 , 400 , "编程不止" );
    

     // 实现闪烁的“按任意键继续”
     int c = 255 ;
         while ( ! kbhit ())
        {
             setcolor ( RGB (c, 0 , 0 ));
             outtextxy ( 430 , 610 , "按任意键继续" );
            c -= 8 ;
             if (c < 0 ) c = 255 ;
             Sleep ( 20 );
        }
         getch ();
         cleardevice ();
}




void zhufu_z ()               
{
    cleardevice ();
    IMAGE zhufu_b;
     loadimage ( & zhufu_b, "./fire/bj.jpg" );
     putimage ( 0 , 0 , & zhufu_b);

    setcolor (YELLOW);
     setfont ( 64 , 0 , "黑体" );
     outtextxy ( 450 , 100 , "语录" );
     setcolor (WHITE);
     setfont ( 32 , 0 , "宋体" );
     outtextxy ( 300 , 200 , "你可还记得,友人的笑容  " );
     outtextxy ( 300 , 250 , "蕴藏着世上所有的温柔" );
     outtextxy ( 300 , 300 , "你可会记得,少女脚步轻盈" );
     outtextxy ( 300 , 350 , "像清风吹过麦田" );
     outtextxy ( 300 , 400 , "你可还会记得,黑暗中有光亮起 " );
     outtextxy ( 300 , 450 , "你孤冷人生中唯一的璀璨 那是——你的家" );


    

     int c = 255 ;
     while ( ! kbhit ())
    {
         setcolor ( RGB (c, 0 , 0 ));
         outtextxy ( 430 , 610 , "按任意键" );
        c -= 8 ;
         if (c < 0 ) c = 255 ;
         Sleep ( 20 );
    }
     getch ();
     cleardevice ();
    
}


// 制作水平、竖直移动的图片
void Wishing ()
{
    Wish. t2 = timeGetTime ();

     if ( Wish. t2 - Wish. t1 > Wish. dt )
    {
         /**** 图片的移动 *****/
         putimage ( Wish. x , Wish. y , & Wish. img , SRCINVERT );

         if ( Wish. dir == 0 )
            Wish. x += Wish. dxy ;
         else
            Wish. y -= Wish. dxy ;

         putimage ( Wish. x , Wish. y , & Wish. img , SRCINVERT );

         /**** 图片出界后 *****/
         if ( Wish. x > 1200 || Wish. y < 0 )
        {
            Wish. dir = rand () % 2 ;           // 获取随机方向

             if ( Wish. dir == 0 )             // 如果左右运动
            {
                Wish. y = rand () % 700 ;       // 初始位置
                Wish. x = - 490 ;
                Wish. dxy = rand () % 7 + 1 ;   // 随机运动分量
            }
             else                              // 上下运动
            {
                Wish. dxy = rand () % 7 + 1 ;
                Wish. x = rand () % 700 ;
                Wish. y = 800 ;
            }
        }
        Wish. t1 = Wish. t2 ;
    }
}


// 显示花样
void Style ( DWORD & st1 )
{
    DWORD st2 = timeGetTime ();

     if ( st2 - st1 > 266000 )        // 一首歌的时间
    {
         // 心形坐标
         int x[ 13 ] = { 60 , 75 , 91 , 100 , 95 , 75 , 60 , 45 , 25 , 15 , 25 , 41 , 60 };
         int y[ 13 ] = { 65 , 53 , 40 , 22 , 5 , 4 , 20 , 4 , 5 , 22 , 40 , 53 , 65 };
         for ( int i = 0 ; i < NUM; i ++ )
        {
             cleardevice ();
             /**** 规律分布烟花弹 ***/
            Jet[i]. x          = x[i] * 10 ;
            Jet[i]. y          = ( y[i] + 75 ) * 10 ;
            Jet[i]. hx         = Jet[i]. x ;
            Jet[i]. hy         = y[i] * 10 ;
            Jet[i]. height     = Jet[i]. y - Jet[i]. hy ;
            Jet[i]. shoot      = true ;
            Jet[i]. dt         = 7 ;
             putimage ( Jet[i]. x , Jet[i]. y , & Jet[i]. img [Jet[i]. n ], SRCINVERT );    // 显示烟花弹

             /**** 设置烟花参数 ***/
            Fire[i]. x         = Jet[i]. x + 10 ;
            Fire[i]. y         = Jet[i]. hy ;
            Fire[i]. show      = false ;
            Fire[i]. r         = 0 ;

             /**** 播放发射声音 ***/
             char c1[ 50 ], c2[ 30 ], c3[ 30 ];
             sprintf ( c1, "open ./fire/shoot.mp3 alias s%d" , i );
             sprintf ( c2, "play s%d" , i );
             sprintf ( c3, "close n%d" , i );

             mciSendString ( c3, 0 , 0 , 0 );
             mciSendString ( c1, 0 , 0 , 0 );
             mciSendString ( c2, 0 , 0 , 0 );
        }
        st1 = st2;
    }
}


// 绽放烟花
void Show ( DWORD * pMem )
{
     // 烟花个阶段绽放时间间隔,制作变速绽放效果
     int drt[ 16 ] = { 5 , 5 , 5 , 5 , 5 , 6 , 25 , 25 , 25 , 25 , 55 , 55 , 55 , 55 , 55 };

     for ( int i = 0 ; i < NUM; i ++ )
    {
        Fire[i]. t2 = timeGetTime ();

         // 增加爆炸半径,绽放烟花,增加时间间隔做变速效果
         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]. y > - 400 //烟花发射高度在一半以下的不输出
            {
                Fire[i]. draw = false ;
                 Init ( 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 < 1200 && yy > 0 && yy < 800 )
                        pMem[yy * 1200 + xx] = BGR ( Fire[i]. xy [x1][y1] );    // 显存操作绘制烟花
                }
            }
            Fire[i]. draw = false ;
        }
    }
}

猜你喜欢

转载自blog.csdn.net/nightchenright/article/details/80867156