DirectX游戏开发入门

转载自 guigangsky
最终编辑 guigangsky

 

[文章导读] 

    今天我们要接触到令人敬畏的DirectX。它比Windows GDI要快好几倍,可用于不同的语言和多种平台

[正文]

  ☆ 简介

  今天我们要接触到令人敬畏的DirectX。它比Windows GDI要快好几倍,可用于不同的语言和多种平台,支持从绘制象素到高级3D图象,从播放声音到数字音乐,从键盘控制到反震手柄……它给你游戏编程所需的一切(有点夸张)。当然了,它是巨大的,需要好几本书才能含盖它的全部。先不要去担心我在这里所教给你之外的数不清的知识,毕竟我把你推到了起跑线上。

  阅读本章,你需要前几章的知识和C语言的知识,由于我们还要谈到组件对象模型(COM),它是面向对象系统的基础,你最好还要有一点儿C++的知识。没有也不太要紧,我在讲到这处时会照顾你的。反正你记住,使用DirectX并不需要多少C++的知识。开始吧!

  ☆ 什么是DirectX?

  DirectX是游戏制作者的API(Application Development Interface)。它是一组允许你直接控制计算机硬件设备的软件。如果你的硬件支持DirectX,并且你用硬件加速你的程序,这就意味着一个字——快。不用担心你的硬件知识,你不会真正的接触到它们。我们是通过硬件抽象层(HAL)和硬件仿真层(HEL)来保证设备无关性和让你的程序正常运行。

  DirectX由很多组件构成,每一个都有特定的用途。组件DirectDraw是最为重要的一个,因为所有的图形都要用到它,它是2D图形的引擎,3D图形也同样离不开它。DirectDraw是我们今天就要说的。其它的组件是:

  ▲ DirectSound:提供硬件和软件的声音混合与回放。

  ▲ DirectMusic:处理基于消息的音乐数据。它支持乐器数字接口(MIDI)并为创建交互式音乐提供创作工具。

  ▲ DirectPlay:使得通过调制解调器链接或通过网络来与<strong class="kgb" onmouseover="isShowAds = true;isShowAds2 = true;KeyGate_ads.Move(this,"","%u901A%u8FC7%u4E00%u4E2A%u7B80%u5355%u7684%u95EE%u5019%u7A0B%u5E8F%20HelloServer%20%u6765%u4ECB%u7ECD","-100879","应用程序","%u5F00%u53D1%u9AD8%u6027%u80FD%u7F51%u7EDC%u7A0B%u5E8F","http%3A//ibm.csdn.net/ISN_J.aspx%3Faction%3DJMP%26pointid%3D2613", event)" style="border-top-width: 0px; font-weight: normal; border-left-width: 0px; border-bottom-width: 0px; cursor: hand; color: #0000ff; border-right-width: 0px; text-decoration: underline" onclick="javascript:window.open("http://s4.17luntan.com/ClickPortal/WebClick.aspx?id=-100879&k=%u5E94%u7528%u7A0B%u5E8F&siteid=0098295a-e262-40f7-ae50-7a6fbbdb678b&url=http%3A//news.csdn.net/n/20050712/23661.html&gourl=http%3A//ibm.csdn.net/ISN_J.aspx%3Faction%3DJMP%26pointid%3D2613&parm=A448BDA1BE802ADCC983B3990A87F485039FFF1267775D5D&alliedsiteid=0");" onmouseout="isShowAds = false;isShowAds2 = false">应用程序相连成为可能。

  ▲ Direct3D:是一个三维图形包,它提供一个高级的保留模式(Retained Mode)接口,这使得你能够实现一个完整的三维图形系统。它还包含一个低级的即时模式(Immediate Mode)接口,使得应用程序获得对渲染管线的完全控制。

  ▲ DirectInput:为包括游戏杆、鼠标、键盘和游戏控制器在内的输入设备提供支持。它还为反馈游戏设备提供支持。

  ▲ DirectSetup:为DirectX提供了一个简单的安装过程。它简化了更新<strong class="kgb" onmouseover="isShowAds = false;isShowAds2 = false;isShowGg = true;InTextAds_GgLayer="_u663E_u793A";KeyGate_ads.ShowGgAds(this,"_u663E_u793A",event)" style="border-top-width: 0px; padding-right: 0px; padding-left: 0px; font-weight: normal; border-left-width: 0px; border-bottom-width: 0px; padding-bottom: 0px; margin: 0px; cursor: hand; color: #0000ff; padding-top: 0px; border-right-width: 0px; text-decoration: underline" onclick="javascript:window.open("http://pagead2.googlesyndication.com/pagead/iclk?sa=l&ai=BPBau96QmSIGQGIuSvwPh543BCvf6ozDnuMTuA8CNtwHAuAIQAhgCIM-BhwooFDgAUPW507QFYJ2J4YHoBaABwdiG9wOyAQ1uZXdzLmNzZG4ubmV0yAEB2gEqaHR0cDovL25ld3MuY3Nkbi5uZXQvbi8yMDA1MDcxMi8yMzY2MS5odG1sqQJQBo3lHDCDPsgC78OjAqgDAegD5wPoA7ID9QMABAAAiAQBkAQBmAQA&num=2&adurl=http://www.ledzd.com&client=ca-pub-3578421812762734");GgKwClickStat("显示","www.ledzd.com","afc","2000084115");" onmouseout="isShowGg = false;InTextAds_GgLayer="_u663E_u793A"">显示和音频驱动程序的过程,并且确保没有硬件或软件冲突的存在。

  ▲ AutoPlay:让你能够制作一张一旦插入驱动器就能自动安装的光盘。AutoPlay并非DirectX所独有,因为它是Microsoft Win32 API的一部分。

  组件对象模型(COM)是DirectX的基础,有一些技巧建立COM对象——别问我怎么做——但你知道一点点还是有好处的。我只是简单说一下,如果你有兴趣,具体的细节就自己查资料吧!可能下一节你有些困惑,但不要紧,我所说的你不用太明白,毕竟我们的目的是使用COM对象,这可比创建容易多了。

  ☆ 组件对象模型(COM)

  COM接口是DirectX技术的基础,没有COM就没有DirectX。(不用担心,你只需要对COM技术有一个粗浅的了解就可以使用DirectX——只要你在编写DirectX应用程序时遵循一定的步骤,甚至都可以在不了解COM的情况下使用DirectX。

  DirectX的大多数API都是基于COM结构的。COM为软件模块化和软件重用提供了最坚实的基础,它的最重要的概念就是接口(interface),接口是软件重用的最基本方法。更专业的说,接口是一系列操作的规范描述,即接口规范。

  所有的COM接口都是从Iunknown接口继承而来的,IUnknown接口是所有COM接口的根。IUnknown接口具有3个方法:

  · QueryInterface():此方法查询新接口,并在新接口存在时返回之。

  · AddRef():此方法在接口或其它应用程序连编到此COM对象上时将引用计数值递加1。

  · Release():此方法将COM对象的引用计数递减1。当引用计数递减到0时,该COM对象自动释放。

  所有COM对象都具有这三个方法。虽然DirectX应用程序一般不需要考虑引用计数的问题,但引用计数确实是存在的,它已经由DirectX自动完成了。我们所要做的,就是创建DirectX对象,然后在使用完毕后调用Release方法释放引用。

  ☆ 设置

  用DirectX创建程序,你需要有三件主要的事要做。第一件事是COM对象本身,它们包含在.DLL文件里,这些.DLL文件需要在Windows里注册,这在安装DirectX软件包时已经完成了。这些对象是我们创建DirectX应用程序时用到的接口,例如IdirectDraw。但这还不够,因为在COM层上直接使用DirectX是令人沮丧的和乏味的。我们希望有更容易的办法解决它。利用静态库(.LIB文件)是个好办法,它是DirectX软件包的一部分,你可以从Microsoft免费获得。它有一个“打包”函数使你工作更轻松。使用DirectX的不同组件,你需要链接不同的静态库。例如你要使用DirectDraw组件,你就需要ddraw.lib。

  最后,你还需要DrectX头文件,它包含函数原形、宏、常量和你需要用到的各种类型。对于DirectDraw,这个头文件是ddraw.h。
要确认你使用了正确的文件版本,你还得让编译器包含软件开发包的目录。具体的做法是:

  首先点击Tool菜单,选择Options,然后点击Directories,在Show Directories for 组合框下拉菜单中选择Include files,增加一个新的目录。将你的DirectX的路径填入。(例如:C:DXSDKinclude)然后将它移到列表的第一位,使编译时第一个寻找它(防止寻找老版本)。然后选择Show Directories for组合框下拉菜单中的Library files,方法同前,只是把include改成lib。现在,你已经设置完了DirectX。你仍然需要手动增加一些库文件到你的项目中,但先不急,我将在以后讲它。我们将使用DirectX 7.0。

  ☆ DirectX版本号

  你可能认为版本号没有什么好讲的,但我们确实要说一说。Microsoft在DirectX里创建了令人难以置信的科技,但它并不代表不使人迷惑。对于每一个DirectX版本,并不是所有的接口都一次次的升级。因此,尽管DirectX有了7个版本(我写文章时DirectX8.0正准备发布),但DirectDraw并没有7个版本。当DirectX6是最新版本时,DirectDraw的最新接口版本是IDirectDraw4,不是IDirectDraw6。现在最新的版本是DirectX7,所以我们要用IDrectDraw7。很奇怪,是不是?我想你已经明白了我的意思,请不用因为以后看到的感到困惑了。

  最后一件事。当我写这篇文章时,DirectX7是最新的可用版本,但或许现在你已经有了DirectX8,并且或许你还听说了,DirectDraw将不再升级了,取代它的是DirectX Graphics,这是一个功能强大的图形API。但DirectDraw不升级就意味着我们不学习它了,毕竟都离不开COM。如果你想用DirectX8的接口写2D的游戏,你需要用3D方法去创建2D观点。听起来很棒,是的,的确如此,因为使用3D接口将给你更多的硬件支持,例如阿尔发混合。但这也恰恰是个问题,如果机器没有相应的硬件设备,程序会以更慢的速度运行。

  DirectDraw是很容易学的。由于DirectX中的3D图形是基于DirectDraw的,3D应用程序在DirectDraw环境中执行;极少有应用程序专门使用3D。大多数程序使用3D函数对一些对象建模,而另一些对象,诸如背景和精灵,是以2D图形渲染的。所以本系列将使用DirectDraw。关于DirectX8,我还没有太多的了解,因此我只能对DirecX7做详细介绍。总的来说,你使用DirectX,还是离不开DirectDraw的。

  ☆ DirectDraw概述

  在你的程序中使用DirectDraw,你至少要做四件事,它们是:

  1、建立一个DirectDraw对象。

  2、设置协作等级。

  3、设置显示模式和色彩深度(全屏模式)。

  4、至少创建一个DirectDraw表面。

  在讲怎样完成以上步骤之前,先让我们了解一下每一步的含义。第一个,要创建一个DirectDraw对象,这意味着我们要建立一个指向IDirectDraw7接口的指针。这很简单,不是吗?有三种办法可以实现它,你可以直接使用COM,或使用DirectDraw的两个函数之一。三种办法各有千秋,我们过一会儿将详细介绍。第二个,设置操作等级。这可能对你来说比较新鲜。协作是由于Windows是一个多任务操作系统而产生的概念。意思是所有运行的程序都要随时告知Windows它们将要或正在使用的资源,这将保证你所要使用的资源不会被windows再分配给别的应用程序。不用担心,有一个很简单的函数完成它。

  第三个你是否有点熟悉?如果你要写一个全屏的程序,通常是游戏程序,你需要设置显示模式和色彩深度。在Windows的应用程序里做这些通常不是一个好主意,因为它能导致其它程序的同时运行出现问题。当你结束自己的程序时,你当然要恢复到改变前的状态。设置全屏模式,只是调用一个单独的DirectDraw的函数,程序结束后,要恢复原来的状态。

  最后,也是最重要的,是DirectDraw表面的概念。操纵表面是DirectDraw的全部。简单的说,DirectDraw表面是一个用于存储图象数据的线性内存区域。DirectDraw表面的大小就是以象素为单位,用宽和高来定义。所以你可以认为表面是一个用来画图的矩形区域。它有自己的接口,称作IDirectDrawSurface7。有三种主要的表面,我们将在本章和下一章分别用到它们。

  · 主表面:每一个DirectDraw应用程序都有一个主表面。主表面就相当于用户的<strong class="kgb" onmouseover="isShowAds = false;isShowAds2 = false;isShowGg = true;InTextAds_GgLayer="_u663E_u793A_u5668";KeyGate_ads.ShowGgAds(this,"_u663E_u793A_u5668",event)" style="border-top-width: 0px; padding-right: 0px; padding-left: 0px; font-weight: normal; border-left-width: 0px; border-bottom-width: 0px; padding-bottom: 0px; margin: 0px; cursor: hand; color: #0000ff; padding-top: 0px; border-right-width: 0px; text-decoration: underline" onclick="javascript:window.open("http://pagead2.googlesyndication.com/pagead/iclk?sa=l&ai=Bpb0J96QmSIGQGIuSvwPh543BCuTu4k6s9OTEBcCNtwHAuAIQBRgFIM-BhwooFDgAUI7C3YcEYJ2J4YHoBbIBDW5ld3MuY3Nkbi5uZXTIAQHaASpodHRwOi8vbmV3cy5jc2RuLm5ldC9uLzIwMDUwNzEyLzIzNjYxLmh0bWypAlAGjeUcMIM-yALI2KMGqAMB6APnA-gDsgP1AwAEAACIBAGQBAGYBAA&num=5&adurl=http://www.sunwaylcd.com/LCD.asp&client=ca-pub-3578421812762734");GgKwClickStat("显示器","www.sunwaylcd.com","afc","2000084115");" onmouseout="isShowGg = false;InTextAds_GgLayer="_u663E_u793A_u5668"">显示器。它的内容是可见的。同理,主表面就是根据显示器的显示模式设定宽和高。

  · 后缓冲区:后缓冲区是紧随主表面的表面,但它不可见。它是动画没有闪烁的主因,通常,你在后缓冲区画好每一帧,然后把后缓冲区的内容拷贝到主表面,使它显示出来。由于它紧随着主表面,所以它的大小同主表面相同。(你就理解为楼上和楼下的关系)

  · 离屏缓冲区:它很象后缓冲区,只是它不是紧挨着主表面。尽管你可以用它作任何事,但它经常被用来存储位图。离屏缓冲区你可以任意设置大小,唯一的限制是你内存的大小。

  DirectDraw表面可以在系统内存中建立,或直接建立在显示内存中。如果你都建立在显示内存中,速度效果将是最好的,如在系统内存就要慢一些了。如果你把一个表面存储在显示内存中,另一个在系统内存中,性能会有一些损失的,尤其是显示卡与主板之间有一个令人恶心的带宽。总之,如果能把表面都建立在显示内存中,你或许应该尽力做到。

  OK,我们总算有了一点儿认知,让我们看看具体怎么做吧!这儿有一个计划,我们将建立一个全屏模式下,16位色彩,640×480分辨率的程序,我将告诉你全部你需要做的。但开始前,你需要对Windows编程有一点了解。想必你看过了前面几章,应该对创建窗口已经熟悉了。由于这是一个全屏的程序,你不需要任何地窗口控制,所以你的窗口风格应该用WS_POUP|WS_VISIBLE。弄好了吗?All right,出发吧!

posted @ 2012-05-18 15:15  残阳掠影  阅读(1567)  评论(0编辑  收藏  举报