视频1 视频21 视频41 视频61 视频文章1 视频文章21 视频文章41 视频文章61 推荐1 推荐3 推荐5 推荐7 推荐9 推荐11 推荐13 推荐15 推荐17 推荐19 推荐21 推荐23 推荐25 推荐27 推荐29 推荐31 推荐33 推荐35 推荐37 推荐39 推荐41 推荐43 推荐45 推荐47 推荐49 关键词1 关键词101 关键词201 关键词301 关键词401 关键词501 关键词601 关键词701 关键词801 关键词901 关键词1001 关键词1101 关键词1201 关键词1301 关键词1401 关键词1501 关键词1601 关键词1701 关键词1801 关键词1901 视频扩展1 视频扩展6 视频扩展11 视频扩展16 文章1 文章201 文章401 文章601 文章801 文章1001 资讯1 资讯501 资讯1001 资讯1501 标签1 标签501 标签1001 关键词1 关键词501 关键词1001 关键词1501 专题2001
DirectX学习手记(-)
2025-10-05 18:14:06 责编:小OO
文档
DirectX学习手记(-)DirectX学习手记(-)

DirectX学习手记(-) HappyFire 2002/8/2题记:玩了很多的游戏,不禁萌发了自己做游戏的念头,于是7月份从网上收集了N多资料。7月20几号在家开始了闭关式的学习,一直到昨天,我的第一个地图类封装完毕,并乘胜追击到凌晨3点,做好了地图编辑器的0.9版。早上起来觉得有点累(才睡了几个小时,呵呵),于是把这些天的学习经历回忆一下,权当是休息。这个过程是一个从对游戏编程一无所知到略识其理得过程,我想对于像我这样的初学者应该有所帮助吧,至少可以少走些弯路。一. 初识DirectX在放假之前,我拜读了金点时空softboy的《圣剑英雄传--英雄救美制作手札》一文。此文简述了RPG游戏的基本原理,通俗易懂,看完此文使人觉得游戏制作并非遥不可及,强烈推荐!但此文并没有提到有关DirectX编程的方法。所以做游戏,还要先过DirectX关。于是我花了一天的时间,通读了老王翻译的《DirectX中文手册》,并分析了几个例程,在加上一个多星期的编程经历,总算有了一点感觉。1.基础中的基础既然我们讨论的是Windows平台下的游戏编程,当然要对Windows编程有所了解。我们使用的是Win32 SDK(API)编程。至于为什么不用MFC? MFC是微软对API的封装(其实何止是封装),它适用于开发有统一程序架构和界面的大型商业软件,但其复杂的机制影响了速度,这对于游戏编程是难以忍受的,因此基于C/C++的Win32API是我们必然的选择。(也听说有用VB开发的游戏,但那毕竟不是主流)。那么对于Win32 API要掌握到什么程度呢?我想只要知道WinMain、窗口类、消息循环、窗口回调函数,能编个简单的HelloWorld就行了,至于GDI只要稍作了解,而Windows的控件基本上用不到。这方面的文章很多,找几篇看看就行了。当然游戏编程不同于一般的编程,所以这其中也有些变化,在下面我会提到的。2.第一个DirectDraw例程学DirectX当然要先学习它最基本也是最重要的部分DirectDraw。DirectDraw是微软提供的Windows平台下高效的与硬件无关的图形引擎,它提供对显存的直接访问...好了,闲话少说,来看看我的第一个例程(这是在手册上的第一个例程的基础上修改而成的)://-----------------------------------//工程:helloDX//文件:helloDX.cpp//内容:第一个DirectDraw应用程序//-----------------------------------#include #include #include //全局变量LPDIRECTDRAW lpDD; //DirectDraw对象LPDIRECTDRAWSURFACE lpDDSPrimary ; //DirectDraw主表面LPDIRECTDRAWSURFACE lpDDSBack ; //后台缓冲表面char szMsg1[]="我的第一个DirectDraw程序" ;char szMsg2[]="按ESC退出" ;BOOL bActive = TRUE ;HWND hwn

d ;//函数声明LRESULT CALLBACK WinProc ( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam ) ;BOOL InitWindow ( HINSTANCE hInstance, int nCmdShow ) ;BOOL InitDDraw ( void ) ;//初始化DirectXvoid FreeDDraw ( void ) ;//释放DirectX对象void MainLoop ( void ) ;//游戏主循环//-------------------------------------------------------//函数:WinMain()//功能:Win32应用程序入口函数.进行初始化工作,处理消息循环//-------------------------------------------------------int WINAPI WinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance,LPSTR lpCmdLine, int nCmdShow ){MSG msg ;//初始化主窗口if ( !InitWindow(hInstance,nCmdShow) )return FALSE ;//初始化DirectDraw环境,并实现DirectDraw功能if ( !InitDDraw() ){MessageBox ( GetActiveWindow(), "初始化DirectDraw过程中出错!

