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

来源:岁月联盟 编辑:exp 时间:2012-04-09

"透明动画”是游戏中一定会用到的基本技巧,它通过图案的连续显示及图案本身背景的透明化处理,在背景图上产生出栩栩如生的动画效果。

 


看过之前笔记的朋友们应该知道,在笔记六里我们介绍了使位图背景透明的方法,在笔记八里我们讲解了使用游戏循环显示动画的技巧,而这节笔记的内容,刚好是两者的一个综合。

 


如果有没看过之前笔记系列的朋友,为了便于理解本节的内容,可以先浏览一下之前的笔记六和笔记八,下面我给出链接。

 


【Visual C++】游戏开发笔记之六——游戏画面绘图(三)透明特效的制作方法http://www.2cto.com/kf/201204/126479.html

 


【Visual C++】游戏开发笔记之八——基础动画显示(二)游戏循环的使用http://www.2cto.com/kf/201204/126521.html

 

 

为了实现透明动画的效果,我们采用了一个如下图所示的恐龙跑动的连续图,每一张跑动图的宽高都为95*99。我们知道,透明动画制作的前提是,必须在一个暂存的内存DC上完成每一张跑动图的透明,然后再贴到窗口上,这样画面更新时才不会出现在透明贴图过程中产生的闪烁现象。

 /

 


上图中每一个小恐龙的尺寸为95*99,这个数据在写代码过程中比较关键。

 

 

 

实现这个程序的关键点,当然是MyPaint函数的写法。

而在MyPaint函数里面我们主要实现了两个功能:

1.恐龙跑动图案的透明背景化

2.更新贴图的坐标,实现动画效果

 

 

下面我们给出MyPaint函数的写法:


[cpp]
        num = 0;    //显示图号  
    x = 640;    //贴图起始X坐标  
    y = 360;    //贴图起始Y坐标  
void MyPaint(HDC hdc) 

    if(num == 8) 
        num = 0; 
 
    //在mdc中贴上背景图  
    SelectObject(bufdc,bg); 
    BitBlt(mdc,0,0,640,480,bufdc,0,0,SRCCOPY); 
 
    //在mdc中进行透明处理  
    SelectObject(bufdc,dra); 
    BitBlt(mdc,x,y,95,99,bufdc,num*95,99,SRCAND); 
    BitBlt(mdc,x,y,95,99,bufdc,num*95,0,SRCPAINT); 
 
    //将最后的画面显示在窗口中  
    BitBlt(hdc,0,0,640,480,mdc,0,0,SRCCOPY); 
 
    tPre = GetTickCount();     //记录此次绘图时间  
    num++; 
 
    x-=20;                     //计算下次贴图的坐标  
    if(x<=-95) 
        x = 640; 

        num = 0;    //显示图号
 x = 640; //贴图起始X坐标
 y = 360;    //贴图起始Y坐标
void MyPaint(HDC hdc)
{
 if(num == 8)
  num = 0;

 //在mdc中贴上背景图
 SelectObject(bufdc,bg);
 BitBlt(mdc,0,0,640,480,bufdc,0,0,SRCCOPY);

 //在mdc中进行透明处理
 SelectObject(bufdc,dra);
 BitBlt(mdc,x,y,95,99,bufdc,num*95,99,SRCAND);
 BitBlt(mdc,x,y,95,99,bufdc,num*95,0,SRCPAINT);

 //将最后的画面显示在窗口中
 BitBlt(hdc,0,0,640,480,mdc,0,0,SRCCOPY);

 tPre = GetTickCount();     //记录此次绘图时间
 num++;

 x-=20;        //计算下次贴图的坐标
 if(x<=-95)
  x = 640;
}

 

 


关键点的说明:

▲7~17行,  在mdc上进行透明操作并将最后的结果显示在窗口中。

▲13~14行,进行透明时,按照目前的图号来取出对应的跑动图案或者屏蔽图。

▲22~24行,计算下次恐龙图贴图坐标,由于我们的程序设定动画是由右向左跑动的,在Y轴坐标不变化,而X轴坐标每次向左递减20,直到图案跑到左边窗口外时再将坐标设回最右边,这样可以看到恐龙不断由右向左循环跑动的效果。

 

 

 

 


同样我们利用一个完整的实例来了解实现透明动画的具体过程:

 

 

[cpp]
#include "stdafx.h"  
 
//全局变量声明  
HINSTANCE hInst; 
HBITMAP dra,bg; 
HDC     hdc,mdc,bufdc; 
HWND    hWnd; 
DWORD   tPre,tNow; 
int     num,x,y; 
 
//全局函数声明  
ATOM                MyRegisterClass(HINSTANCE hInstance); 
BOOL                InitInstance(HINSTANCE, int); 
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM); 
void                MyPaint(HDC hdc); 
 
