两个小时学会DirectDraw编程 (转)

2024-01-13 01:58

本文主要是介绍两个小时学会DirectDraw编程 (转),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

这并非哗众取宠, 通常学习一种电脑技术有两种方法. 一种是自己摸索, 在错误的方向上一错再错, 屡战屡败, 不过最后得道成功. 另一种是有人 或好的材料指导, 因而事半功倍, 在正确的方向上走了速成的捷径. 就象KFC 的鸡一样. 第一种学法能学出电脑天才, 因为所谓电脑高手, 其实就是排错试错的高手. 而第二种则出电脑专才. 这个两小时(?)的学习, 不能使你深入的掌握DD, 不过可以给你编制DD的框架. 能给你 一个起始点, 这个教程就算成功了.


DirectDraw编程需要一些背景知识:

DirectDraw是为在 Windows95/NT 下实现高速图形显示所写的程式库.


高速图形显示的基本方法是用一种叫做 Page Flipping的技术. 关于什么是 Page Flipping, 参见古技介绍.如果你 不急的话, 看到下面, 你也会看到.


在 Windows95/NT下做 Page Flipping 分为全屏的和窗口的两种. 在全屏下Page Flipping 叫做Flip, 在窗口下叫做 Blit.


知道了这些背景知识, 我们可以开始写程式了.


写所有 DirectDraw的程式, 差不多都有以下几个步骤,

1. 初始化, 这是每个程式都需要的劳什子.
2. 设置显示模式.
3. 在内存里建立PageFlipping所需要的两个页, 前页和后页.
4. 给显示的区域加个画框以免画到外面来.
5. 在后页画图, 然后"刷"的一下子换到前页来.


步骤一: 初始化

DirectDraw 是一个面向对象的函数库. "面向对象"的意思并不是指面对著你的女朋友, "对象" 在这里, 你可以简单地想象成是一个模板, 比方说,"政府", 一旦你说:"我成立了一个政府". 别人 就会立即把你套入"政府模板", 自然而然地认为你有印钞票的功能. 在我们的程式里, 你一旦声明 一个变量(比如 myDD)是 DirectDraw对象 (DirectDraw对象的正式名为 LPDIRECTDRAW) , 这个myDD就有了 DirectDraw对象的所有的功能和特性. 定义 的语法是:

LPDIRECTDRAW pMyDD;
除了 DD的对象外, 还有几个重要的对象, "页面", "裁剪板" 和 "调色板". "页对象"用来定义"前页"和"后页". 定义如下:

LPDIRECTDRAWSURFACE pMyDDSFront;
LPDIRECTDRAWSURFACE pMyDDSBack;
一个"裁剪板对象", 在窗口模式下用来剪去画出窗口边界的部份.

LPDIRECTDRAWCLIPPER pMyClipper;
"调色板"设定屏幕的颜色表, 在读取256色的 Bitmap时要用到.
LPDIRECTDRAWPALETTE myDDPal;
最最重要的"对象"就是这些了. 当然 DirectX还有很多复杂晦涩的对象. 这是速成不起来的.

编制 Windows 程式有一大堆变量和对象是 Windows所要求的, 这也是我最烦 Microsoft的地方. Microsoft 似乎知道这点. 所以在 VC4.0后的版本有了 Wizard的功能帮你自动生成代码. 尽量地去用它的 Wizard使我们的生活变得容易.

由于我们的程式可能会占用一个窗口, 就给这个窗口一个 handle:

HWND myWnd
初始化的工作还没有完, 我们要把这些对象指向一个安全的地方 Null.

pMyDD = NULL;
pMyDDSFront = NULL;
pMyDDSBack = NULL;
pMyClipper = NULL;
pMyDDPal=NULL;

最后, 在 Windows系统为我们的 myDD对象开辟相应的区域:

DirectDrawCreate( NULL, //用当前的显示驱动
&pMyDD, NULL))
Okay, 烦人的初始化总算完了.


步骤二: 设置屏幕的显示方式.

DirectDraw 有自己的设置屏幕的方式, 而且它的屏幕模式分为"全屏"( exclusive mode)和"窗口"( normal mode). 各有各的设置方法. 设置的主要区别在于 SetCooperativeLeve的参数.

SetCooperativeLeve 在"窗口"模式下这样设置:
pMyDD->SetCooperativeLevel(AfxGetMainWnd()->GetSafeHwnd(),DDSCL_NORMAL);
而在"全屏"模式下这样设置:

