当前位置: 首页 > news >正文

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

欢迎光临 C++ Builder 研究,http://www.ccrun.com/doc/go.asp?id=440
这并非哗众取宠, 通常学习一种电脑技术有两种方法. 一种是自己摸索, 在错误的方向上一错再错, 屡战屡败, 不过最后得道成功. 另一种是有人 或好的材料指导, 因而事半功倍, 在正确的方向上走了速成的捷径. 就象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里.


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

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • 【长篇博文】Docker学习笔记与深度学习环境的搭建和部署(二)
  • 从系统中取得指定资源图像(转载)
  • 【长篇博文】Docker学习笔记(四):镜像的分层、打包、双向绑定、导入导出、Dockerfile的构建、部署与发布
  • PyTorch1.8-gpu和TensorFlow-gpu-2.5已发布【附下载地址和安装教程】
  • 2004年7月19日
  • 使用TensorRT提高GPU上的YOLOv4对象检测速度
  • 论文《Focal Loss for Dense Object Detection》Detectron2的安装与测试(测试案例:全景分割、姿态估计、实例分割、目标检测 - Faster R-CNN)
  • 反叛之冰:Internet Communications Engine
  • 【经典视觉算法推荐】Focal Loss 论文公式推导及主要贡献
  • 2004年7月20日
  • YOLO自带的图像数据增强方法
  • 好久没来了
  • 企业微信点餐接口文档
  • 观十面埋伏有感(爆强!) (转自猛禽的blog)
  • 企业微信点餐数据库
  • [原]深入对比数据科学工具箱:Python和R 非结构化数据的结构化
  • 〔开发系列〕一次关于小程序开发的深度总结
  • AHK 中 = 和 == 等比较运算符的用法
  • bearychat的java client
  • If…else
  • input实现文字超出省略号功能
  • JavaScript设计模式与开发实践系列之策略模式
  • JavaScript实现分页效果
  • java多线程
  • Java反射-动态类加载和重新加载
  • jquery ajax学习笔记
  • JS+CSS实现数字滚动
  • JSDuck 与 AngularJS 融合技巧
  • js数组之filter
  • Laravel深入学习6 - 应用体系结构:解耦事件处理器
  • nodejs调试方法
  • PhantomJS 安装
  • SQLServer插入数据
  • underscore源码剖析之整体架构
  • vue 个人积累(使用工具,组件)
  • win10下安装mysql5.7
  • 安装python包到指定虚拟环境
  • 基于Volley网络库实现加载多种网络图片(包括GIF动态图片、圆形图片、普通图片)...
  • 使用Swoole加速Laravel(正式环境中)
  • 算法---两个栈实现一个队列
  • ​Benvista PhotoZoom Pro 9.0.4新功能介绍
  • ​数据链路层——流量控制可靠传输机制 ​
  • #我与Java虚拟机的故事#连载13:有这本书就够了
  • (51单片机)第五章-A/D和D/A工作原理-A/D
  • (C#)获取字符编码的类
  • (附源码)springboot宠物管理系统 毕业设计 121654
  • (转)IIS6 ASP 0251超过响应缓冲区限制错误的解决方法
  • .Net Framework 4.x 程序到底运行在哪个 CLR 版本之上
  • .NET Framework 和 .NET Core 在默认情况下垃圾回收(GC)机制的不同(局部变量部分)
  • .Net mvc总结
  • .NET Standard / dotnet-core / net472 —— .NET 究竟应该如何大小写?
  • .NET/C# 判断某个类是否是泛型类型或泛型接口的子类型
  • @KafkaListener注解详解(一)| 常用参数详解
  • [BFS广搜]迷阵
  • [CareerCup] 6.1 Find Heavy Bottle 寻找重瓶子