环境并实现其功能.包括:创建DirectDraw对象,//设置显示模式,创建主表面//----------------------------------------------------------------BOOL InitDDraw (void){DDSURFACEDESC ddsd ; //表面描述DDSCAPS ddscaps ;//HDC hdc ; //设备环境句柄//创建DirectDraw对象if ( DirectDrawCreate(NULL,&lpDD,NULL)!=DD_OK )return FALSE ;//取得独占和全屏模式if ( lpDD->SetCooperativeLevel(GetActiveWindow(),DDSCL_EXCLUSIVE|DDSCL_FULLSCREEN)!=DD_OK )return FALSE ;//设置显示模式if ( lpDD->SetDisplayMode(0,480,8)!=DD_OK)return FALSE ;//填充主表面信息ddsd.dwSize = sizeof(ddsd) ;ddsd.dwFlags = DDSD_CAPS|DDSD_BACKBUFFERCOUNT ;ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE|DDSCAPS_FLIP|DDSCAPS_COMPLEX ;ddsd.dwBackBufferCount = 1 ;//创建主表面对象if ( lpDD->CreateSurface(&ddsd,&lpDDSPrimary,NULL)!=DD_OK )return FALSE ;//提取后台缓存表面指针ddscaps.dwCaps = DDSCAPS_BACKBUFFER ;if ( lpDDSPrimary->GetAttachedSurface ( &ddscaps, &lpDDSBack )!=DD_OK )return FALSE ;return TRUE ;}//-------------------------------------------------------//函数:FreeDDraw()//功能:释放所有的DirectDraw对象//-------------------------------------------------------void FreeDDraw(void){if ( lpDD!=NULL ){if ( lpDDSPrimary!=NULL ){lpDDSPrimary->Release() ;lpDDSPrimary = NULL ;}lpDD->Release() ;lpDD = NULL ;}}//-------------------------------------------------------//函数:MainLoop()//功能:游戏主循环//-------------------------------------------------------void MainLoop (void){static int i = 0;HDChdc ;//后台缓冲表面上的操作if ( lpDDSBack->GetDC(&hdc)==DD_OK ){SetBkColor ( hdc, RGB(0+i,255-i,0+i) ) ;SetTextColor ( hdc, RGB( 0+i,0+i,255-i) ) ;TextOut ( hdc, 220, 200, szMsg1, lstrlen(szMsg1) ) ;TextOut ( hdc, 280, 220, szMsg2, lstrlen(szMsg2) ) ;lpDDSBack->ReleaseDC (hdc) ;i+=10 ;if ( i>255)i=0 ;}if (lpDDSPrimary->Flip(NULL,0)!=DD_OK){//一经Flip,两个表面的指针互换!lpDDSPrimary指向后台表面,所以FreeDDraw() ;//你就看到刚才在后台表面上写的字了,而lpDDSBack指向了原来的前台主表面PostQuitMessage(0);//把它掉到后台进行操作}}3.例程详解初次看这个程序,可能会觉得有点复杂,先让我们看看这个程序能做什么。在VC++6.0中建一个名helloDX的Win32 Application工程,新建一个空白的cpp文件helloDX.cpp,把这断代码粘贴上去。先别急着运行,还要把DirectDraw库添加到工程中。方法是在菜单project中选Setting,打开project setting对话框,在右面的link选择卡里面的对象/库模块里添加ddraw.lib,确定就行了。下面运行程序,你看到了什么?我们先分析一下这个程序的结构,首先它是一个典型的Win32 API程序,有WinMain和WinProc两大块组成。但稍微有点不同的是,它对于消息循环的处理采用了Peek方式:while(1){if ( PeekMessage(&msg, NULL, 0,

