zoukankan      html  css  js  c++  java
  • 《逐梦旅程 WINDOWS游戏编程之从零开始》笔记2——透明贴图,动画技术

    第5章 透明贴图

    像这样直接贴图会产生这种情况,所以我们需要透明贴图。

    透明遮罩法:主要利用BitBlt函数中Raser(光栅)值的运算,需要准备素材图和遮罩图:

    这个方法的原理解释见书131页。

    示例程序:

      1 #include <windows.h>
      2 
      3 #define WINDOW_WIDTH    800                            //为窗口宽度定义的宏,以方便在此处修改窗口宽度
      4 #define WINDOW_HEIGHT    600                            //为窗口高度定义的宏,以方便在此处修改窗口高度
      5 #define WINDOW_TITLE    L"【致我们永不熄灭的游戏开发梦想】程序核心框架"        //为窗口标题定义的宏
      6 
      7 HDC    g_hdc=NULL,g_mdc=NULL;       //全局设备环境句柄
      8 HBITMAP g_hBackGround,g_hCharacter1,g_hCharacter2;  //定义3个位图句柄,用于3张图片的存放
      9 
     10 LRESULT CALLBACK    WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );  //窗口过程函数
     11 BOOL Game_Init(HWND hwnd); //在此函数中进行资源的初始化
     12 VOID Game_Paint(HWND hwnd); //进行绘图代码的书写
     13 BOOL Game_CleanUp(HWND hwnd); //资源的清理
     14 
     15 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nShowCmd)
     16 {
     17     //【1】窗口创建四步曲之一:开始设计一个完整的窗口类
     18     WNDCLASSEX wndClass = { 0 };                            //用WINDCLASSEX定义了一个窗口类,{0}用来初始化结构体
     19     wndClass.cbSize = sizeof( WNDCLASSEX ) ;            //设置结构体的字节数大小
     20     wndClass.style = CS_HREDRAW | CS_VREDRAW;    //设置窗口的样式
     21     wndClass.lpfnWndProc = WndProc;                    //设置指向窗口过程函数的指针
     22     wndClass.cbClsExtra  = 0;                                //窗口类的附加内存,取0就可以了
     23     wndClass.cbWndExtra  = 0;                            //窗口的附加内存,依然取0就行了
     24     wndClass.hInstance = hInstance;                        //指定包含窗口过程的程序的实例句柄。
     25     wndClass.hIcon=(HICON)::LoadImage(NULL,L"icon.ico",IMAGE_ICON,0,0,LR_DEFAULTSIZE|LR_LOADFROMFILE);  //本地加载自定义ico图标
     26     wndClass.hCursor = LoadCursor( NULL, IDC_ARROW );    //指定窗口类的光标句柄。
     27     wndClass.hbrBackground=(HBRUSH)GetStockObject(GRAY_BRUSH);  //为hbrBackground成员指定一个灰色画刷句柄    
     28     wndClass.lpszMenuName = NULL;                        //用一个以空终止的字符串,指定菜单资源的名字。
     29     wndClass.lpszClassName = L"ForTheDreamOfGameDevelop";        //用一个以空终止的字符串,指定窗口类的名字。
     30 
     31     //【2】窗口创建四步曲之二:注册窗口类
     32     if( !RegisterClassEx( &wndClass ) )                //设计完窗口后,需要对窗口类进行注册,这样才能创建该类型的窗口
     33         return -1;        
     34 
     35     //【3】窗口创建四步曲之三:正式创建窗口
     36     HWND hwnd = CreateWindow( L"ForTheDreamOfGameDevelop",WINDOW_TITLE,        //喜闻乐见的创建窗口函数CreateWindow
     37         WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH,
     38         WINDOW_HEIGHT, NULL, NULL, hInstance, NULL );
     39 
     40     //【4】窗口创建四步曲之四:窗口的移动、显示与更新
     41     MoveWindow(hwnd,250,80,WINDOW_WIDTH,WINDOW_HEIGHT,true);        //调整窗口显示时的位置,使窗口左上角位于(250,80)处
     42     ShowWindow( hwnd, nShowCmd );    //调用ShowWindow函数来显示窗口,第二个参数用于指定窗口的显示状态
     43     UpdateWindow(hwnd);                        //对窗口进行更新,就像我们买了新房子要装修一样
     44 
     45     //游戏资源的初始化,若初始化失败,弹出一个消息框,并返回FALSE
     46     if(!(Game_Init(hwnd)))
     47     {
     48         MessageBox(hwnd,L"资源初始化失败",L"消息窗口",0);
     49         return FALSE;
     50     }
     51 
     52     //【5】消息循环过程
     53     MSG msg = { 0 };        //定义并初始化msg
     54     while( msg.message != WM_QUIT )            //使用while循环,如果消息不是WM_QUIT消息,就继续循环
     55     {
     56         if( PeekMessage( &msg, 0, 0, 0, PM_REMOVE ) )   //查看应用程序消息队列,有消息时将队列中的消息派发出去。
     57         {
     58             TranslateMessage( &msg );        //将虚拟键消息转换为字符消息
     59             DispatchMessage( &msg );            //分发一个消息给窗口程序。
     60         }
     61     }
     62 
     63     //【6】窗口类的注销
     64     UnregisterClass(L"ForTheDreamOfGameDevelop", wndClass.hInstance);  //程序准备结束,注销窗口类
     65     return 0;  
     66 }
     67 
     68 LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )      
     69 {
     70     PAINTSTRUCT paintStruct;    //定义一个PAINTSTRUCT结构体来记录一些绘制信息
     71 
     72     switch( message )                        //switch语句开始
     73     {
     74     case WM_PAINT:                        // 若是客户区重绘消息
     75         g_hdc=BeginPaint(hwnd,&paintStruct);    //指定窗口进行绘图工作的准备,并将和绘图有关的信息填充到paintstruct结构体中
     76         Game_Paint(hwnd);
     77         EndPaint(hwnd,&paintStruct);    //EndPaint函数标记指定窗口的绘画过程结束
     78         ValidateRect(hwnd, NULL);        // 更新客户区的显示
     79         break;                                    //跳出该switch语句
     80 
     81     case WM_KEYDOWN:                // 若是键盘按下消息
     82         if (wParam == VK_ESCAPE)    // 如果被按下的键是ESC
     83             DestroyWindow(hwnd);        // 销毁窗口, 并发送一条WM_DESTROY消息
     84         break;                                    //跳出该switch语句
     85 
     86     case WM_DESTROY:                //若是窗口销毁消息
     87         PostQuitMessage( 0 );        //向系统表明有个线程有终止请求。用来响应WM_DESTROY消息
     88         break;                                //跳出该switch语句
     89 
     90     default:                                    //若上述case条件都不符合,则执行该default语句
     91         return DefWindowProc( hwnd, message, wParam, lParam );        //调用缺省的窗口过程
     92     }
     93     return 0;            //正常退出
     94 }
     95 
     96 //初始化函数,进行一些简单的初始化
     97 BOOL Game_Init(HWND hwnd)
     98 {
     99     g_hdc = GetDC(hwnd);  //获取设备环境句柄
    100 
    101     //-----【位图绘制四步曲之一:加载位图】-----
    102     //从文件加载3张位图
    103     g_hBackGround = (HBITMAP)LoadImage(NULL,L"bg.bmp",IMAGE_BITMAP,WINDOW_WIDTH,WINDOW_HEIGHT,LR_LOADFROMFILE);   
    104     g_hCharacter1 = (HBITMAP)LoadImage(NULL,L"character1.bmp",IMAGE_BITMAP,640,579,LR_LOADFROMFILE);  
    105     g_hCharacter2 =  (HBITMAP)LoadImage(NULL,L"character2.bmp",IMAGE_BITMAP,800,584,LR_LOADFROMFILE);
    106 
    107     //-----【位图绘制四步曲之二:建立兼容DC】-----
    108     g_mdc = CreateCompatibleDC(g_hdc);    //建立兼容设备环境的内存DC
    109 
    110     Game_Paint(hwnd);
    111     ReleaseDC(hwnd,g_hdc);  //释放设备环境
    112     return TRUE;
    113 }
    114 
    115 //绘制函数
    116 VOID Game_Paint(HWND hwnd)
    117 {
    118     //先贴上背景图
    119     SelectObject(g_mdc,g_hBackGround);
    120     BitBlt(g_hdc,0,0,WINDOW_WIDTH,WINDOW_HEIGHT,g_mdc,0,0,SRCCOPY);    //采用BitBlt函数在g_hdc中先贴上背景图
    121 
    122     //用透明遮罩法绘制出第一个人物
    123     SelectObject(g_mdc,g_hCharacter1);
    124     BitBlt(g_hdc,50,WINDOW_HEIGHT-579,320,640,g_mdc,320,0,SRCAND);//透明遮罩法第一步,即将屏蔽图与背景图做"AND"运算 
    125     BitBlt(g_hdc,50,WINDOW_HEIGHT-579,320,640,g_mdc,0,0,SRCPAINT);//透明遮罩法第二步,即将前景图与背景图做"OR"运算
    126 
    127     //用透明遮罩法绘制出第二个人物
    128     SelectObject(g_mdc,g_hCharacter2);
    129     BitBlt(g_hdc,450,WINDOW_HEIGHT-584,400,584,g_mdc,400,0,SRCAND);//透明遮罩法第一步,即将屏蔽图与背景图做"AND"运算
    130     BitBlt(g_hdc,450,WINDOW_HEIGHT-584,400,584,g_mdc,0,0,SRCPAINT);//透明遮罩法第二步,即将前景图与背景图做"OR"运算
    131 }
    132 
    133 //清理资源
    134 BOOL Game_CleanUp(HWND hwnd)
    135 {
    136     //释放资源对象
    137     DeleteObject(g_hBackGround);
    138     DeleteObject(g_hCharacter2);
    139     DeleteObject(g_hCharacter1);
    140     DeleteDC(g_mdc);
    141     return TRUE;
    142 }
    View Code

    透明彩色法

    利用在贴图时可以设置某种颜色为透明色的函数,比如TransparentBlt函数,AlphaBlend函数

    示例程序(貌似有问题,暂且不贴出了)


    第6章 动画技术

    首先是使用定时器,通过调用SetTimer来创建一个定时器,每隔指定的时间间隔给我们的程序发送WM_TIMER消息。

    示例程序:

      1 #include <windows.h>
      2 #include <tchar.h>//使用swprintf_s函数所需的头文件
      3 
      4 #pragma  comment(lib,"Msimg32.lib")  //添加使用TransparentBlt函数所需的库文件
      5 
      6 #define WINDOW_WIDTH    800                            //为窗口宽度定义的宏,以方便在此处修改窗口宽度
      7 #define WINDOW_HEIGHT    600                            //为窗口高度定义的宏,以方便在此处修改窗口高度
      8 #define WINDOW_TITLE    L"【致我们永不熄灭的游戏开发梦想】程序核心框架"        //为窗口标题定义的宏
      9 
     10 HDC    g_hdc=NULL,g_mdc=NULL;       //全局设备环境句柄
     11 HBITMAP    g_hSprite[12];     //声明位图数组用来储存各张人物位图
     12 int    g_iNum=0;         //"g_iNum"变量用来记录目前显示的图号
     13 
     14 LRESULT CALLBACK    WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );  //窗口过程函数
     15 BOOL Game_Init(HWND hwnd); //在此函数中进行资源的初始化
     16 VOID Game_Paint(HWND hwnd); //进行绘图代码的书写
     17 BOOL Game_CleanUp(HWND hwnd); //资源的清理
     18 
     19 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nShowCmd)
     20 {
     21     //【1】窗口创建四步曲之一:开始设计一个完整的窗口类
     22     WNDCLASSEX wndClass = { 0 };                            //用WINDCLASSEX定义了一个窗口类,{0}用来初始化结构体
     23     wndClass.cbSize = sizeof( WNDCLASSEX ) ;            //设置结构体的字节数大小
     24     wndClass.style = CS_HREDRAW | CS_VREDRAW;    //设置窗口的样式
     25     wndClass.lpfnWndProc = WndProc;                    //设置指向窗口过程函数的指针
     26     wndClass.cbClsExtra  = 0;                                //窗口类的附加内存,取0就可以了
     27     wndClass.cbWndExtra  = 0;                            //窗口的附加内存,依然取0就行了
     28     wndClass.hInstance = hInstance;                        //指定包含窗口过程的程序的实例句柄。
     29     wndClass.hIcon=(HICON)::LoadImage(NULL,L"icon.ico",IMAGE_ICON,0,0,LR_DEFAULTSIZE|LR_LOADFROMFILE);  //本地加载自定义ico图标
     30     wndClass.hCursor = LoadCursor( NULL, IDC_ARROW );    //指定窗口类的光标句柄。
     31     wndClass.hbrBackground=(HBRUSH)GetStockObject(GRAY_BRUSH);  //为hbrBackground成员指定一个灰色画刷句柄    
     32     wndClass.lpszMenuName = NULL;                        //用一个以空终止的字符串,指定菜单资源的名字。
     33     wndClass.lpszClassName = L"ForTheDreamOfGameDevelop";        //用一个以空终止的字符串,指定窗口类的名字。
     34 
     35     //【2】窗口创建四步曲之二:注册窗口类
     36     if( !RegisterClassEx( &wndClass ) )                //设计完窗口后,需要对窗口类进行注册,这样才能创建该类型的窗口
     37         return -1;        
     38 
     39     //【3】窗口创建四步曲之三:正式创建窗口
     40     HWND hwnd = CreateWindow( L"ForTheDreamOfGameDevelop",WINDOW_TITLE,        //喜闻乐见的创建窗口函数CreateWindow
     41         WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH,
     42         WINDOW_HEIGHT, NULL, NULL, hInstance, NULL );
     43 
     44     //【4】窗口创建四步曲之四:窗口的移动、显示与更新
     45     MoveWindow(hwnd,250,80,WINDOW_WIDTH,WINDOW_HEIGHT,true);        //调整窗口显示时的位置,使窗口左上角位于(250,80)处
     46     ShowWindow( hwnd, nShowCmd );    //调用ShowWindow函数来显示窗口,第二个参数用于指定窗口的显示状态
     47     UpdateWindow(hwnd);                        //对窗口进行更新,就像我们买了新房子要装修一样
     48 
     49     //游戏资源的初始化,若初始化失败,弹出一个消息框,并返回FALSE
     50     if(!(Game_Init(hwnd)))
     51     {
     52         MessageBox(hwnd,L"资源初始化失败",L"消息窗口",0);
     53         return FALSE;
     54     }
     55 
     56     //【5】消息循环过程
     57     MSG msg = { 0 };        //定义并初始化msg
     58     while( msg.message != WM_QUIT )            //使用while循环,如果消息不是WM_QUIT消息,就继续循环
     59     {
     60         if( PeekMessage( &msg, 0, 0, 0, PM_REMOVE ) )   //查看应用程序消息队列,有消息时将队列中的消息派发出去。
     61         {
     62             TranslateMessage( &msg );        //将虚拟键消息转换为字符消息
     63             DispatchMessage( &msg );            //分发一个消息给窗口程序。
     64         }
     65     }
     66 
     67     //【6】窗口类的注销
     68     UnregisterClass(L"ForTheDreamOfGameDevelop", wndClass.hInstance);  //程序准备结束,注销窗口类
     69     return 0;  
     70 }
     71 
     72 LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )      
     73 {
     74     PAINTSTRUCT paintStruct;    //定义一个PAINTSTRUCT结构体来记录一些绘制信息
     75 
     76     switch( message )                        //switch语句开始
     77     {
     78     case WM_TIMER:                        //定时器消息
     79         Game_Paint(hwnd);                //调用Game_Paint()函数进行窗口绘图
     80         break;                                    //跳出该switch语句;                                    //跳出该switch语句
     81 
     82     case WM_KEYDOWN:                // 若是键盘按下消息
     83         if (wParam == VK_ESCAPE)    // 如果被按下的键是ESC
     84             DestroyWindow(hwnd);        // 销毁窗口, 并发送一条WM_DESTROY消息
     85         break;                                    //跳出该switch语句
     86 
     87     case WM_DESTROY:                //若是窗口销毁消息
     88         Game_CleanUp(hwnd);            //调用自定义的资源清理函数Game_CleanUp()进行退出前的资源清理
     89         PostQuitMessage( 0 );        //向系统表明有个线程有终止请求。用来响应WM_DESTROY消息
     90         break;                                //跳出该switch语句
     91 
     92     default:                                    //若上述case条件都不符合,则执行该default语句
     93         return DefWindowProc( hwnd, message, wParam, lParam );        //调用缺省的窗口过程
     94     }
     95     return 0;            //正常退出
     96 }
     97 
     98 //初始化函数,进行一些简单的初始化
     99 BOOL Game_Init(HWND hwnd)
    100 {
    101     g_hdc = GetDC(hwnd);  //获取设备环境句柄
    102 
    103     wchar_t   filename[20];
    104     //载入各个萝莉位图
    105     for(int i=0;i<12;i++)      
    106     {
    107         memset(filename, 0, sizeof(filename));  //filename的初始化
    108         swprintf_s(filename,L"%d.bmp",i);  //调用swprintf_s函数,“组装”出对应的图片文件名称
    109         g_hSprite[i] = (HBITMAP)LoadImage(NULL,filename,IMAGE_BITMAP,WINDOW_WIDTH,WINDOW_HEIGHT,LR_LOADFROMFILE);
    110     }
    111     //-----【位图绘制四步曲之二:建立兼容DC】-----
    112     g_mdc = CreateCompatibleDC(g_hdc);    //建立兼容设备环境的内存DC
    113 
    114     g_iNum = 0;                     //设置初始的显示图号为"0"
    115     SetTimer(hwnd,1,90,NULL);   //建立定时器,间隔0.09秒发出消息,第四个参数取NULL表示我们会在消息处理函数中对WM_TIMER消息添加相应的代码
    116 
    117     Game_Paint(hwnd);
    118     return TRUE;
    119 }
    120 
    121 //绘制函数
    122 VOID Game_Paint(HWND hwnd)
    123 {
    124     //处理图号
    125     if(g_iNum == 11)               //判断是否超过最大图号,若超过最大图号“12”,则将显示图号重设为"0"。
    126         g_iNum = 0;               
    127 
    128     //依据图号来贴图
    129     SelectObject(g_mdc,g_hSprite[g_iNum]);//根据图号选入对应的位图
    130     BitBlt(g_hdc,0,0,WINDOW_WIDTH,WINDOW_HEIGHT,g_mdc,0,0,SRCCOPY);         //以目前图号进行窗口贴图
    131 
    132     //图号自增
    133     g_iNum++;                    //将“g_iNum”值加1,为下一次要显示的图号
    134 }
    135 
    136 //清理资源
    137 BOOL Game_CleanUp(HWND hwnd)
    138 {
    139     KillTimer(hwnd,1);   //删除所建立的定时器  
    140     //释放资源对象
    141     for(int i=0;i<12;i++)
    142         DeleteObject(g_hSprite[i]);
    143     DeleteDC(g_mdc);
    144     ReleaseDC(hwnd,g_hdc);  //释放设备环境
    145     return TRUE;
    146 }
    View Code

    这样就能连续切换一组图片,形成了动画效果。

    游戏循环技术是目前WIndows游戏中普遍采用的动画显示技术。

    透明动画

    就是透明贴图在加上游戏循环来显示动画的技巧

    排序贴图

    示例程序:

      1 #include <windows.h>
      2 #include <tchar.h>//使用swprintf_s函数所需的头文件
      3 #include  <time.h> //使用获取系统时间time()函数需要包含的头文件
      4 
      5 #pragma  comment(lib,"Msimg32.lib")        //添加使用TransparentBlt函数所需的库文件
      6 
      7 //-----------------------------------【宏定义部分】--------------------------------------------
      8 //    描述:定义一些辅助宏
      9 //------------------------------------------------------------------------------------------------
     10 #define WINDOW_WIDTH    800                            //为窗口宽度定义的宏,以方便在此处修改窗口宽度
     11 #define WINDOW_HEIGHT    600                            //为窗口高度定义的宏,以方便在此处修改窗口高度
     12 #define WINDOW_TITLE        L"【致我们永不熄灭的游戏开发梦想】游戏动画显示技术之 排序贴图"    //为窗口标题定义的宏
     13 #define SPRITE_NUMBER 30  //定义宏SPRITE_NUMBER,表示画面上要出现的人物数目,在此设定为30个
     14 
     15 //-----------------------------------【全局结构体定义部分】-------------------------------------
     16 //    描述:全局结构体定义
     17 //------------------------------------------------------------------------------------------------
     18 struct Sprites        //定义sprite结构,代表画面上的人物,其结构成员x和y为贴图坐标,direction为目前人物的移动方向
     19 {
     20     int x,y;            //x和y为贴图坐标
     21     int direction; // direction为目前人物的移动方向
     22 }; 
     23 
     24 //-----------------------------------【全局变量声明部分】-------------------------------------
     25 //    描述:全局变量的声明
     26 //------------------------------------------------------------------------------------------------
     27 HDC            g_hdc=NULL,g_mdc=NULL,g_bufdc=NULL;      //全局设备环境句柄,两个全局内存DC句柄
     28 HBITMAP        g_hSprite[4],g_hBackGround;                                //声明位图数组用来储存各张人物位图
     29 DWORD        g_tPre=0,g_tNow=0;                    //声明l两个函数来记录时间,g_tPre记录上一次绘图的时间,g_tNow记录此次准备绘图的时间
     30 int            g_iPicNum=0,g_iX=0,g_iY=0;                //g_iPicNum用来记录图号,g_iX,g_iY分别记录贴图的横纵坐标            
     31 Sprites        Sprite[SPRITE_NUMBER];   //按照SPRITE_NUMBER的值建立数组Sprite[]
     32 
     33 //-----------------------------------【全局函数声明部分】-------------------------------------
     34 //    描述:全局函数声明,防止“未声明的标识”系列错误
     35 //------------------------------------------------------------------------------------------------
     36 LRESULT CALLBACK    WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam );//窗口过程函数
     37 BOOL                        Game_Init(HWND hwnd);            //在此函数中进行资源的初始化
     38 VOID                            Game_Paint( HWND hwnd);        //在此函数中进行绘图代码的书写
     39 BOOL                        Game_CleanUp(HWND hwnd );    //在此函数中进行资源的清理
     40 
     41 //-----------------------------------【WinMain( )函数】--------------------------------------
     42 //    描述:Windows应用程序的入口函数,我们的程序从这里开始
     43 //------------------------------------------------------------------------------------------------
     44 int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nShowCmd)
     45 {
     46     //【1】窗口创建四步曲之一:开始设计一个完整的窗口类
     47     WNDCLASSEX wndClass = { 0 };                            //用WINDCLASSEX定义了一个窗口类
     48     wndClass.cbSize = sizeof( WNDCLASSEX ) ;            //设置结构体的字节数大小
     49     wndClass.style = CS_HREDRAW | CS_VREDRAW;    //设置窗口的样式
     50     wndClass.lpfnWndProc = WndProc;                    //设置指向窗口过程函数的指针
     51     wndClass.cbClsExtra        = 0;                                //窗口类的附加内存,取0就可以了
     52     wndClass.cbWndExtra        = 0;                            //窗口的附加内存,依然取0就行了
     53     wndClass.hInstance = hInstance;                        //指定包含窗口过程的程序的实例句柄。
     54     wndClass.hIcon=(HICON)::LoadImage(NULL,L"icon.ico",IMAGE_ICON,0,0,LR_DEFAULTSIZE|LR_LOADFROMFILE);  //本地加载自定义ico图标
     55     wndClass.hCursor = LoadCursor( NULL, IDC_ARROW );    //指定窗口类的光标句柄。
     56     wndClass.hbrBackground=(HBRUSH)GetStockObject(WHITE_BRUSH);  //为hbrBackground成员指定一个白色画刷句柄    
     57     wndClass.lpszMenuName = NULL;                        //用一个以空终止的字符串,指定菜单资源的名字。
     58     wndClass.lpszClassName = L"ForTheDreamOfGameDevelop";        //用一个以空终止的字符串,指定窗口类的名字。
     59 
     60     //【2】窗口创建四步曲之二:注册窗口类
     61     if( !RegisterClassEx( &wndClass ) )                //设计完窗口后,需要对窗口类进行注册,这样才能创建该类型的窗口
     62         return -1;        
     63 
     64     //【3】窗口创建四步曲之三:正式创建窗口
     65     HWND hwnd = CreateWindow( L"ForTheDreamOfGameDevelop",WINDOW_TITLE,                //喜闻乐见的创建窗口函数CreateWindow
     66         WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH,
     67         WINDOW_HEIGHT, NULL, NULL, hInstance, NULL );
     68 
     69     //【4】窗口创建四步曲之四:窗口的移动、显示与更新
     70     MoveWindow(hwnd,250,80,WINDOW_WIDTH,WINDOW_HEIGHT,true);        //调整窗口显示时的位置,使窗口左上角位于(250,80)处
     71     ShowWindow( hwnd, nShowCmd );    //调用ShowWindow函数来显示窗口
     72     UpdateWindow(hwnd);                        //对窗口进行更新,就像我们买了新房子要装修一样
     73 
     74     //游戏资源的初始化,若初始化失败,弹出一个消息框,并返回FALSE
     75     if (!Game_Init (hwnd)) 
     76     {
     77         MessageBox(hwnd, L"资源初始化失败", L"消息窗口", 0); //使用MessageBox函数,创建一个消息窗口
     78         return FALSE;
     79     }
     80     PlaySound(L"OrcTheme.wav", NULL, SND_FILENAME | SND_ASYNC|SND_LOOP); //循环播放背景音乐 
     81 
     82     //【5】消息循环过程
     83     MSG msg = { 0 };                //定义并初始化msg
     84     while( msg.message != WM_QUIT )        //使用while循环,如果消息不是WM_QUIT消息,就继续循环
     85     {
     86         if( PeekMessage( &msg, 0, 0, 0, PM_REMOVE ) )   //查看应用程序消息队列,有消息时将队列中的消息派发出去。
     87         {
     88             TranslateMessage( &msg );        //将虚拟键消息转换为字符消息
     89             DispatchMessage( &msg );            //分发一个消息给窗口程序。
     90         }
     91         else
     92         {
     93             g_tNow = GetTickCount();   //获取当前系统时间
     94             if(g_tNow-g_tPre >= 150)        //当此次循环运行与上次绘图时间相差0.1秒时再进行重绘操作
     95                 Game_Paint(hwnd);
     96         }
     97 
     98     }
     99 
    100     //【6】窗口类的注销
    101     UnregisterClass(L"ForTheDreamOfGameDevelop", wndClass.hInstance);  //程序准备结束,注销窗口类
    102     return 0;  
    103 }
    104 
    105 //-----------------------------------【WndProc( )函数】--------------------------------------
    106 //    描述:窗口过程函数WndProc,对窗口消息进行处理
    107 //------------------------------------------------------------------------------------------------
    108 LRESULT CALLBACK WndProc( HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam )      
    109 {
    110 
    111     switch( message )                        //switch语句开始
    112     {
    113 
    114     case WM_KEYDOWN:                    // 若是键盘按下消息
    115         if (wParam == VK_ESCAPE)    // 如果被按下的键是ESC
    116             DestroyWindow(hwnd);        // 销毁窗口, 并发送一条WM_DESTROY消息
    117         break;                                    //跳出该switch语句
    118 
    119     case WM_DESTROY:                    //若是窗口销毁消息
    120         Game_CleanUp(hwnd);            //调用自定义的资源清理函数Game_CleanUp()进行退出前的资源清理
    121         PostQuitMessage( 0 );            //向系统表明有个线程有终止请求。用来响应WM_DESTROY消息
    122         break;                                    //跳出该switch语句
    123 
    124     default:                                        //若上述case条件都不符合,则执行该default语句
    125         return DefWindowProc( hwnd, message, wParam, lParam );        //调用缺省的窗口过程
    126     }
    127 
    128     return 0;                                    //正常退出
    129 }
    130 
    131 
    132 //-----------------------------------【BubSort( )函数】--------------------------------------
    133 //    描述:进行气泡法排序
    134 //------------------------------------------------------------------------------------------------
    135 VOID        BubSort(int n)
    136 {
    137     int i,j;
    138     bool f;
    139     Sprites tmp;
    140 
    141     for(i=0;i<n-1;i++)
    142     {
    143         f = false;
    144         for(j=0;j<n-i-1;j++)
    145         {
    146             if(Sprite[j+1].y < Sprite[j].y)
    147             {
    148                 tmp = Sprite[j+1];
    149                 Sprite[j+1] = Sprite[j];
    150                 Sprite[j] = tmp;
    151                 f = true;
    152             }
    153         }
    154         if(!f)
    155             break;
    156     }
    157 }
    158 
    159 
    160 
    161 //-----------------------------------【Game_Init( )函数】--------------------------------------
    162 //    描述:初始化函数,进行一些简单的初始化
    163 //------------------------------------------------------------------------------------------------
    164 BOOL Game_Init( HWND hwnd )
    165 {
    166     srand((unsigned)time(NULL));      //用系统时间初始化随机种子
    167     HBITMAP bmp;
    168 
    169     g_hdc = GetDC(hwnd);  
    170     g_mdc = CreateCompatibleDC(g_hdc);  //创建一个和hdc兼容的内存DC
    171     g_bufdc = CreateCompatibleDC(g_hdc);//再创建一个和hdc兼容的缓冲DC
    172     bmp = CreateCompatibleBitmap(g_hdc,WINDOW_WIDTH,WINDOW_HEIGHT); //建一个和窗口兼容的空的位图对象
    173 
    174     SelectObject(g_mdc,bmp);//将空位图对象放到mdc中
    175 
    176     //加载各张跑动图及背景图
    177     g_hBackGround= (HBITMAP)LoadImage(NULL,L"bg.bmp",IMAGE_BITMAP,WINDOW_WIDTH,WINDOW_HEIGHT,LR_LOADFROMFILE);
    178     g_hSprite[0] = (HBITMAP)LoadImage(NULL,L"11.bmp",IMAGE_BITMAP,384,96,LR_LOADFROMFILE);
    179     g_hSprite[1] = (HBITMAP)LoadImage(NULL,L"22.bmp",IMAGE_BITMAP,384,96,LR_LOADFROMFILE);
    180     g_hSprite[2] = (HBITMAP)LoadImage(NULL,L"33.bmp",IMAGE_BITMAP,384,96,LR_LOADFROMFILE);
    181     g_hSprite[3] = (HBITMAP)LoadImage(NULL,L"44.bmp",IMAGE_BITMAP,384,96,LR_LOADFROMFILE);
    182 
    183 
    184     //设定初始的贴图坐标都为窗口内的任意坐标,初始的移动方向都为向左。
    185     for(int i=0;i<SPRITE_NUMBER;i++)
    186     {
    187         Sprite[i].direction = 3;    //起始方向
    188         Sprite[i].x = rand()%WINDOW_WIDTH;       //贴图的起始X坐标
    189         Sprite[i].y = rand()%WINDOW_HEIGHT;    //贴图的起始Y坐标
    190     }
    191 
    192     Game_Paint(hwnd);
    193     return TRUE;
    194 }
    195 
    196 //-----------------------------------【Game_Paint( )函数】--------------------------------------
    197 //    描述:绘制函数,在此函数中进行绘制操作
    198 //--------------------------------------------------------------------------------------------------
    199 VOID Game_Paint( HWND hwnd )
    200 {
    201     if(g_iPicNum == 4)        //判断是否超过最大图号,若超过最大图号“3”,则将显示图号重设为"0"。
    202         g_iPicNum = 0;
    203 
    204     //在mdc中贴上背景图
    205     SelectObject(g_bufdc,g_hBackGround);
    206     BitBlt(g_mdc,0,0,WINDOW_WIDTH,WINDOW_HEIGHT,g_bufdc,0,0,SRCCOPY);
    207 
    208     BubSort(SPRITE_NUMBER);    //贴上人物图之前调用BubSort()函数进行排序
    209 
    210     for(int i=0;i<SPRITE_NUMBER;i++)
    211     {
    212         SelectObject(g_bufdc,g_hSprite[Sprite[i].direction]);
    213         TransparentBlt(g_mdc,Sprite[i].x,Sprite[i].y,96,96,g_bufdc,g_iPicNum*96,0,96,96,RGB(0,0,0));//采用TransparentBlt透明色彩法
    214     }
    215 
    216     //将最后的画面显示在窗口中
    217     BitBlt(g_hdc,0,0,WINDOW_WIDTH,WINDOW_HEIGHT,g_mdc,0,0,SRCCOPY);
    218 
    219 
    220     g_tPre = GetTickCount();     //记录此次绘图时间
    221     g_iPicNum++;
    222 
    223 
    224     //下面这个for循环,决定每一只精灵下一次的移动方向及贴图坐标
    225     for(int i=0;i<SPRITE_NUMBER;i++)
    226     {
    227         switch(rand()%4)          //随机数除以4的余数来决定下次移动方向,余数0,1,2,3分别代表上,下,左,右
    228         {
    229         case 0:                         //
    230             Sprite[i].y -= 20;
    231             //在计算出新的贴图坐标之后,还需判断此新的坐标会不会使得人物贴图超出窗口边界,若超出,则将该方向上的坐标设定为刚好等于临界值
    232             if(Sprite[i].y < 0)
    233                 Sprite[i].y = 0;
    234             Sprite[i].direction = 0;
    235             break;
    236             //其他方向按照和上面相同的方法计算
    237         case 1:        //
    238             Sprite[i].y += 20;
    239             if(Sprite[i].y > WINDOW_HEIGHT-100)
    240                 Sprite[i].y = WINDOW_HEIGHT-100;
    241             Sprite[i].direction = 1;
    242             break;
    243         case 2:                        //
    244             Sprite[i].x-= 20;
    245             if(Sprite[i].x < 0)
    246                 Sprite[i].x = 0;
    247             Sprite[i].direction = 2;
    248             break;
    249         case 3:                        //
    250             Sprite[i].x+= 20;
    251 
    252             if(Sprite[i].x >WINDOW_WIDTH-100)
    253                 Sprite[i].x = WINDOW_WIDTH-100;
    254             Sprite[i].direction = 3;
    255             break;
    256         }
    257     }
    258 }
    259 
    260 //-----------------------------------【Game_CleanUp( )函数】--------------------------------
    261 //    描述:资源清理函数,在此函数中进行程序退出前资源的清理工作
    262 //---------------------------------------------------------------------------------------------------
    263 BOOL Game_CleanUp( HWND hwnd )
    264 {
    265     //释放资源对象
    266     DeleteObject(g_hBackGround);
    267     for (int i=0;i<4;i++)
    268     {
    269         DeleteObject(g_hSprite[i]);
    270     }
    271     DeleteDC(g_bufdc);
    272     DeleteDC(g_mdc);
    273     ReleaseDC(hwnd,g_hdc);
    274     return TRUE;
    275 }
    View Code

    参考博客:

    【Visual C++】游戏开发笔记之六——游戏画面绘图(三)透明特效的制作方法

    【Visual C++】游戏开发笔记之十 基础动画显示(三) 透明动画的实现

    【Visual C++】游戏开发笔记之十一 基础动画显示(四) 排序贴图

    【Visual C++】游戏开发笔记之七——基础动画显示(一)定时器的使用

    【Visual C++】游戏开发笔记之八——基础动画显示(二)游戏循环的使用

  • 相关阅读:
    jQuery dataType指定为json的问题
    C# Post数据和接收简单示例【转】
    搜集的关于领域驱动设计(DDD)的理论知识
    WCF:(400) Bad Request
    关于SQL生成随机字符串
    如何通过禁用按钮避免jQuery.ajax重复请求
    注册自定义HTTP Handlers
    Node.js+Express on IIS
    iframe在IE下不能写cookie的解决
    node.js从全局目录里加载module
  • 原文地址:https://www.cnblogs.com/f91og/p/7146569.html
Copyright © 2011-2022 走看看