Windows游戏图形基础(下)
发表于2017-10-24
接Windows游戏图形基础(上),下面开始下半部分的内容介绍,一起来看看吧。
1.6.6 示例程序GDldemo1
在这个示例程序中,我们建立7 种系统提供的画笔以及画刷样式,用随机函数发生“ 二人组”srand()与rand()对各画笔与画刷的颜色值分量进行随机地初始化, 并将结果绘制在窗口中.
好了,开始贴详细注释的程序源代码。
程序代码片段一, 全局变量声明:
程序代码片段一, 全局变量声明:
程序代码片段二, Game_lnit() 函数:
程序代码片段三, Game_ Paint()函数:
程序代码片段四, Game_ Clean Up()函数: 好了,代码贴得差不多了。运行这个程序,我们便会得到如下的画面。
而且每次运行时, 都会得到不同的画笔和画刷颜色画出的图案,说起来这个程序还并不是一无是处, 还是具有一定的观赏性的。
1.7 文字的输出
文字的显示在游戏编程中也是非常重要的内容,显示出赏心悦目的彩色文字甚至是特效字体能给游戏加上不少印象分。而在GDI 中,有着不少API 函数用于方便我们将文字信息输出到屏幕上。
DirectX中的2D文字显示函数, 就借助了GDI 中文字显示的一些API 函数,只是对它们进行了再封装而己。
在GDI 中,我们可以采用TextOut 函数、DrawText 函数、DrawTextEx 函数等等来输出文字。
在GDI 中,我们可以采用TextOut 函数、DrawText 函数、DrawTextEx 函数等等来输出文字。
1.7.1 最常用文字输出函数TextOut
TextOut 函数的作用是用当前选择的字符、背景颜色和正文颜色将一个字符串写到指定位置,简单点说,就是在指定地方输出一段
文字。我们先来看一下它的原型:
其中的参数很好理解,首先TextOut 函数的第一个参数DC 句柄是指明大方向的, 表示为哪个DC 进行绘制。第二第三个参数分别是需要进行文本显示的位置的横纵坐标的值。第四个参数是指向字符串的指针, 最后一个参数是这段文本长度的整型值。需要特别注意的是,文本默认颜色是黑色,默认的背景色是WHITE_BRUSH 。后面我们会讲解如何改变默认的颜色、背景,以及选择自己喜欢的字体。文字。我们先来看一下它的原型:
进阶文字输出函数我们通常指的是DrawText 。MSDN 中对DrawText 函数的描述是,在指定的矩形里写入格式化文本,且根据指定的方法对文本格式化(扩展的制表符,字符对齐、折行等〉。
我们看一下他的原型:
我们看一下他的原型:
1.7.3 设置文字颜色
我们通常在GDI 中,可以用SetTextColor 函数来设置文字的颜色值。在MSDN 中查到它的原型如下:
给大家一个调用实例:
1.7.4 设置文字背景透明
在GDI 中,默认的文字输出背景为白色, 这样输出文字的地方背景就被破坏了,显得非常不美观。为了能使文字输出的背景透明,就需要调用一下SetBkMode 函数,进行背景模式的设置。
我们可以在MSDN 中查到SetBkMode函数的原型如下:
我们可以在MSDN 中查到SetBkMode函数的原型如下:
我们用如下的代码来将文字背景色设为透明:
这句代码一般在初始化的时候调用一次就好了, 这样后面我们输出的文字都是背景为透明了。
现在市面上各式各样的TTF 字体显得原来越好看,比如“张海山锐线简体”,还有“时尚中黑简体” 等等。
下面我们开始介绍用于字体创建的函数——CreateFont。这个函数创建一种有很多属性的逻辑字体, 字体可以在创建后用
SelectObject 选进我们的设备环境就行了。
接我们字体创建函数CreateFont 在MSDN 中的定义:
其中第一个参数为我们期望的字体大小, GB3I2_CHARSET是我们常用的字符集, 最后一个参数中设置我们想要设置的字体的中文名称,这里我们选的是“张海山锐线简体”, 当然需要你的电脑字体库中安装了这种字体,如果没安装的话,就会显示默认的那种很丑很没风格的字体。大家怕出现很丑的默认字体的话,可以选现在Windows7中自带的还算蛮好看的“微软雅黑”;
关于游戏程序中的文字显示, 掌握这5 个API 函数基本上就够用了。另外还有一个专门设置文字背景颜色的SetBkColor函数,大家知道就可以了,我们用得很少。
1.7.7 示例程序GDIdemo2
这是一个关于字体的创建、彩色文字显示的示例程序。主要的实现代码都在Game_ Paint()函数中,我们把它贴出来讲解一下。
程序代码片段,Game_ Paint()函数:
程序代码片段,Game_ Paint()函数:
效果截图如下:
俗话说“ 2D 游戏是贴图的艺术,3D游戏是渲染的艺术”这里说的贴图,就是位图的绘制了,它是用GDI 写游戏最核心的基础知识。
位图属于GDI 中尤其重要的对象之一, 如果想用GDI 来开发游戏,我们需要运用大量的位图来丰富游戏的画面。GDI 游戏的画面主要是通过绘制位图来实现的。
为大家总结好的利用位图绘图的大体思路如下:
先调用Load.Bitmap 载入位图到位图句柄中,接着把位图句柄用SelectObject 选入设备环境,
再通过在设备环境中调用绘制位图的函数把位图绘制出来。下面, 我们通过一个四步曲来讲解,这样才显得直观易懂。
先调用Load.Bitmap 载入位图到位图句柄中,接着把位图句柄用SelectObject 选入设备环境,
再通过在设备环境中调用绘制位图的函数把位图绘制出来。下面, 我们通过一个四步曲来讲解,这样才显得直观易懂。
1.8.1 位图绘制四步曲
经过我们的总结, 位图从文件显示到程序窗口中一般可以通过以下简明扼要的四步曲:
- 加载位图, 从文件中加载位图对象。
- 建立兼容DC ,建立一个与窗口设备环境DC 兼容的内存设备环境DC .
- 选用位图对象,内存DC使用步骤1中所建立的位图对象。
- 进行贴图, 将内存DC 的内容贴到窗口DC 中.
下面我们把这四步曲分步详细展开, 说明如何按部就班地完成相关操作。
1 . 位图绘制四步曲之一: 加载位图
位图绘制四步曲之一: 加载位图。关键词, 加载( Load )。
一般我们都是从文件加载位图, 使用的是Loadlmage() 函数。
Loadlmage 函数不仅可以加载位图,还可用于加载图标、光标等图像资源。在MSDN 中,我们可以查到其原型声明如下所示。
1 . 位图绘制四步曲之一: 加载位图
位图绘制四步曲之一: 加载位图。关键词, 加载( Load )。
一般我们都是从文件加载位图, 使用的是Loadlmage() 函数。
Loadlmage 函数不仅可以加载位图,还可用于加载图标、光标等图像资源。在MSDN 中,我们可以查到其原型声明如下所示。
- 第一个参数,HINSTANCE 类型的hinst ,包含被加载图像模型的实例句柄,若从硬盘文件或者资源文件中进行加载, 这个参数设为NULL 。
这句代码表示从工程所在文件夹加载一幅名为Dota2 图片的bmp 文件到位图句柄g_hBitmap中,且加载后在内存中这幅图存储的宽为800 ,高为600 。
2. 位图绘制四步曲之二: 建立兼窑DC
位图绘制四步曲之二: 建立兼容DC 。关键词,兼容(Compatible)
位图绘制四步曲之二: 建立兼容DC 。关键词,兼容(Compatible)
为了绘制出位图,我们需要创建一个和设备环境兼容的内存设备环境,这样才会有暂时存放位图对象的地方。我们一会儿就是把位图对象用SelectObject 函数选入到内存设备环境中, 然后再用贴图函数,把内存设备环境中的内容贴到设备环境中。我们通常习惯把内存设备环境叫做内存DC,下文中我们就这样写。
内存DC 在这里起到中转站的作用,用于暂时存储加载好的位图, 由于我们最终会把暂存在内存DC 上这幅位图贴到真正的DC 上,所以这个DC 要做到与窗口DC 的无缝衔接, 在属性和性质上兼容。在GDI 中一般我们都调用CreateCompatible()函数来建立内存DC 。
内存DC 在这里起到中转站的作用,用于暂时存储加载好的位图, 由于我们最终会把暂存在内存DC 上这幅位图贴到真正的DC 上,所以这个DC 要做到与窗口DC 的无缝衔接, 在属性和性质上兼容。在GDI 中一般我们都调用CreateCompatible()函数来建立内存DC 。
CreateCompatibleDC 函数的作用就是创建一个与指定DC 相兼容的内存DC,它的原型声明如下:
内存DC 使用后也必须进行释放的操作。需要注意的是,释放内存DC 所调用的函数为DeleteDC() , 而不是ReleaseDC() 。
DeleteDC 用于撤销指定的设备环境,它的原型声明如下:
如果一个设备上下文环境的句柄是通过调用GetDC 函数得到的, 那么应用程序不能通过DeleteDC 删除该设备上下文环境,它应该调用ReleaseDC 函数来释放该设备上下文环境。
也就是说,有GetDC 的地方后面必然跟一个ReleaseDC,这就是ReleaseDC 存在的意义, 而DeleteDC 就是专用于撤销指定的设备环境的。
也就是说,有GetDC 的地方后面必然跟一个ReleaseDC,这就是ReleaseDC 存在的意义, 而DeleteDC 就是专用于撤销指定的设备环境的。
3 . 位图绘制四步曲之三:选用位图对象
位图绘制四步曲之三: 选用位图对象。关键词, 选用( Select ) 。
选用位图对象在GDI 中一般采用SelectObject()来实现。
位图绘制四步曲之三: 选用位图对象。关键词, 选用( Select ) 。
选用位图对象在GDI 中一般采用SelectObject()来实现。
4. 位图绘制四步曲之四:进行贴图
位图绘制四步曲之四: 进行贴图。关键词,贴图(BitBlt )。
前面的三步其实都是在为这步做准备。
位图绘制四步曲之四: 进行贴图。关键词,贴图(BitBlt )。
前面的三步其实都是在为这步做准备。
在这一步当中,我们把内存DC 中的内容复制到设备环境DC 上,就实现了贴图的效果。这个操作所使用的函数有很多, 比如BitBlt()、TransparentBlt()或者StretchBlt() 。我们最常使用的是BitBIt 函数,它在GDI 编程中具有重要的意义。
BitBlt 函数的功能是从源矩形中复制一个位图到目标矩形,必要时按目前目标设备设置的模式进行图像的拉伸或压缩。
我们可以在MSDN 中查到它的原型如下:
- 第九个参数,DWORD 类型的dwRop ,指定光栅操作代码,即贴图的方式。这些代码定义着源矩形区域的颜色数据,将如何与目标矩形区域的颜色数据组合以完成最后的颜色。
最后给一个调用实例,对着调用实例,大家就能容易了解BitBlt 函数的用法:
其中, g_mdc 为源设备环境DC, g_hdc 为目标设备环境DC,这就表示是从g_mdc 向g_hdc来贴图的。
5 . 提纲要领
我们将这位图绘制四步曲结合起来看,发现这四步分别都是一句代码,非常地直观,大家只要理解并消化这四句代码,就学会了位图的绘制。
1.8.2 示例程序GDldemo3
我们把一张名为Naruto.bmp的火影忍者图片文件放到工程目录下面,然后用这节教大家的知识来载入这张位图并显示在窗口中。
下面来看下这个程序中的核心代码:
程序代码片段一, 宏定义与全局变量声明:
下面来看下这个程序中的核心代码:
程序代码片段一, 宏定义与全局变量声明:
程序代码片段二, Game_Init() 函数:
程序代码片段三, Game_Paint() 函数:
程序代码片段四, Game CleanUp()函数:
效果图如下:
最后总结一下, 用GDI 显示来显示一幅位图的操作是很直观的, 先用Loadlmage 函数载入位图, 然后用CreateCompatibleDC 创建一个兼容DC , 再用SelectObject 将位图句柄选入某设备环境之中, 然后用贴图函数BitBlt 进行贴图操作,最后释放位图资源和设备环境。即下面的这四步曲:
- 加载位图,从文件中加载位图对象。
- 建立兼容DC , 建立一个与窗口设备环境DC 兼容的内存设备环境DC 。
- 选用位图对象,内存DC 使用步骤1中所建立的位图对象。
- 进行贴图,将内存DC 的内容贴到窗口DC 中。
另外需要注意的是,资源的释放是要有讲究的,我们记住一个原则就可以了,就是对称原则——先创建的后释放,后创建的先释放。
1.9 消除闪烁:缓冲显示技术
我们在编写游戏或者遇到其他任何需要在每秒钟多次刷新窗口的程序时,经常都会遇到画面闪烁的问题。这跟屏幕的刷新过程和工作方式有着密切的关系。因为如果我们不进行任何处理措施,直接把绘制的中间过程显示在屏幕上,难免会出现“ 穿帮镜头” 。就像我们在进行一台晚会的演出,要想奉献出一台精彩绝伦的晚会, 除了节目本身要精彩以外, 还需要做到有条不絮, 分好台前和台
后。台后的演员准备好之后, 才会上台前去表演,把自己最完美的一面展现给观众。
游戏的画面处理艺术也是这个道理, 采取了与晚会演出相似的处理方式一一分台前和台后。
而在游戏画面显示中,我们把这种技术叫双缓冲( Double buffer ) 。
后。台后的演员准备好之后, 才会上台前去表演,把自己最完美的一面展现给观众。
游戏的画面处理艺术也是这个道理, 采取了与晚会演出相似的处理方式一一分台前和台后。
而在游戏画面显示中,我们把这种技术叫双缓冲( Double buffer ) 。
类似于我们上面讲到的进行一台晚会的演出,双缓冲技术就是我们在其他地方(简单的说就是不针对屏幕,不显示出来的地方)开辟一个存储空间,把所有的动画都要渲染到这个地方,而不是直接渲染到屏幕上(针对屏幕的存储区域) 。等到准备完成之后,再将画面整体拷贝显示到屏幕之上, 正所谓不打无准备之仗。
在GDI 中,直接针对屏幕的就是窗口DC——喜闻乐见的hdc , 而上文中我们所说的“不显示出来的的地方” , 一般为与屏幕窗口DC 兼容的内存DC 。前面我们在位图绘制四步曲的第二步中,创建的兼容DC , 就是例子。
在GDI 中,直接针对屏幕的就是窗口DC——喜闻乐见的hdc , 而上文中我们所说的“不显示出来的的地方” , 一般为与屏幕窗口DC 兼容的内存DC 。前面我们在位图绘制四步曲的第二步中,创建的兼容DC , 就是例子。
双缓冲( Double buffering )技术我们有时候也称作页面切换技术( Page Flipping ),而常常为了使画面显示更加平滑,在双缓冲不能满足我们要求的时候,也经常用到第三个缓冲区,这就称为三缓冲( Triple Buffering )技术。这种缓冲区的数量可以根据我们的需要任意增加缩减,因为只是简单调用一下API 函数CreateCompatibleDC 就可以创建一个指定DC 兼容的内存DC ,所以用起来
非常方便。
在后面将要讲解的Direct3D ,就是运用了通过创建多层类似于内存DC 的缓冲链, 来实现三维画面的平滑显示, 在Direct3D 中把这种技术叫做交换链。
非常方便。
在后面将要讲解的Direct3D ,就是运用了通过创建多层类似于内存DC 的缓冲链, 来实现三维画面的平滑显示, 在Direct3D 中把这种技术叫做交换链。
1.10 章节小憩
本章我们和大家一起详细探讨了游戏编程所需的GDI编程知识,讲到了GDI 的概念、设备环境、Windows 屏幕区域相关概念、GDI 基本几何绘图、随机系统初步、文字输出,以及重中之重的位图绘制。