分享
 
 
 

DirectDraw与DirectInput游戏编程体验

王朝other·作者佚名  2008-05-19
窄屏简体版  字體: |||超大  

我想关于这个主题的文章,不算少,但也不算太多。但大多是分别介绍 DirectDraw 与 DirectInput,而并没有将其结合起来,也许你会问:“分开与合并起来并没有本质区别啊!”。其实的确没有本质区别,但那样使那些最初对游戏编程报有极大热情的爱好者感到非常失望,因为这其中的一个并不能完全满足他们的要求,并且使其感到巨大的阻力,从而失去信心。所以本文将 DirectDraw 与 DirectInput结合起来去讲一个主题就是“游戏编程”,请注意是“游戏编程”,当然这只是一个简单的桌面游戏,但这已经与先前有很大的不同了,这已不是简单的 DirectDraw或 DirectInput编程。我想你现在应该能够体会出其中的区别了。

声明:在这之前需要你具有一定的 WIN32 API 函数的知识,并且可以熟练使用。和 DirectDraw的知识,关于DirectDraw可以参见 www.frontfree.net 中的 1-3),或其它文章。最后是 c++ 语言,当然也要包括面向对象的那部分。在 Visual C++ .NET 编译环境下进行开发的。

首先 ,我们还是先简要复习一下DirectDraw的概念吧!

DirectDraw本质上是显存管理程序。它最重要的性能是允许程序员直接在显存里存储和操纵位图。它使你能够利用视频硬件bliter(位块传输器)在显存内部进行位图的blit(位块传输)。用视频硬件的blitter从显存向显存进行blit比从内存向显存更快。这在64位显卡向显存提供64位数据路径的今天显得尤其重要,硬件独立于促CPU进行位块传输操作,使得CPU得以继续工作。另外DirectDraw支持显卡的其他硬件加速特性,例如对精灵和z -buffering的硬件支持。

DirectDraw的工作原理

我们这里还是用图表方式展现给大家吧!

细心的朋友可以很明显地注意到图示中的右上角的图解中说明,表面对象有两个宽度,一个是WIDTH,一个是PITCH。WIDTH就是创建表面时所给出的那个宽度,而PITCH是表面的实际宽度,是按字节算的。在许多显卡上,PITCH和WIDTH是相等的,比如在640x480的高彩模式下,PITCH为1280。而在某些显卡上,PITCH比WIDTH要大。比如在640x480的256色模式下,当WIDTH是640时,PITCH为1024而不是640,这些显卡这样做是为了更好地进行数据对齐来提高性能或达到其它目的。所以,我们在实际编程时,为了保证程序的兼容性,必须按PITCH处理。 但这些硬件的底层问题,我们不用太关心,只要稍有了解就可以了。

下面我们再简要叙述一下,如何使用 DirectX 9.0 中提供的 DirectDraw 类库来创建对象并使用操作对象。

宏定义在先,定义删除指针和释放对象的宏

#define SAFE_DELETE(p) { if(p) { delete (p); (p)=NULL; } }

#define SAFE_RELEASE(p) { if(p) { (p)-Release(); (p)=NULL; } }

先创建一个 CDisplay 的全局对象

CDisplay就是ddutil.h中定义的类,用于处理表面之间的拷贝翻页等操作的类,再次定义一个全局变量,用于以后对指向的表面之间进行操作

CDisplay* g_pDisplay = NULL;

然后创建表面,当然可以创建很多的表面,这些表面都是离屏表面,在更新画面时,都可以用 CDisplay 类的对象中的方法,将其拷贝到后备缓冲区表面上。只要创建离屏表面,就要用到 CSurface 类。CSurface也是ddutil.h头文件中定义的类,用于对表面本身进行操作,如设置色彩键码,在此定义的图画指针。

CSurface* g_pBackSurface = NULL;

DirectX 中就一共用这两个类封装了 DirectDraw 对象的大部分操作,如果你觉得这还不能满足要求,那么你也可以在程序中用 DirectDraw API 函数编写程序,不过在本文中不再介绍。

这之后,我们会用到 InitDirectDraw 函数。这个函数是我们自己创建的。在此函数中作所有的 DirectDraw 的对象初始化工作。

HRESULT InitDirectDraw( HWND hWnd )

