6.3 透明动画 透明动画是GDI游戏开发中经常会用到的基本技巧,它通过图案的连续显示及图案本身背景的透明化处理,在背景图上产生出栩栩如生的动画效果。 在第5章里,我们介绍了使位图背景透明的两套方法,分别是透明色彩法和透明遮罩法。而在上一节里我们刚刚讲解了使用游戏循环来显示动画的技巧(用定时器也可以的),而这节透明动画的内容,刚好是两者的一个综合。如果对这两方面知识有遗忘的话,可以翻到本书讲解这两方面内容的地方进行温习。 其实两套透明体系的任意一种在这里都可以使用,我们在讲解过程中和最后的示例代码里都是采用的操作起来简便的透明色彩法。 素材选择方面,我们使用的是一张国产单机游戏第一品牌《仙剑奇侠传》中第一代仙剑的主角“李逍遥”的侧面行走图,应该会勾起广大“仙剑迷”们儿时的些许回忆吧。 我们知道,透明动画制作的前提是,必须在一个暂存的内存DC上完成每一张跑动图的透明,然后再贴到窗口上,这样画面更新时才不会出现在透明贴图过程中产生的闪烁现象。 我们的“李逍遥”行走素材图的尺寸为480×108,素材中有八个人物,每个人物的尺寸为80×108,这些数据在写代码中比较关键。 实现这个程序的关键点,当然是绘制函数的写法。在我们的程序中,绘制函数为自定义的Game_ Paint()函数。 而在Game_ Paint( )函数里面我们主要实现了两个功能: 李逍遥行走图案的透明背景化。 更新贴图的坐标,实现动画效果。 下面我们先给出Game_ Paint()函数的写法: 首先,是Game_ Paint()函数中多次使用的宏定义,这样的对窗口和宽度定义的宏从某种意义上减少了硬编码: 1. //------------------------【宏定义部分】-------------------------------------- 2. // 描述:定义一些辅助宏 3. //------------------------------------------------------------------------- 4. #define WINDOW_WIDTH 800 //为窗口宽度定义的宏,以方便在此处修改窗口宽度 5. #define WINDOW_HEIGHT 600 //为窗口高度定义的宏,以方便在此处修改窗口高度 然后接着就是Game_ Paint()函数的写法: 1. //--------------------【Game_Paint( )函数】---------------------------------- 2. // 描述:绘制函数,在此函数中进行绘制操作 3. //------------------------------------------------------------------------- 4. VOID Game_Paint( HWND hwnd ) 5. { 6. if(g_iNum == 8) //判断是否超过最大图号,若超过最大图号“7”,则将显示图号重设为"0"。 7. g_iNum = 0; 8. 9. //在mdc中贴上背景图 10. SelectObject(g_bufdc,g_hBackGround); 11. BitBlt(g_mdc,0,0,WINDOW_WIDTH,WINDOW_HEIGHT,g_bufdc,0,0,SRCCOPY); 12. 13. //在mdc中进行透明处理 14. SelectObject(g_bufdc,g_hSprite); 15. TransparentBlt(g_mdc,g_iX,g_iY,60,108,g_bufdc,g_iNum*60,0,60,108, RGB(255,0,0));//采用TransparentBlt透明色彩法 16. 17. 18. //将最后的画面显示在窗口中 19. BitBlt(g_hdc,0,0,WINDOW_WIDTH,WINDOW_HEIGHT,g_mdc,0,0,SRCCOPY); 20. 21. g_tPre = GetTickCount(); //记录此次绘图时间,供下次游戏循环中判断是否已经达到画面更新操作设定的时间间隔。 22. g_iNum++; //将“g_iNum”值加1,为下一次要显示的图号 23. 24. g_iX+=10; //计算下次贴图的坐标 25. //如果贴图坐标超出窗口边缘,将其坐标置为-60 26. if(g_iX>=WINDOW_WIDTH) 27. g_iX =-60; 28. 29. } 第6~7行代码精析:作用依旧是把图号控制在0到最大值之间。 第9~19行代码精析:采用三缓冲,即有三个DC。从g_bufdc贴图到g_mdc上,并进行透明操作,再将最后的结果显示在窗口(即g_hdc)中,这样就可以避免动画的闪烁。 其中,10~11行,按照目前的图号来取出对应的李逍遥图案,然后用透明色彩法贴出来,透明色为红色RGB(255,0,0)。 第24~27行代码精析:计算下次李逍遥的贴图坐标,由于我们的程序设定动画是由右向左走动的,在Y轴坐标不变化,而X轴坐标每次向左递减10,直到李逍遥跑到左边窗口外时再将坐标设回最右边,这样可以看到“李逍遥”不断由右向左循环走动的效果。 下面我们把上面讲到的程序的其他代码也贴出来,看看这个程序的整体示例程序GDIdemo8是怎样的。 在这个示例程序中,我们用游戏循环配合透明色彩法,来实现透明动画。 程序代码片段一,全局变量声明: 1. //---------------------【全局变量声明部分】------------------------------------ 2. // 描述:全局变量的声明 3. //------------------------------------------------------------------------- 4. HDC g_hdc=NULL,g_mdc=NULL,g_bufdc=NULL; //全局设备环境句柄,两个全局内存DC句柄与 5. HBITMAP g_hSprite=NULL,g_hBackGround=NULL; //定义两个位图句柄,一个用于存储人物图,一个用于存储背景图 6. DWORD g_tPre=0,g_tNow=0; //声明l两个函数来记录时间,g_tPre记录上一次绘图的时间,g_tNow记录此次准备绘图的时间 7. int g_iNum=0,g_iX=0,g_iY=0; //g_iNum用来记录图号,g_iX,g_iY分别记录贴图的横纵坐标 程序代码片段二,Game_Init()函数: 1. //-------------------【Game_Init( )函数】--------------------------------- 2. // 描述:初始化函数,进行一些简单的初始化 3. //----------------------------------------------------------------------- 4. BOOL Game_Init( HWND hwnd ) 5. { 6. HBITMAP bmp; 7. 8. g_hdc = GetDC(hwnd); 9. g_mdc = CreateCompatibleDC(g_hdc); //创建一个和hdc兼容的内存DC 10. g_bufdc = CreateCompatibleDC(g_hdc);//再创建一个和hdc兼容的缓冲DC 11. bmp = CreateCompatibleBitmap(g_hdc,WINDOW_WIDTH,WINDOW_HEIGHT); //建一个和窗口兼容的空的位图对象 12. 13. SelectObject(g_mdc,bmp);//将空位图对象放到mdc中 14. g_hSprite = (HBITMAP)LoadImage(NULL,L"goright.bmp",IMAGE_BITMAP,480,108, LR_LOADFROMFILE); 15. g_hBackGround= (HBITMAP)LoadImage(NULL,L"bg.bmp",IMAGE_BITMAP,WINDOW_WIDTH,WINDOW_HEIGHT,LR_LOADFROMFILE); 16. 17. g_iX =0; //贴图起始X坐标 18. g_iY= 350; //贴图起始Y坐标 19. 20. Game_Paint(hwnd); 21. return TRUE; 22. } 第8~10行代码精析:三个设备环境的初始化,为三缓冲动画绘图做准备。 第11~13行代码精析:因为后面我们是在g_mdc上进行透明处理的,所以需要建一个空的位图对象把他放到g_mdc中。 第14~15行代码精析:加载李逍遥人物图案和背景图。 第17~19行代码精析:设定贴图初始坐标。 Game_Paint函数在上面讲解的时候已经贴出过,这里就不浪费篇幅再次贴出了。 接着我们来看一下运行截图: 看到运行截图,大家是不是有回到玩“仙剑奇侠传”时的那种感觉呢?
逐梦旅程:Windows游戏编程之从零开始——6.3 透明动画
书名: 逐梦旅程:Windows游戏编程之从零开始
作者: 毛星云
出版社: 清华大学出版社
出版年: 2013-9-16
页数: 679
定价: 98.00元
装帧: 平装
ISBN: 9787302337508