pMyDD->SetCooperativeLevel( hwnd, DDSCL_EXCLUSIVE | DDSCL_FULLSCREEN );
如果它们的返回值为 DD_OK表示成功. 我们就可以把屏幕调节成我们想要的样子, 例如 640x480x8. 也就是256色. 究竟有那些屏幕模式可用取决于你的显示卡

pMyDD->SetDisplayMode( 640, 480, 8 );
现在, 我们已经有了一个屏幕, 不过还不能在上面画画, 我们需要步骤三来 替我们建立一个可供画画涂涂用的画板.


步骤三: 建立前后页(两块画板).

两块画板的好处是可以一边在一块上面画, 一边给别人看已经画好的另一块. 等这块画好了, 两块板就对调一下, 让别人看新画好的这块. 如果画的足够快, 换的足够快. 看的人就会看到动画了, 就象电影的效果一样. 我们把这叫做 Page Flipping.
这里先要介绍的是怎样在系统中建立两块画板( double buffering), 不过你也可以根据需要建立三块,四块画板.
DDSURFACEDESC ddsd; //这个结构描述"页"的特徵.
ddsd.dwFlags = DDSD_CAPS;
ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE;//指定我们用的是前页.

ddsd.dwSize = sizeof(ddsd); //尺寸


// 做前页:
HRESULT result;
result = pMyDD->CreateSurface(&ddsd, &pMyDDSFront, NULL);
当发生错误时, 要记得 Release对象.

if (result!=DD_OK)
{
pMyDD->Release();
pMyDD = NULL;

}


ddsd.dwWidth = scr_width; //设定后页的大小,
ddsd.dwHeight = scr_height;

//指定 我们要后页
ddsd.dwFlags = DDSD_WIDTH | DDSD_HEIGHT | DDSD_CAPS;
ddsd.ddsCaps.dwCaps = DDSCAPS_OFFSCREENPLAIN;

//做后页
result = pMyDD->CreateSurface(&ddsd, &pMyDDSBack, NULL);

}


步骤四: 给显示区加一个画框(裁剪板).

在窗口下. 为了防止 DirectDraw 画到窗口外面去. 需要加一个画框(裁剪板). 可以用 CreateClipper来 创建剪贴板.
result = pMyDD->CreateClipper(0, &pMyClipper, NULL);

创建后,把它套到窗口上去, 所以要知道是那一个窗口( Handle).

myWnd = AfxGetMainWnd()->GetSafeHwnd();// 从系统中拿到窗口的 Handle
result = pMyClipper->SetHWnd(0, myWnd);

// 把剪贴板加到窗口上去
result = pMyDDSFront->SetClipper(myClipper);


步骤五: 在后页画图, 前后页互换.

其实到这里才是真正开始写游戏的地方, 以前在 DOS下写游戏, 就是直接从 这个步骤开始的. 以上这些工作, 都是 Microsoft强加给我们的.


写游戏之前我们先来解决前后互换的问题.

// 如果前页的内存被 Windows"征用"了, 这里把它要回来. 这个检察常常会被忘记.
if (pMyDDSFront->IsLost() == DDERR_SURFACELOST)
pMyDDSFront->Restore();


DirectDraw 用来互换的语句有 Blt和 BltFast. BltFast据称比 Blt快10%.

result = pMyDDSFront->Blt(&rcTo, pMyDDSBack, &rcFrom, DDBLT_WAIT,NULL);
result = pMyDDSFront->BltFast( 0, 0, pMyDDSBack, &rcFrom, DDBLTFAST_SRCCOLORKEY);


如果程式工作在"全屏"模式下. 前后页互换容易得多, 只是一句:

result = pMyDDSFront->Flip( NULL, 0 );
现在就到了游戏的主要部份了, 我们称之为"游戏逻辑"部, 在普通的游戏中, "游戏逻辑" 通常 要做很多事, 如画游戏场景, 故事处理等等. 做完这些事后, 再和前页做换屏. 不过怎样做你的 游戏, 就没有我什么事了:-)

所有的步骤都讲完了. 是不是觉得特容易? 半个小时就够了? okay, 剩下的一个半小时让 你把它们变成真正的代码吧. 打开你的 Visual C++, 我用的是 VC5.0, 不过你也可以用 VC4.0. 再低恐怕就不可以了. 别忘了检查一下你的 DirectX SDK 有没有安装好. 打开VC, 选择 MFC app EXE Wizard 来生成程式的框架, 我假设学DirectDraw的人应该 会用VC, 所以怎样用 Wizard, 我就不再赘述.

进入 IDE环境后, 加入一个新 CPP file, 把上面用到的子函数的代码打入.
当然你还需要一个 .H file 来放变量名, 对象名和子程式名.

