3.1 高瞻远瞩——Windows 编程体系与游戏编程
Windows 平台游戏编写铁三角——C++、 Windows API与图形库(DirectX或者OpenGL)。
想要在Windows 下编写出绚丽的游戏程序,除了对某种图形库驾轻就熟之外,必要的Windows编程基础是不可少的。
而在Visual Studio 中,如果采用C++编程语言来进行开发的话,我们需要知道通常有这3 种基本的创建交互式Windows 应用程序的方式:
• 方式一,使用Windows API 来进行开发。 Windows API 是Windows 操作系统与应用程序之间的通信的基本接口。
• 方式二,使用MFC 来进行开发。MFC 也就是Microsoft Foundation Classes ,微软基础类库,也就是一组封装了Windows API
的C++类而已。
• 方式三,使用Windows Forms。相对于传统的Windows API 与MFC 开发方式,这是一种基于窗口的新的开发机制, Windows Forms 是微软的.NET 开发框架的图形用户界面部分,该组件通过将现有的Windows API 封装为托管代码提供了对Windows 本地(native)组件的访问方式。我们通常可以把这套纽件看做是孔MFC 的替代品。
在开发游戏程序时,最需要关注的地方就是执行效率。因为游戏程序中往往在每一个瞬间都有大量的图形需要绘制,如果绘制效率不高,图形数量变多,计算量变大的时候就会特别卡。一款成功的游戏最基本的特点就是具有流畅的用户体验,这个要求达不到的话, 其他方面就不用考虑了。
而C++引以为豪的执行效率与生俱来,配上Windows API 能直接与操作系统打交道的高效率特性,强强联合,再配上能直接与显卡打交道的图形库(DirectX 或者OpenGL ),这样,在Windows平台上编写游戏的铁三角配置就诞生了。
3.2 理解两个术语——API 与SDK
API——应用程序编程接口, SDK——软件开发包
3.2.1 何为API
微软公司为了方便我们开发基于Windows 的应用程序,为我们提供了各种各样的函数。这些函数是Windows 操作系统提供给应用程序编程的接口,即Application Programming Interface ,简称为API。
我们在编写Windows 程序中所说的API 函数, 就是指系统提供的函数,主要的Windows 函数都在Windows.h 头文件中进行声明了。
3.2.2 什么是SDK
3.3 Windows 程序的“心脏”——WinMain 函数
WinMain——Windows 程序的入口点函数。
当Windows 操作系统启动一个程序时,它最先调用的就是这个程序的WinMain 函数(实际是由插入到可执行文件中的启动代码调用的)。WinMain 是Windows 程序的入口点函数,与之前我们学C++时写的那些黑洞洞的DOS 程序的入口点函数main 的作用相同。当WinMain 函数结束或返回时, Windows 应用程序也就结束了。
3.3.1 WinMain 函数
int WINAPI WinMain(
__in HINSTANCE hInstance,
__in HINSTANCE hPrevInstance,
__in LPSTR lpCmdLine,
__in int nCmdShow
);
3.3.2 MessageBox 函数
在MSDN 中查到这个函数有如下原型:
int MessageBox(
__in HWND hWnd,
__in LPCTSTR lpText,
__in LPCTSTR lpCaption,
__in UINT uType
);
3.3.3 PlaySound 函数
BOOL PlaySound(
LPCTSTR pszSound,
HMODULE hmod,
DWORD fdwSound
);
如果要使用PlaySound 函数的话,必须在编译之前连接winmm.lib 库文件;
3.3.4 示例程序Firstblood !
#include <Windows.h>
#pragma comment(lib,"winmm.lib")
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
PlaySound(L"FirstBlood.wav", NULL, SND_FILENAME | SND_ASYNC); //播放音效
MessageBox( NULL, L"First blood! 你好,游戏开发的世界,我们来征服你了!", L"First blood! 消息窗口", 0 );//显示一个消息框
return 0;
}
接着我们逐行详细来讲解一下这短小精悍的8 行代码的含义:
第1 行代码解析:包含一下Windows.h 头文件,如果我们要编写基于Windows API 的程序,这个头文件一般都要include 一下。包含了Windows.h 头文件后,我们在编写程序中用到的那些API函数就像是有了“户口”,政府(编译器〉才会认为他们是合法居民。不然任我们调用什么API函数,我们的编译器都不会买账的。
第2 行代码解析:后面会用到PlaySound 函数来播放音效,这里就必须在程序中链接使用PlaySound 函数所需的winmm.lib 库文件。我们经常在编译源代码时,会出现“无法解析的外部符号”系列的错误,这一般都是lib库文件没添加或者添加不正确造成的。
在工程中包含库文件有两种方式,任选一种就可以了:
- 第一种方式,就是用我们这里使用的#pragma comment(lib, "winrnm.lib”)语句,在双引号“”之间填我们需要链接的库文件。一般我们把#pragma comment 语句放在包含头文件的include 语句之后。
- 第二种方式,在工程配直中添加库文件的包含。具体做法是在Visual Studio中依次单击菜单栏的【项目】→ 【属性】(或者按快捷键【Alt+F7] ),在弹出的工程属性管理页面依次单击【配置属性】→【链接器】→【输入】。然后接着在附加依赖项一
栏单击向下的箭头,并单击弹出的【编辑】字样;这时,会弹出一个【附加依赖项】对话框,我们在这个对话框的编辑框中填上要加入的库文件(比如这里用到的winmm.Lib ),并单击【确定】按钮就可以了。
第3-4 行代码解析:也就是写一下WinMain 函数的标准原型,可以直接从MSDN 中把WinMain函数的标准写法拷贝过来贴到这里,我们平常写程序时经常可以这样做,无形中大大提高了效率。
第5 行代码解析: 调用一下PlaySound 函数来播放音效,其中第一个参数我们这样写L”FirstBlood.wav”,其中的L表示我们要把字符串“FirstBlood.wav ”转化为宽字符版。因为在Visual Studio 中默认使用的是Unicode 字符集。如果我们不写L而
直接写“FirstBlood. wav”的话,就会报出“不能将参数1 从const char [15 ] 转换为LPCWSTR ” 系列的错误。
因为我们把FirstBlood.wav 这个音频文件放在了工程文件夹中与程序源文件相同的路径下了,所以直接写L”FirstBlood.wav”, 程序就会在程序源文件所在的目录找到FirstBlood.wav 音频文件并载入进来。
关于工程中使用的字符集, 我们可以在工程属性页中更改。即在Visual Studio 中依次单击菜单栏的【项目】→【属性】(或者按快捷键【Alt+F7 】),在弹出的工程属性管理页面依次单击【配置属性】→【常规】, 在【字符集】一栏中进行更改。
第6 行代码解析: 调用一下MessageBox 函数来显示一个对话框,其中第一个参数填NULL 就行了,第二个参数填对话框中的内容,第三个参数填对话框的标题,注意也都要用L 将宇符串转化为宽字符版。
第7~8 行代码解析: 第7 行我们给上WinMai n 函数的返回值,因为WinMain 函数的返回值类型为int,这里返回0 就可以了。第8 行给上WinMain 函数的回括号,表示WinMain 函数的内容到这里就结束了。
3.4 Windows 程序的“外貌”——窗口
3.5 Winodows 资源的“身份证”——句柄
句柄——每个Windows 资源都有且都独特的“身份证”。
在Windows应用程序中,窗口都是通过窗口句柄(HWND )来标识的。我们要对某个窗口进行操作的话,首先就是要得到这个窗口的句柄。
句柄(HANDLE)是Windows 程序中极其重要的一个概念,我们经常需要与其打交道。在Window s 程序中,有各种各样的资源,比如窗口、图标、光标等。系统创建这些资源时会为它们分配内存,并返回标识这些资源的标识号,这些标识号就是句柄。
3.6 Windows 程序的“邮局”——消息与消息队列
3.6.1 消息的表示形式——MSG 结构体
typedef struct tagMSG { // msg
HWND hwnd;
UINT message;
WPARAM wParam;
LPARAM lParam;
DWORD time;
POINT pt;
} MSG;