{

HRESULT hr; //接受返回值,其实是long型变量

LPDIRECTDRAWPALETTE pDDPal = NULL; //定义程序中的调色板

int iSprite; //定义与sprite个数有关的计数器

g_pDisplay = new CDisplay(); //动态开辟一个CDisplay类

if( FAILED( hr = g_pDisplay-CreateFullScreenDisplay( hWnd, SCREEN_WIDTH,

SCREEN_HEIGHT, SCREEN_BPP ) ) ) /*设置程序为全屏,并且 g_pDisplay 就是动态开辟一个CDisplay类的指针,而在这个类的域中,有一个DirectDraw主表面指针,和一个后备缓冲区表面的指针。在从我建议你可以先去阅读一下 ddutil.h 和 ddutil.cpp 文件。*/

{

MessageBox( hWnd, TEXT("This display card does not support 1024x768x8. "),

TEXT("DirectDraw Sample"), MB_ICONERROR | MB_OK );

return hr;

}

if( FAILED( hr = g_pDisplay-CreatePaletteFromBitmap( &pDDPal, MAKEINTRESOURCE( IDB_DIRECTX ) ) ) ) //顾名思义,就是从bmp图片中获得调色板值,并赋值在pDDPal结构指针所指向的结构体中。

return hr;

if( FAILED( hr = g_pDisplay-SetPalette( pDDPal ) ) ) //用刚才从IDB_DIRECTX中获得的调色板制来设置程序调色板

return hr;

SAFE_RELEASE( pDDPal );//释放指针,在用过后,一定要释放,这是良好的编程习惯

// 用IDB_WINXP图片创建一个表面,并用g_pBackSurface指向这个表面

if( FAILED( hr = g_pDisplay-CreateSurfaceFromBitmap(

&g_pBackSurface, MAKEINTRESOURCE( IDB_WINXP ),

SCREEN_WIDTH, SCREEN_HEIGHT ) ) )

return hr;//设置色彩键码为黑色,0代表黑色,这样在表面的拷贝过程中黑色像素的点将不会被拷贝,这样可以产生镂空效果。当然你可以任意设置关键颜色,而颜色的表示法可以用 RGB 宏定义。例如 红色:RGB( 255,0,0 ), 黑色 RGB( 255,255,255 )

if( FAILED( hr = g_pBackSurface-SetColorKey( RGB( 255,255,255 ) ) ) )

return hr;

return S_OK;

}

下面的函数是用于更新画面的。

HRESULT DisplayFrame()

{

HRESULT hr;

g_pDisplay-Clear( 0 ); //清空后备缓冲区表面

//将g_pBackSurface所指向的图片拷贝到后备缓冲区表面

g_pDisplay-Blt( 0, 0, g_pBackSurface, NULL );//最关键的地方在这里,请看下面的语句,只要我们一执行翻页操作,就可以将改动了的图像了显示在屏幕上了

if( FAILED( hr = g_pDisplay-Present() /*翻页操作*/) )

return hr;

return S_OK;

}

下面的函数是用于在程序失去焦点时调用的。

HRESULT RestoreSurfaces()

{

HRESULT hr;

LPDIRECTDRAWPALETTE pDDPal = NULL; /*当程序失去焦点,要保存当前的画面,请注意这里,g_pDisplay-GetDirectDraw()函数返回的才是真正的 DirectDraw 对象 */

if( FAILED( hr = g_pDisplay-GetDirectDraw()-RestoreAllSurfaces() ) )

return hr;//在此我们还要重新创建调色板

if( FAILED( hr = g_pDisplay-CreatePaletteFromBitmap( &pDDPal, MAKEINTRESOURCE( IDB_DIRECTX ) ) ) )

return hr;//重新设置调色板

if( FAILED( hr = g_pDisplay-SetPalette( pDDPal ) ) )

return hr;

SAFE_RELEASE( pDDPal );//重新画出图画

if( FAILED( hr = g_pLogoSurface-DrawBitmap( MAKEINTRESOURCE( IDB_WINXP ),

SPRITE_DIAMETER, SPRITE_DIAMETER ) ) )

return hr;

return S_OK;

}

下面这个函数是释放表面指针所用的。

VOID FreeDirectDraw()

{

SAFE_DELETE( g_pBackSurface );

SAFE_DELETE( g_pDisplay );

}

我们的回顾到此结束,下面我们开始本文要介绍的一个关键技术,DirectInput 的使用。

游戏编程可不仅仅是图形程序的开发工作,实际上包含了许多方面,本文所要讲述的就是关于如何使用 DirectInput 来对键盘编程的问题。

而我们为什么要选择用 DirectInput 来处理游戏中的输入问题呢?其实用 Win32 API 函数也完全可以处理这些工作,例如其中,有一个

GetAsyncKeyState() 的函数可以返回一个指定键的当前状态是按下还是松开。这个函数还能返回该指定键在上次调用 GetAsyncKeyState() 函数以后,是否被按下过。虽然这个函数听上去很不错,但需要我们自己轮换查询每个键盘的状态。而在 DirectInput 中我们已经可以脱离这些烦琐的工作,只因它的功能更强大。

由于本文重点在二者的结合,故在此只介绍 DirectInput 中比较简单的,而且最容易上手的立即模式的工作方式。

而这里我们要用到 DirectInput 的 API 函数。有人会问,为什么在 DirectDraw 中用 DirectX 提供的类库编程,而对于 DirectInput 却直接使用要用其 API 函数呢,是因为没有提供 DirectInput 的类库吗?不是!而是因为使用类库并不很方便而且不灵活。

OK,让我们开始我们游戏编程的第二部――DirectInput编程。

前面讲 DirectDraw 时,并没有提到,微软是按 COM 来设计DirectX的,所以就有了一个 DIRECTINPUT 对象来表示输入设备,而某个具体的设备由 DIRECTINPUTDEVICE 对象来表示。也许会感到很无奈,怎么游戏编程需要这么多的知识啊,其实您也无需烦恼,只要知道一下就可以了,其实这并不;影响您的设计,而且就算您不知道,也同样可以驾驭DIRECTINPUT。

实际的建立过程是先创建一个 DIRECTINPUT 对象,然后在通过此对象的 CreateDevice 方法来创建 DIRECTINPUTDEVICE 对象。

#include

#define DINPUT_BUFFERSIZE 16

LPDIRECTINPUT lpDirectInput; // DirectInput 对象实际上是一个

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有