0, PM_NOREMOVE) ){//如果有消息就处理消息if ( !GetMessage(&msg, NULL, 0, 0 ) ) return msg.wParam;TranslateMessage ( &msg ); DispatchMessage ( &msg );}else if(bActive){//如果程序处于激活状态,进入游戏主循环MainLoop(); }//等待消息else WaitMessage();}函数PeekMessage判断消息队列中是否有消息,如果有就处理消息,如果没有再判断程序是否激活,如果激活就进入游戏主循环,如果没有激活就什么都不做,等待消息产生。这个循环不断进行下去,直到窗口收到WM_QUIT消息。在进入这个循环之前,我们初始化了窗口(注册窗口类,建立窗口),注意在建立窗口时我们指定窗口样式为WS_POPUP,这样就不会出现窗口边框标题栏什么的了。而且窗口的大小指定为显示器屏幕的大小,因为我们要实现的是全屏的DirectDraw编程。初始化窗口之后我们初始化了DirectDraw环境并建立了DirectDraw对象(下面将详细说明),这样程序就可以使用DirectDraw进行图形输出了。下面介绍我们的主角DirectDraw。你一定注意到了程序开头的全局变量声明:LPDIRECTDRAW lpDD; //DirectDraw对象LPDIRECTDRAWSURFACE lpDDSPrimary ; //DirectDraw主表面LPDIRECTDRAWSURFACE lpDDSBack ; //后台缓冲表面这个LPDIRECTDRAW就是DirectDraw对象的类型了(我们姑且把它作为一个类型好了,其实它是一个COM接口,这个我也不怎么懂:)),程序中至少有一个LPDIRECTDRAW类型的对象,它是建立其他对象的基础,两个LPDIRECTDRAWSURFACE类型的对象被称为是DirectDraw表面。lpDD对应着你的显卡,lpDDSPrimary,lpDDSBack这样的对象对应着显存(或主存)中的一块区域。建立DirectDraw表面的时候可以指定它的类型,这里的lpDDSPrimary是主表面,也是前台你能看到的表面(它被显示到屏幕上),lpDDSBack是后台缓冲表面,它是附带于lpDDSPrimary的。当然也可以创建不带后台缓冲表面的主表面(手册的第一个例程就是),也可以创建带多个后台缓冲的主表面。在这里我介绍最最常用的带一个缓冲的主表面。建立主表面之前,我们必须先建立DirectDraw对象,就是这里的lpDD,请看InitDDraw函数的内容。函数DirectDrawCreate(NULL,&lpDD,NULL)创建了一个LPDIRECTDRAW对象,这个函数的具体用法可以查相关资料我就不在赘述了。建立lpDD后还要设置DirectDraw的环境,具体就是这里的取得独占和全屏模式和设置显示模式,注意SetDisplayMode的第三个参数8不是颜色8色,而是色深度为8位,即256色。然后是建立主表面,先要填写一个DDSURFACEDESC表面描述结构体,ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE|DDSCAPS_FLIP|DDSCAPS_COMPLEX 指出要建立的表面是主表面,且能够filp(后面再说),是带缓冲的复杂表面; ddsd.dwBackBufferCount = 1 指明缓冲表

面数为1。一般都是这样填的,具体的可以查资料。填好后就可以通过lpDD的CreateSurface方法创建主表面了。然后是后台表面...这里的代码怎么有点不同?我们不是通过填写 DDSURFACEDESC结构体,在通过CreateSurface创建后台表面的!因为后台缓冲表面是同主表面联系在一起的,主表面创建好了它就自动创建好了,我们要作的是获取它的指针以便去应用它!使用lpDDSPrimary->GetAttachedSurface,明白这里的AttachedSurface了吧!至此所有的表面创建完毕,可以用来图形操作了。(顺便提一下,还有一种表面叫离屏表面,它上面的东西不会被直接显示到屏幕上,它的作用是存放图像,然后把图像复制到后台表面上,即Blt,呵呵,以后再说...)我们在什么地方用DirectDraw呢?当然是在游戏模块中,在这个程序中是MainLoop(MainLoop每个游戏都有,这是最简单的了)。在MainLoop里面我们先是获取后台表面的设备环境句柄,然后用Windows的GDI写了几个字。再然后运用主表面的Flip方法,把前后台表面的指针互换,这样你就看到刚才写的字了。由于MainLoop是不断循环执行的,而且我们通过静态变量i改变了字符的颜色,因此你看到的就是不断变色的字符了。关于Flip一定要理解,其实就是指针互换,因此非常快!经过Flip,lpDDSPrimary指向后台表面,所以你就看到刚才在后台表面上写的字了,而lpDDSBack指向了原来的前台主表面把它掉到后台进行操作(换个颜色在写一遍),然后再Flip回去,你再看到的字颜色就变了。明白了吧? 再多说几句,我们设置了lpDD为全屏模式,只有在这种模式下才能使用Flip,如果是窗口模式就只能Blt(Blt就是复制啊)了。在程序结束之前不要忘了释放DirectDraw对象和表面对象,这里放在FreeDDraw()里面的,注意我没有释放后台表面,因为它随着主表面释放了。下载本文

显示全文
专题