MFC(Microsoft Fried Checken)的 Wizard会帮你生成 ::InitInstance() 和 ::OnIdle(LONG lCount), 把你的 初始化部份, 建页等步骤放在 InitInstance子类里. 把"游戏逻辑"和换页放在 OnIdle里.


最后我想给大家一个完整的可运行的例子, 不过平均每分钟六个汉字的速度打得我头昏眼花. 四肢发 麻. 过两天再

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/upwaker/archive/2004/07/16/43391.aspx

这篇关于两个小时学会DirectDraw编程 (转)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/599874

相关文章

shell编程之函数与数组的使用详解

《shell编程之函数与数组的使用详解》:本文主要介绍shell编程之函数与数组的使用,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录shell函数函数的用法俩个数求和系统资源监控并报警函数函数变量的作用范围函数的参数递归函数shell数组获取数组的长度读取某下的

揭秘Python Socket网络编程的7种硬核用法

《揭秘PythonSocket网络编程的7种硬核用法》Socket不仅能做聊天室,还能干一大堆硬核操作,这篇文章就带大家看看Python网络编程的7种超实用玩法,感兴趣的小伙伴可以跟随小编一起... 目录1.端口扫描器:探测开放端口2.简易 HTTP 服务器:10 秒搭个网页3.局域网游戏:多人联机对战4.

Java并发编程必备之Synchronized关键字深入解析

《Java并发编程必备之Synchronized关键字深入解析》本文我们深入探索了Java中的Synchronized关键字,包括其互斥性和可重入性的特性,文章详细介绍了Synchronized的三种... 目录一、前言二、Synchronized关键字2.1 Synchronized的特性1. 互斥2.

C语言实现两个变量值交换的三种方式

《C语言实现两个变量值交换的三种方式》两个变量值的交换是编程中最常见的问题之一,以下将介绍三种变量的交换方式,其中第一种方式是最常用也是最实用的,后两种方式一般只在特殊限制下使用,需要的朋友可以参考下... 目录1.使用临时变量(推荐)2.相加和相减的方式(值较大时可能丢失数据)3.按位异或运算1.使用临时

Python异步编程中asyncio.gather的并发控制详解

《Python异步编程中asyncio.gather的并发控制详解》在Python异步编程生态中,asyncio.gather是并发任务调度的核心工具,本文将通过实际场景和代码示例,展示如何结合信号量... 目录一、asyncio.gather的原始行为解析二、信号量控制法:给并发装上"节流阀"三、进阶控制

java两个List的交集,并集方式

《java两个List的交集,并集方式》文章主要介绍了Java中两个List的交集和并集的处理方法,推荐使用Apache的CollectionUtils工具类,因为它简单且不会改变原有集合,同时,文章... 目录Java两个List的交集,并集方法一方法二方法三总结java两个List的交集,并集方法一

Python如何计算两个不同类型列表的相似度

《Python如何计算两个不同类型列表的相似度》在编程中,经常需要比较两个列表的相似度,尤其是当这两个列表包含不同类型的元素时,下面小编就来讲讲如何使用Python计算两个不同类型列表的相似度吧... 目录摘要引言数字类型相似度欧几里得距离曼哈顿距离字符串类型相似度Levenshtein距离Jaccard相

使用Navicat工具比对两个数据库所有表结构的差异案例详解

《使用Navicat工具比对两个数据库所有表结构的差异案例详解》:本文主要介绍如何使用Navicat工具对比两个数据库test_old和test_new,并生成相应的DDLSQL语句,以便将te... 目录概要案例一、如图两个数据库test_old和test_new进行比较:二、开始比较总结概要公司存在多

C#比较两个List集合内容是否相同的几种方法

《C#比较两个List集合内容是否相同的几种方法》本文详细介绍了在C#中比较两个List集合内容是否相同的方法,包括非自定义类和自定义类的元素比较,对于非自定义类,可以使用SequenceEqual、... 目录 一、非自定义类的元素比较1. 使用 SequenceEqual 方法(顺序和内容都相等)2.

C#多线程编程中导致死锁的常见陷阱和避免方法

《C#多线程编程中导致死锁的常见陷阱和避免方法》在C#多线程编程中,死锁(Deadlock)是一种常见的、令人头疼的错误,死锁通常发生在多个线程试图获取多个资源的锁时,导致相互等待对方释放资源,最终形... 目录引言1. 什么是死锁?死锁的典型条件:2. 导致死锁的常见原因2.1 锁的顺序问题错误示例:不同