//***WinMain函数,程序入口点函数**************************************     
int APIENTRY WinMain(HINSTANCE hInstance, 
                     HINSTANCE hPrevInstance, 
                     LPSTR     lpCmdLine, 
                     int       nCmdShow) 

    MSG msg; 
 
    MyRegisterClass(hInstance); 
 
    //初始化  
    if (!InitInstance (hInstance, nCmdShow))  
    { 
        return FALSE; 
    } 
 
    //消息循环  
    GetMessage(&msg,NULL,NULL,NULL);  //初始化msg  
    while( msg.message!=WM_QUIT ) 
    { 
        if( PeekMessage( &msg, NULL, 0,0 ,PM_REMOVE) ) 
        { 
            TranslateMessage( &msg ); 
            DispatchMessage( &msg ); 
        } 
        else 
        { 
            tNow = GetTickCount(); 
            if(tNow-tPre >= 100) 
                MyPaint(hdc); 
        } 
    } 
 
    return msg.wParam; 

 
//****设计一个窗口类,类似填空题,使用窗口结构体*************************     
ATOM MyRegisterClass(HINSTANCE hInstance) 

    WNDCLASSEX wcex; 
 
    wcex.cbSize = sizeof(WNDCLASSEX);  
    wcex.style          = CS_HREDRAW | CS_VREDRAW; 
    wcex.lpfnWndProc    = (WNDPROC)WndProc; 
    wcex.cbClsExtra     = 0; 
    wcex.cbWndExtra     = 0; 
    wcex.hInstance      = hInstance; 
    wcex.hIcon          = NULL; 
    wcex.hCursor        = NULL; 
    wcex.hCursor        = LoadCursor(NULL, IDC_ARROW); 
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1); 
    wcex.lpszMenuName   = NULL; 
    wcex.lpszClassName  = "canvas"; 
    wcex.hIconSm        = NULL; 
 
    return RegisterClassEx(&wcex); 

 
//****初始化函数*************************************  
// 加载位图并设定各对象的初始值  
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) 

    char filename[20] = ""; 
    HBITMAP bmp; 
    hInst = hInstance; 
 
    hWnd = CreateWindow("canvas", "动画演示" , WS_OVERLAPPEDWINDOW, 
        CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); 
 
    if (!hWnd) 
    { 
        return FALSE; 
    } 
 
    MoveWindow(hWnd,10,10,640,480,true); 
    ShowWindow(hWnd, nCmdShow); 
    UpdateWindow(hWnd); 
 
    hdc = GetDC(hWnd); 
    mdc = CreateCompatibleDC(hdc); 
    bufdc = CreateCompatibleDC(hdc); 
    bmp = CreateCompatibleBitmap(hdc,640,480); 
 
    SelectObject(mdc,bmp); 
 
    dra = (HBITMAP)LoadImage(NULL,"dra.bmp",IMAGE_BITMAP,760,198,LR_LOADFROMFILE); 
    bg = (HBITMAP)LoadImage(NULL,"bg.bmp",IMAGE_BITMAP,640,480,LR_LOADFROMFILE); 
 
    num = 0;    //显示图号  
    x = 640;    //贴图起始X坐标  
    y = 360;    //贴图起始Y坐标  
 
    MyPaint(hdc); 
 
    return TRUE; 

 
//****自定义绘图函数*********************************  
// 1.恐龙跑动图案的透明背景化  
// 2.更新贴图坐标,实现动画效果  
void MyPaint(HDC hdc) 

    if(num == 8) 
        num = 0; 
 
    //在mdc中贴上背景图  
    SelectObject(bufdc,bg); 
    BitBlt(mdc,0,0,640,480,bufdc,0,0,SRCCOPY); 
 
    //在mdc中进行透明处理  
    SelectObject(bufdc,dra); 
    BitBlt(mdc,x,y,95,99,bufdc,num*95,99,SRCAND); 
    BitBlt(mdc,x,y,95,99,bufdc,num*95,0,SRCPAINT); 
 
    //将最后的画面显示在窗口中  
    BitBlt(hdc,0,0,640,480,mdc,0,0,SRCCOPY); 
 
    tPre = GetTickCount();     //记录此次绘图时间  
    num++; 
 
    x-=20;                     //计算下次贴图的坐标  
    if(x<=-95) 
        x = 640; 

 
//****消息处理函数***********************************  
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) 

    switch (message) 
    { 
        case WM_DESTROY:                    //窗口结束消息,撤销各种DC  
            DeleteDC(mdc); 
            DeleteDC(bufdc); 
            DeleteObject(dra); 
            DeleteObject(bg); 
            ReleaseDC(hWnd,hdc); 
            PostQuitMessage(0); 
            break; 
        default:                            //其他消息  
            return DefWindowProc(hWnd, message, wParam, lParam); 
   } 
   return 0; 


 这个程序的运行结果为:
 

 

 
 

笔记十到这里就结束了。


 

本节源代码请点击这里下载:  【Visual C++】Code_Note_10http://download.csdn.net/detail/zhmxy555/4175339

 


感谢一直支持【Visual C++】游戏开发笔记系列专栏的朋友们,也请大家继续关注我的博客,我一有空就会把自己的学习心得,觉得比较好的知识点写出来和大家一起分享。

精通游戏开发的路还很长很长,非常希望能和大家一起交流,共同学习和进步。

大家看过后觉得有启发的话可以顶一下这篇文章,让更多的朋友有机会看到它。也希望大家可以多留言来和我探讨编程相关的问题。
最后,谢谢大家一直的支持~~~

 

 

The end


 

摘自 枫落★流年