欢迎来到淘文阁 - 分享文档赚钱的网站! | 帮助中心 好文档才是您的得力助手!
淘文阁 - 分享文档赚钱的网站
全部分类
  • 研究报告>
  • 管理文献>
  • 标准材料>
  • 技术资料>
  • 教育专区>
  • 应用文书>
  • 生活休闲>
  • 考试试题>
  • pptx模板>
  • 工商注册>
  • 期刊短文>
  • 图片设计>
  • ImageVerifierCode 换一换

    win32 游戏编程.ppt

    • 资源ID:70019942       资源大小:2.07MB        全文页数:82页
    • 资源格式: PPT        下载积分:15金币
    快捷下载 游客一键下载
    会员登录下载
    微信登录下载
    三方登录下载: 微信开放平台登录   QQ登录  
    二维码
    微信扫一扫登录
    下载资源需要15金币
    邮箱/手机:
    温馨提示:
    快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。
    如填写123,账号就是123,密码也是123。
    支付方式: 支付宝    微信支付   
    验证码:   换一换

     
    账号:
    密码:
    验证码:   换一换
      忘记密码?
        
    友情提示
    2、PDF文件下载后,可能会被浏览器默认打开,此种情况可以点击浏览器菜单,保存网页到桌面,就可以正常下载了。
    3、本站不支持迅雷下载,请使用电脑自带的IE浏览器,或者360浏览器、谷歌浏览器下载即可。
    4、本站资源下载后的文档和图纸-无水印,预览文档经过压缩,下载后原文更清晰。
    5、试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。

    win32 游戏编程.ppt

    WIN32 游戏编程游戏编程Author:景落西轩:景落西轩C+数值类型bool(逻辑型)char(字符或8位整数)short(16位整数)int(16位或32位整数)long(32位整数)float(32位浮点数)double(64位浮点数)long double(80位浮点数)Tip:在整数数据类型前可加上unsigned表示为无符号数,数的范围可增大一倍。变量与常量所有变量定义的前面均可加上修饰符const表示它是常量,不能在程序中改变它的值。其实如果我们不打算在程序中改变某变量的值,我们就可以把它声明为常量以防止意外改动。我们还可加上修饰符static表示此变量是静态变量,这个要举一个例子以方便说明:比如说在某一个函数内有这样一条定义:static int count=0;,那么程序执行前就会为count这个变量开辟一块固定的空间并把count的初值设为0。以后每次执行这个函数时,程序不会象普通变量那样重新为它分配空间,也就是不会改变它的位置和数值,换句话说,它的生命周期与整个程序一样。这样只要在函数中再加一句count=count+1即可统计这个函数执行了多少次。如果局部变量和全局变量重名,调用时会使用局部变量,如果一定要使用那个全局变量,调用时在变量名前加上:即可。这里建议大家尽量少用全局变量,因为它可能使程序变得混乱和难于调试。NAMESPACENamespace是一个挺有趣的东西,它的引入是为了方便我们使用相同名字的变量、常量、类(在第二章我们会接触类)或是函数。一个Namespace是这样定义的:namespace xxx/xxx是是namespace的名字的名字在在这里可以像平常一里可以像平常一样定定义各种各种东西西以后要使用某个namespace中的东西,比如说xxx中的aaa,像这样:xxx:aaa即可。不过这样好像挺麻烦的-平白无故就多出了一个xxx:。于是有了using namespace xxx;这种语句,可以帮你省下这几个字符。记住,using namespace也只是在最紧挨它的一对和符号内起作用,在所有函数之外执行的这条语句才在整个文件中有效。注意:namespace s1int a=0;namespace s2float a=0;void main()using namespace s1;using namespace s2;/a=a+1;/这句是句是错误的!因的!因为编译器此器此时无法确定无法确定a在哪个在哪个namespaces1:a=s2:a+1;/这样就是正确的就是正确的操作符与表达式在逻辑表达式中,用=表示相等,!=表示不等,比如说(4=5)为FALSE;大于等于用=表示,小于等于则是=。&表示逻辑与,|表示逻辑或,!表示逻辑非。(右移)非常好用,我们可以看到,左移和右移可以代替乘或除2的n次方的作用,而且这样做可以节省不少CPU运算时间。在程序优化中这一种方法是十分重要的,例如a*9可用(a3)+a代替(注意,+运算比(指向的类的成员)2、!(逻辑非).(位取反)-(负号)+(加1)-(减1)&(变量地址)3、*(指针所指内容)sizeof(长度计算)4、*(乘)/(除)%(取模)5、+(加)-(减)6、(位右移)7、(小于)(大于)=(大于等于)8、=(等于)!=(不等于)9、&(位与)10、(位异或)11、|(位或)12、&(逻辑与)13、|(逻辑或)14、?:(?表达式)15、=+=-=(联合操作)预编译指令(1)#include 指令该指令指示编译器将xxx.xxx文件的全部内容插入此处。若用括起文件则在系统的INCLUDE目录中寻找文件,若用括起文件则在当前目录中寻找文件,再在系统默认目录下搜索。(2)#define指令(3)#if、#else和#endif指令这些指令一般这样配合使用:#if defined(标识)/如果定如果定义了了标识要要执行的指令行的指令#else 要要执行的指令行的指令#endif在头文件中为了避免重复调用(比如说两个头文件互相包含对方),常采用这样的结构:#if!(defined XXX)/XXX为一个在你的程序中唯一的一个在你的程序中唯一的标识符,符,/每个每个头文件的文件的标识符都不符都不应相同。相同。/起起标识符的常符的常见方法是若方法是若头文件名文件名为abc.h /则标识为abc_h#define XXX真正的内容,如函数声明之真正的内容,如函数声明之类#endif结构,联合和枚举结构构结构可以把不同变量变为一个变量的成员。例如:struct S/定定义结构构Sshort hi;/结构构S的第一个成的第一个成员short lo;/结构构S的第二个成的第二个成员;S s;/定定义S类型的型的变量量s然后我们就可以像s.hi和s.lo一样使用s的成员。联合合联合可以让不同变量共享相同的一块空间,举个例子:#include using namespace std;struct Sshort hi;short lo;union MIXlongl;Ss;charc4;void main()MIX mix;mix.l=100000;coutmix.s.hiendl;coutmix.s.lo;此时mix所在的内存位置的情况是这样的:图1.2枚枚举枚举的用处是迅速定义大量常量。例如:enum YEAR/可以可以给枚枚举起一个名字起一个名字january=1,/如果不加上如果不加上=1月份将依次月份将依次为0-11,不符合我,不符合我们平平时的的习惯,所以,所以/可以加上它。可以加上它。february,march,april,may,june,july,august,september,october,november,december;控制语句控制语句判断和跳转语句(if、goto)选择语句(switch)break语句循环语句(for、while)指针、数组与字符串指针、数组与字符串C+中的字符串其实也是指针的一种,因为并没有一种基本数据类型是字符串,所谓字符串实际是一个以/0(这叫做转义符,代表一个ASCII码为0的符号)作为结束标志的一个字符指针(char*),它实际上是一个字符数组extern的作用就是告诉编译器此变量会在其它程序文件中声明。把这种外部变量声明放在头文件里,再在每个文件中都包含这个头文件,然后只要在任何一个文件中声明变量,所有文件就都可以使用这个变量了。如果不加extern,各个文件使用的变量虽然同名但内容不会统一。在各个文件中也需要先声明函数,之后才能使用它。不过这时用不着使用extern了。最后我们来看看一个简单的多文件程序的例子:/*-main.h-*/#if!(defined MAIN_H)#include using namespace std;extern int a;void print();#define MAIN_H#endif/*-main.cpp-*/#include main.hint a;void main()a=3;print();/*-function.cpp-*/#include main.hvoid print()couta;C+语法(以后再补)语法(以后再补)基本基本WINDOWS程序程序代码见备注代码见备注WINMAIN函数int PASCAL WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)第一个参数hInstance是标识该应用程序的句柄。不过句柄又是什么呢?其实就是一个指向该程序所占据的内存区域的指针,它唯一地代表了该应用程序,Windows使用它管理内存中的各种对象。当然,它十分重要。在后面的初始化程序主窗口的过程中就需要使用它作为参数。第二个参数是hPrevInstance,给它NULL吧,这个参数只是为了保持与16位Windows的应用程序的兼容性。第三个参数是lpCmdLine,是指向应用程序命令行参数字符串的指针。比如说我们运行test hello,则此参数指向的字符串为hello。最后一个参数是nCmdShow,是一个用来指定窗口显示方式的整数。关于窗口显示方式的种类,将在下面说明。注册窗口类注册窗口类 创建窗口前通常要填充一个窗口类WNDCLASS,并调用RegisterClass()对该窗口类进行注册。每个窗口都有一些基本的属性,如窗口标题栏文字、窗口大小和位置、鼠标、背景色,窗口消息处理函数(后面会讲这个函数)的名称等等。注册的过程就是将这些属性告诉系统,然后再调用CreateWindow()函数创建出窗口。(见备注)风格 含义CS_HREDRAW如果窗口宽度发生改变,重绘整个窗口CS_VREDRAW如果窗口高度发生改变,重绘整个窗口CS_DBLCLKS能感受用户在窗口中的双击消息CS_NOCLOSE禁用系统菜单中的关闭命令CS_SAVEBITS把被窗口遮掩的屏幕图像部分作为位图保存起来。当该窗口被移动时,Windows使用被保存的位图来重建屏幕图像创建窗口当窗口类注册完毕之后,我们就可以创建一个窗口,这是通过调用CreateWindow()函数完成的。窗口类中已经预先定义了窗口的一般属性,而在CreateWindow()中的参数中可以进一步指定窗口更具体的属性。下面举一个例子来说明CreatWindow()的用法:显示和更新窗口显示和更新窗口窗口创建后,并不会在屏幕上显示出来,要真正把窗口显示在屏幕上,还得使用ShowWindow()函数,其原型如下:BOOL ShowWindow(HWND hWnd,int nCmdShow);参数hWnd就是要显示的窗口的句柄。nCmdShow是窗口的显示方式,一般给它WinMain()函数得到的nCmdShow的值就可以了。常用的窗口显示方式有:ShowWindow()函数的执行优先级不高,当系统正忙着执行其它的任务时窗口不会立即显示出来。所以我们使用ShowWindow()函数后还要再调用UpdateWindow(HWND hWnd);函数以保证立即显示窗口。消息循环 在WinMain()函数中,调用InitWindow()函数成功地创建了应用程序主窗口之后,就要启动消息循环,其代码如下:for(;)if(PeekMessage(&msg,NULL,0,0,PM_REMOVE)if(msg.message=WM_QUIT)break;TranslateMessage(&msg);DispatchMessage(&msg);消息处理函数消息处理函数消息处理函数又叫窗口过程,在这个函数中,不同的消息将被switch语句分配到不同的处理程序中去。Windows的消息处理函数的原型是这样定义的:LRESULT CALLBACK WindowProc(HWND hwnd,/接收消息窗口的句柄接收消息窗口的句柄UINT uMsg,/主消息主消息值WPARAM wParam,/副消息副消息值1LPARAM lParam/副消息副消息值2);常用常用WINDOWS函数函数见备注见备注描绘游戏的画笔描绘游戏的画笔DirectDraw是DirectX的重要组成部分,它就像一支画笔,主要负责各种把各种图像显示在屏幕上,对Windows环境中的游戏非常重要。现在就让我们进入激动人心的DirectDraw部分吧。初始化DIRECTDRAW 为了告诉编译器我们需要使用DirectDraw,我们要在程序文件中#include,并把ddraw.lib和dxguid.lib加入工程。记住,做完了这些工作后DirectDraw程序才能被正常编译。简介:见备注简介:见备注DIRECTDRAW对象对象如果要使用DirectDraw,必须创建一个DirectDraw对象,它是DirectDraw接口的核心。用DirectDrawCreateEx()函数可以创建DirectDraw对象,DirectDrawCreateEx()函数是在ddraw.h中定义的,它的原型如下:HRESULT WINAPI DirectDrawCreateEx(GUID FAR*lpGUID,LPVOID*lplpDD,REFIID iid,IUnknown FAR*pUnkOuter);参数介参数介绍见备注注设置控制级和显示模式设置控制级和显示模式DirectDrawCreate函数调用成功后,lpDD已经指向了一个DirectDraw对象,它是整个DirectDraw接口的最高层领导,以后的步骤都是在它的控制之下。我们用IDirectDraw7:SetCooperativeLevel()来设置DirectDraw程序对系统的控制级。它的原型如下:HRESULT SetCooperativeLevel(HWND hWnd,DWORD dwFlags)第一个参数是窗口句柄,我们给它hWnd,使DirectDraw对象与主窗口联系上。第二个参数是控制级标志。这里使用DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN,表示我们期望DirectDraw以独占和全屏方式工作。控制级描述了DirectDraw是怎样与显示设备及系统作用的。DirectDraw控制级一般被用来决定应用程序是运行于全屏模式(必须与独占模式同时使用),还是运行于窗口模式。但DirectDraw的控制级还可设置如下两项:(1)允许按Ctrl+Alt+Del重新启动(仅用于独占模式,为DDSCL_ALLOWREBOOT)。(2)不允许对DirectDraw应用程序最小化或还原(DDSCL_NOWINDOWCHANGES)。普通的控制级(DDSCL_NORMAL)表明我们的DirectDraw应用程序将以窗口的形式运行。在这种控制级下,我们将不能改变显示器分辨率,或进行换页操作(这是一个重要的操作,在4.2节会介绍)。除此之外,我们也不能够调用那些会对显存产生激烈反应的函数,如第五章要讲的Lock()。当应用程序为全屏并且独占的控制级时,我们就可以充分的利用硬件资源了。此时其它应用程序仍可创建页面、使用DirectDraw或GDI的函数,只是无法改变显示模式。下一步我们使用IDirectDraw7:SetDisplayMode()来设置显示模式,其原形为:HRESULT SetDisplayMode(DWORD dwWidth,DWORD dwHeight,DWORD dwBPP,DWORD dwRefreshRate,DWORD dwFlags);dwWidth and dwHeight用来设置显示模式的宽度和高度。dwBPP用来设置显示模式的颜色位数。dwRefreshRate设置屏幕的刷新率,0为使用默认值。dwFlags现在唯一有效的值是DDSDM_STANDARDVGAMODE。创建页面创建页面下一步是创建一个DirectDrawSurface对象。DirectDrawSurface对象代表了一个页面。你可以把页面想象为一张张可供DirectDraw描绘的画布。页面可以有很多种表现形式,它既可以是可见的,称为主页面(Primary Surface);也可以是作换页用的不可见页面,称为后台缓存(Back Buffer),在换页后,它成为可见(换页在4.2节会讲);还有一种始终不可见的,称为离屏页面(Off-screen Surface),它的作用是存储图像。其中,最重要的页面是主页面,每个DirectDraw应用程序都必须创建至少一个主页面,一般来说它就代表着我们的屏幕。创建一个页面之前,首先需要填充一个DDSURFACEDESC2结构,它是DirectDraw Surface Description的缩写,意思是DirectDraw的页面描述。它的结构非常庞大,这里只能作一个最简单的介绍。要注意的是在填充此结构前一定要将其清空!下面是一个典型的主页面的页面描述:ddsd.dwSize=sizeof(ddsd);/给dwSize页面描述的大小面描述的大小ddsd.dwFlags=DDSD_CAPS|DDSD_BACKBUFFERCOUNT;/有后台有后台缓存存ddsd.ddsCaps.dwCaps=DDSCAPS_PRIMARYSURFACE|DDSCAPS_FLIP|DDSCAPS_COMPLEX;/为主主页面,有后台面,有后台缓存,有存,有换页链ddsd.dwBackBufferCount=1;/一个后台一个后台缓存存再看看一个普通表面的页面描述:ddsd.dwSize=sizeof(ddsd);ddsd.dwFlags=DDSD_CAPS|DDSD_WIDTH|DDSD_HEIGHT;/高、高、宽由我由我们指指定定ddsd.ddsCaps.dwCaps=DDSCAPS_OFFSCREENPLAIN;/这是离屏是离屏页面面ddsd.dwHeight=480;/高高ddsd.dwWidth=640;/宽页面描述填充完毕后,把它传递给IDirectDraw7:CreateSurface()方法即可创造页面。CreateSurface()的原形是:HRESULT CreateSurface(LPDDSURFACEDESC2 lpDDSurfaceDesc,LPDIRECTDRAWSURFACE FAR*lplpDDSurface,IUnknown FAR*pUnkOuter);CreateSurface()函数的第一个参数是被填充了页面信息的DDSURFACEDESC2结构的地址,此处为&ddsd;第二个参数是接收主页面指针的地址,此处为&lpDDSPrimary;第三个参数现在必须为NULL,为该函数所保留。如果函数调用成功,lpDDSPrimary将成为一个合法的主页面对象。由于在前面已经设置了该程序的工作模式为独占和全屏,所以,此时主页面所代表的实际上是我们的整个显示屏幕。在主页面上所绘制的图形将立即反映到我们的显示屏幕上。DirectDraw初始化函数最后创造了一个离屏页面,如果我们想创造更多的页面,由于页面描述已被填充好,只需接着它像下面这样先设置高度和宽度再创建页面即可:ddsd.dwHeight=XXX;ddsd.dwWidth=XXX;if(DD_OK!=lpDD-CreateSurface(&ddsd,&lpDDSABC,NULL)return FALSE;后台缓存和换页后台缓存和换页后台缓存和换页对形成无闪烁的动画至关重要。举一个例子,要显示一个物体在一张图片上运动,我们需要在a时刻先画物体,在b时刻把一开始被物体遮住的背景画好,最后在c时刻把物体画在新位置上。但这些操作需要一定时间,如果我们直接改主页面,那么b时刻用户就会看到画面上没有物体,但a和c时刻画面上又有物体,用户就会觉得画面有些闪烁。如何解决这个问题呢?DirectDraw 中的换页就可以帮我们这个忙。首先,我们得设置好一个换页链结构,它由一组 DirectDraw 页面组成,每一个页面都可以被轮流换页至显示屏幕。当前正好位于显示屏幕的页面叫主页面。等待换页至屏幕的页面叫后台缓存。应用程序在后台缓存上进行绘图操作,然后将此页面换页成为主页面,原来的后台缓存就显示在屏幕上了,而原来的主页面就成为了后台缓存,在一般情况下我们只需改变后台缓存的内容。所以,我们在完成了b、c两个步骤后再换页即可避免闪烁现象。我们既可以创建一个简单的双换页链结构(一个主页面和一个后台缓存),也可以创建一个有时候更快的多缓存换页链结构。一般我们只需像4.2.1节的例子那样使用双缓存换页链结构即可。换页所使用的函数是IDirectDrawSurface7:Flip()。它的原形是:HRESULT Flip(LPDIRECTDRAWSURFACE lpDDSurface,DWORD dwFlags);下面介绍它的参数:(1)lpDDSurface换页链中另一个页面的 IDirectDrawSurface7接口的地址,代表换页操作的目标页面。这个页面必须是换页链中的一员。该参数缺省值是 NULL,在这种情况下,DirectDraw 从换页链中按照前后隶属关系依次换页。(2)dwFlags换页的标志选项,常用DDFLIP_WAIT,同BltFast中的DDBLTFAST_WAIT差不多。一般我们这样即可换页:lpDDSPrimary-Flip(NULL,DDFLIP_WAIT);调入入图像像调入图像调入图像初始化DirectDraw后,要将位图(*.bmp)调入页面是非常简单的,对于普通的真彩(24位)图像我们只需用DDReLoadBitmap(页面,页面,图像名图像名.bmp)即可调入图像。这个函数在ddutil.cpp中,你需要把它和ddutil.h拷贝到你的程序的目录下,将其加入你的Project并在主程序的开头#includeddutil.h(在ChapterIV.zip中你可以找到我修改过以适应DirectDraw7的ddutil.h和ddutil.cpp)。注意,DDReLoadBitmap()函数会自动缩放图像以适应页面的大小。页面的丢失与恢复当一个DirectDraw程序被最小化时,它就丧失了对页面的控制权,如果我们的程序不知道,继续改变页面时就会发生DDERR_SURFACELOST错误。而当我们重新回到DirectDraw程序时Windows不会帮我们把页面恢复,如果我们不自己恢复页面用户就会看到黑屏。为了避免出现这种情况,我们可以写一个恢复页面的函数:void RestoreSurface()lpDD-RestoreAllSurfaces();/恢复所有恢复所有页面面ReloadBitmap();/自己的自己的调图函数,重新画上函数,重新画上页面内容面内容值得注意的是Windows也不会帮我们恢复页面的实际内容,我们要象上面的程序那样,再调用自己的调图函数才行。应该什么时候调用RestoreSurface()呢?是不是每一条改变页面的语句都要测试一下有没有发生DDERR_SURFACELOST错误呢?其实并不需要。一般游戏的引擎都是频繁刷新式,每秒钟要刷新几十次,每一次刷新必然要调用上面提到的Flip()。所以我们可以写一个FlipSurface()然后以后调用它来换页:void FlipSurface()HRESULT ddrval;ddrval=lpDDSPrimary-Flip(NULL,DDFLIP_WAIT);if(ddrval=DDERR_SURFACELOST)RestoreSurface();透明色透明色透明色(又称关键色)对实现不规则物体的移动至关重要。所谓透明色,指的就是图像传送中不会被传送的区域的颜色。比如说我们先在一个纯绿色的背景上画了一个人物,把这幅画调入一个页面,再将纯绿色设为这个页面的透明色。以后当我们进行图像传送时,只需指定传送范围为一个包括了人物的矩形,DirectDraw将只会把不规则的人物传到新的页面上而不会把纯绿色的背景一起传送。当然,人物本身不能包含纯绿色,否则就不能完整地传送了。一个页面在同一时刻只能有一种透明色,设置透明色的方法是DDSetColorKey(页面名面名,RGB(红,绿,蓝);,这里的红绿蓝即为平常我们在许多图像处理软件中看到的R/G/B值。例如DDSetColorKey(lpDDSMap,RGB(255,0,255);。因为这个函数也是ddutil提供的,所以你要确认ddutil.cpp在工程内且#include ddutil.h。注意这个函数的调用不是很快,因为它还要用一个技巧转换一下你提供的颜色,以保证在任何色彩位数下透明色均能工作。事实上,如果你使用的是32位色,我们完全可以更快速地直接设置Color Key:DDCOLORKEY ddck;ddck.dwColorSpaceLowValue=RGB(x,x,x);ddck.dwColorSpaceHighValue=ddck.dwColorSpaceLowValue;lpDDSXXX-SetColorKey(DDCKEY_SRCBLT,&ddck);图像传送图像传送用DirectDraw做游戏,最常用的函数就是图像传送(又称位块传送)函数。它的作用是在各个页面之间传送指定矩形范围内的图像,并可同时对其进行各种处理。使用IDirectDrawSurface7:Blt()和IDirectDrawSurface7:Bltfast()函数可以进行图像传送。Blt()函数功能很强大,可对图像进行缩放、旋转、镜象等操作。不过平常我们用简单但够用的Bltfast()就可以了。(见备注)图像缩放图像缩放图像缩放是一种常见的特效,功能强大的函数IDirectDrawSurface7:Blt()理所当然地提供了这种功能。执行的速度还过得去可惜效果不太好,就象用Windows中的画笔缩放图像一样。Blt函数的原形是这样的:HRESULT Blt(LPRECT lpDestRect,LPDIRECTDRAWSURFACE4 lpDDSrcSurface,LPRECT lpSrcRect,DWORD dwFlags,LPDDBLTFX lpDDBltFx);lpDDSrcSurface是源页面的指针,lpDestRect和lpSrcRect分别是目标和源页面的矩形的指针,如果两个矩形的大小不一致就会自动进行缩放。至于dwFlags嘛,按照透明色的情况给它DDBLT_KEYDEST|DDBLT_WAIT、DDBLT_KEYSRC|DDBLT_WAIT或是DDBLT_WAIT即可。最后一个参数lpDDBltFx指明了要使用的特效,可惜没什么有价值的特效(除了5.1节将讲述的填色),给它NULL吧。释放释放DIRECTDRAW对象对象一个完整的DirectDraw程序还需要在最后释放所有DirectDraw对象。为了方便这个过程,我们可以定义几个宏:#define SAFE_DELETE(p)if(p)delete(p);(p)=NULL;#define SAFE_DELETE_ARRAY(p)if(p)delete(p);(p)=NULL;#define SAFE_RELEASE(p)if(p)(p)-Release();(p)=NULL;然后可以像下面的一段程序那样释放DirectDraw对象:void FreeDDraw()SAFE_RELEASE(lpDDSPrimary);/释放主放主页面面对象象/如果如果还有有别的的页面也像面也像lpDDSPrimary一一样释放放SAFE_RELEASE(lpDD);/释放放DirectDraw对象象丰富画面的技巧丰富画面的技巧在上一章中,我们学习了不少DirectDraw的基础知识。但为了做出一个真正的有可玩性的游戏,我们还要继续学点东西。填涂颜色填涂颜色要对页面指定范围内填充某种颜色(一般是填充页面的透明色以达到清除的目的),可以利用IDirectDrawSurface7:Blt()函数。用法如下:MakeRect(x,x,x,x);/指定范指定范围DDBLTFX ddBltFx;ddBltFx.dwSize=sizeof(DDBLTFX);ddBltFx.dwFillColor=RGB(x,x,x);/要填充的要填充的颜色色lpDDS-Blt(&rect,NULL,&rect,DDBLT_WAIT|DDBLT_COLORFILL,&ddBltFx);这里顺便讲一个重要的问题,即所谓的555和565。我们经常用16位色,但16除3不是整数,那么要各用多少位来表示红、绿、蓝呢?有的显卡是三种颜色各用5位,即0rrrrrgggggbbbbb,被称为555。但其它显卡用rrrrrggggggbbbbb的形式来表示这三种颜色,因为人眼对绿色更敏感,这就是565。所以如果你初始化时把屏幕置为16位色,填色时就不能用RGB()了(但设置透明色时仍可),要写一段程序来判断显卡是555还是565再自己根据情况转换颜色。不过如果我们想填充纯红、绿、蓝、黑则不用这么麻烦,这样就可以:MakeRect(x,x,x,x);/指定范指定范围DDPIXELFORMAT ddpf;ddpf.dwSize=sizeof(ddpf);lpDDSBuffer-GetPixelFormat(&ddpf);DDBLTFX ddBltFx;ddBltFx.dwSize=sizeof(DDBLTFX);ddBltFx.dwFillColor=(WORD)ddpf.dwGBitMask;/如是如是纯红则为dwRBitMask,/纯蓝则为dwBBitMasklpDDS-Blt(&rect,NULL,&rect,DDBLT_WAIT|DDBLT_COLORFILL,&ddBltFx);如果我们想填充纯黑色,可以把dwFillColor设为0,并去掉所有与ddpf有关的语句。输出文字输出文字为了向页面输出文字,我们首先要获得页面的HDC(设备描述句柄),然后调用Windows GDI 函数向页面输出文字。由于获得句柄后将不能使用DirectDraw函数改动页面,所以输出完文字后要立刻释放句柄。HDC hdc;if(lpDDSXXX-GetDC(&hdc)=DD_OK)/拿句柄拿句柄 SetBkColor(hdc,RGB(0,0,255);/设置文字背景色,如置文字背景色,如为透明透明则把把这一句改一句改为:/SetBkMode(hdc,TRANSPARENT);SetTextColor(hdc,RGB(255,255,0);/设置文字置文字颜色色TextOut(hdc,100,400,text,strlen(text);/句柄句柄,左上角左上角X,左上角左上角Y,/文字文字(char*),文字文字长度度 lpDDSXXX-ReleaseDC(hdc);/释放句柄放句柄GDI作图作图由于DirectDraw并没有提供画点、线,圆等的语句,所以我们要借助Windows GDI函数来完成这些工作。就像输出文字时一样,我们先要获得页面的HDC:HDC hdc;lpDDSXXX-GetDC(&hdc);画点是最简单的,SetPixel(hdc,x,y,RGB(r,g,b);即可在屏幕的(x,y)坐标处画上一个指定颜色的点。如果需要画线等,我们需要创建画笔:HPEN hpen=CreatePen(PS_SOLID,5,RGB(r,g,b);CreatePen的第一个参数意义为画笔样式,常用的有PS_SOLID(普通画笔)和PS_DOT(由间断点组成的画笔,需要设置画笔宽度为1)。第二个参数是画笔的宽度,第三个参数是画笔的颜色。接着将画笔给HDC:SelectObject(hdc,hpen);移动画笔到(x1,y1):MoveToEx(hdc,x1,y1,NULL);从画图起始位置向(x2,y2)坐标处画线:LineTo(hdc,x2,y2);下面列出一些常用的画图语句,使用方法和画线差不多,设定完画笔即可使用:Rectangle(hdc,x1,y1,x2,y2);/画矩形画矩形Ellipse(hdc,x1,y1,x2,y2);/画画椭圆值得注意的是我们画的图形将由一个刷子来填充,使用最简单的单色刷子的方法是:HBRUSH hbrush=CreateSolidBrush(RGB(r,g,b);/创建刷子建刷子SelectObject(hdc,hbrush);/使用刷子使用刷子画完后,我们要记住释放HDC:lpDDSXXX-ReleaseDC(hdc);锁定页面锁定页面学完了上面的知识,还有很多特效我们是做不出来的,比如淡入淡出、半透明等,因为DirectDraw中现成的函数根本没有这些功能。当然,要做这些东西还是有办法的,使用IDirectDrawSurface7:Lock()就能让我们随心所欲,因为此函数可以允许我们直接修改页面。(见备注)程序提速程序提速上面的程序看起来好像很简单,但运行速度很可能会很慢,即使你直接用汇编重写也不会快多少。原因是读显存非常慢,写显存的速度也比写内存慢。(见备注)特殊效果特殊效果为了方便大家编游戏,这里列出了一些常用特效的制作方法。如果你想知道这些代码是如何工作的,请阅读第六章。下面的程序基于640 x480 x32位色,如果你使用的分辨率不同也很容易修改,但如果使用的色彩数不同就很麻烦了。(见备注)注)加速游戏的魔法见备注为了加速游戏,一提起汇编语言,大家也许会感到很神秘。其实如果你学起来就会发现,它并非想象中那样难。特别是内嵌汇编,由于它和C+紧密结合,使你不必考虑很多烦琐的细节(例如输入输出函数的写法),学习起来比较容易。使用内嵌汇编,特别是使用MMX指令,可以大大提高各种游戏中常见特效的速度,对于编出一个漂亮的游戏非常重要。学好汇编语言还有一个特别有趣的用处:可以观察和看懂VC+生成的汇编代码,从而更好地了解C+语言本身和优化代码。6.1 6.2clcCF=0stcCF=1cmcCF=1-CFadd a,ba=a+b (结果果过大大可可能能会会有有古古怪怪的的结果果,且置且置CF 1)adc a,ba=a+b+CF(加上加上进位位)sub a,ba=a-b (如如结果果小小于于0会会加加上上2的的16或或32次方,且置次方,且置CF 1)sbb a,ba=a-b-CF (减去退位减去退位)inc aa+dec aa-neg aa=-amul aeax=eax*a后的低后的低32位位,edx=高高32位位例:例:mov eax,234723 mov edx,12912189 mul edx;则eax=2835794967 edx=705div aeax=(edx eax)/a的商的商,edx=余数余数例:例:mov eax,12121mov edx,2 此此时(edx eax)=8589946713 mov ebx,121 div ebx;则eax=70991295 edx=18imul/idiv dest,src有有符符号号数数乘乘/除除法法,dest=dest乘乘/除除srcimul/idiv dest,s1,s2有符号数乘有符号数乘/除法,除法,dest=s1乘乘/除除s2指令指令CFZFSFOFPFAX或或BXmov ax,7896?7896add al,ah10000780eadd ah,al00110860eadd al,f2110018600add al,1234001009834mov bx,9048?9048sub bh,bl000114848sub bl,bh010014800sub bl,51010048fbsub bx,8f3410110b9c7not aa=a(注意注意not与与neg不同不同!)and a,ba=a&bor a,ba=a|bxor a,ba=ab6.3sal(也可写成也可写成shl)a,x将将a左移左移x位,位,CF=移出的那一位数移出的那一位数空位用空位用0补足足sar a,x将有符号将有符号a右移右移x位,位,CF=移出的那一位数移出的那一位数空位按空位按a的符号用的符号用0/1补足足shr a,x将无符号将无符号a右移右移x位,位,CF=移出的那一位数移出的那一位数空位用空位用0补足足rol a,x将将a循循环左移左移(左左边出去的数又从最右出去的数又从最右边回来回来)ror a,x将将a循循环右移右移(右右边出去的数又从最左出去的数又从最左边回来回来)rcl/rcr a,x把把CF放在目放在目标最左最左边然后循然后循环左左/右移右移shld a,b,x将将a左移左移x位位,空出位用空出位用b高端高端m位填充位填充例:例:shld edx,eax,16可将可将eax的高的高16位位 放入放入dx中。中。shrd a,b,x将将a右移右移x位位,空出位用空出位用b低端低端m位填充位填充6.3如果你只靠上面几章所讲述的知识编了个游戏,喜欢的人恐怕会不多,为什么?因为没有人会玩一个控制不流畅而且声音效果不佳的游戏。为了在游戏中更好地管理各种输入设备,我们需要

    注意事项

    本文(win32 游戏编程.ppt)为本站会员(qwe****56)主动上传,淘文阁 - 分享文档赚钱的网站仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知淘文阁 - 分享文档赚钱的网站(点击联系客服),我们立即给予删除!

    温馨提示:如果因为网速或其他原因下载失败请重新下载,重复下载不扣分。




    关于淘文阁 - 版权申诉 - 用户使用规则 - 积分规则 - 联系我们

    本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

    工信部备案号:黑ICP备15003705号 © 2020-2023 www.taowenge.com 淘文阁 

    收起
    展开