(1)Windows编程体系与游戏编程
● 首先我们需要知道,游戏类的应用程序通常可以被分为图形用户接口(GUI)和引擎,这两个部分。
● Windows 平台游戏编写套装为—— C++语言、Windows API(能直接与操作系统打交道的高效特性)与图形库(DirectX 或者 OpenGL)【能直接与显卡打交道的图形库】
● 游戏编程更加强调计算机图形学的知识和计算机资源的高效利用。而不是那些我们在普通的软件编程中习以为常的单线程的、事件驱动的或者顺序逻辑执行的那些软件
● 如果在Visual Studio 中用C++语言进行开发的话, 通常有3种基本的创建交互式Windows 应用程序的方式:——Windows 程序的体系
(1) 使用Windows API来进行开发, Windows API是Windows 操作系统与应用程序之间的通信的基本接口
(2)使用MFC来进行开发, 是微软的基础类库,也就是一组封装了Windows API的C++类而已`
(3) 使用Windows Forms,相对于传统的Windows API与MFC开发方式,这是一种基于窗口的新的开发机制,Windows Forms是微软的.NET开发框架的图形用户界面部分,该组件通过现有的Windows API封装为托管代码提供了对Windows本地组件的访问方式, 我们通常可以把这套组件看做是MFC的替代品,
● 在Windows平台上进行游戏开发,通常都是采用C++编程语言搭上 Windows API这套方案,再配合上某种图形库,来完成游戏程序的编写,就算是游戏引擎,也基本上是用的C++、Windows API 加上图形库这套体系
● 游戏编程中MFC的使用: MFC还得依靠 Windows API, 而且比Windows API 高层,也就是说MFC跑起来必定会比Windows API多走一段路, 这就注定了MFC的效率不如 Windows API。由于MFC有底层代码的隐蔽性等特点, 且MFC毕竟封装了很多实际上没用到的东西, 不利于游戏开发的效率和游戏的运行速度, 不适合做游戏开发, MFC做游戏地图编辑器之类的工具软件倒是比较适合。
(2)理解两个术语——API与SDK
何为API:
● 微软公司为了方便我们开发基于Windows的应用程序,为我们提供了各种各样的函数,这些函数是Windows操作系统提供给应用程序编程的接口 ,称为API, API可以理解为预先定义好的函数, **
● 我们在编写Windows程序中所说的API函数,就是指系统提供的函数, 主要的Windows函数都在【Windows.h】头文件中进行声明了
● 任何Windows应用程序与Windows本身之间的所有通信,都要使用Windows应用程序编程接口,也就是Windows API, 它是Windows操作系统提供的标准函数, 可以提供应用程序与Windows互相进行通信的方法, 在Windows和应用程序之间传递数据的是结构体而不是类 。
什么是SDK : ● 中文译为软件开发包, 说白了就是一个开发所需资源的一个集合, 所以 DirectX SDK 就是用 DirectX 进行开发的一个资源的打包集合, 这里需要注意的是 API和SDK 都是IT界广泛使用的术语, 并不是专指特定的API或者SDK
(3)WinMain函数
** ● WinMain函数——Windows程序的入口点函数 : 这个函数是所有Windows应用程序的心脏, 是所有Windows 程序的入口点函数, 当Windows 操作系统启动一个程序时, 他最先调用的就是这个程序的WinMain函数(实际上是由插入到可执行文件中的启动代码调用的) , 当WinMain 函数结束或返回时, Windows 应用程序也就结束了**
** ● WinMain函数的原型为: **
int WINAPI WinMain
(
_In_HINSTANCE hInstance,
_In_HINSTANCE hPrevInstance,
_In_LPSTR lpCmdLine,
_In_int nCmdShow
);
说明: 其中函数类型int之后的WINAPI 字样基本上可以忽略, 它只是WinDef.h 头文件中定义的一个宏,我们可以利用转到定义功能, 查看到它在WinDef.h 头文件中的定义如下:
#define WINAPI _stdcall
也就是说WINAPI 其实就是_stdcall,只是为了让我们清楚知道这里的_stdcall 表示的是一种调用约定, 它让编译器知道了应当以Windows 兼容的方式来产生机器指令, 如果我们在写WinMain 函数的时候去掉这句WINAPI 而直接写 intWinMain(), 仍然是可以编译运行的, 只不过在编译期间会得到一条警告,大概说的是—— 也就是建议我们要确保WinMain 函数具有WINAPI 前辍。
注意: 这里的WINAPI 有时也会写作CALLBACK, 这个CALLBACK和WINAPI 是完全等效的, 因为他们具有相似的宏定义:
** #define CALLBACK _stdcall
#define WINAPI _stdcall
● 在这些 WinMain函数中的 参数之前都有一个 _In 字样, 这里的 _In 可以理解为一个宏, 表示需要我们进行自行输入的一个参数, 与其对应的是 _Out, 它表示指定的这个参数是函数本身向外输出的一个参数。
● 下面我们分别对WinMain 函数的每一个成员进行详细的介绍。
这里的 4个参数, 都是需要在系统调用WinMain 函数的时候, 传递给应用程序的
(1) 第一个参数, HINSTANCE类型的 hInstance, 它表示该程序当前运行的实例句柄, hInstance 其实是一个数值, 当一个程序在Windows下运行时, 它唯一对应一个运行中的实例, 也只有运行中的程序实例, 才有资格分配到实力句柄。 一个应用程序可以运行多个实例, 每运行一个实例, 系统都会给该实例分配一个句柄值, 并且通过hInstance 参数传递给程序的入口点WinMain 函数
(2) 第二个参数, _In_HINSTANCE 类型的 hPrevInstance, 它表示当前实例的前一个实例的句柄, 对于这个参数的用法, MSDN中明确表示在Win32 环境下,该参数总是取NULL, 这就是说,在Win32 环境下, 这个参数没有存在感,不起任何作用, 只是在进行WinMain 函数书写时需要将它作为一个参数表示出来而已。
(3) 第三个参数, LPSTR 类型的lpCmdLine,它是一个以空终止的字符串,指定传递给运用程序的命令行参数,
(4) 第四个参数, int类型的 nCmdShow, 指定程序窗口应该如何显示,是最大化,最小化,还是隐藏等等。
这个参数可以有如下取值:
通过对 nCmdShow 这个值进行个性化的设置, 可以为游戏窗口的创建注入很多新鲜的血液。
(4) MessageBox 函数
先写一个在第二章的源代码如下:
#include<Windows.h>
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPSTR lpCmdLine,int nCmdShow)
{
MessageBox(NULL,L"你好,Visual Studio!",L"消息窗口",0);
return 0;
}
下面我们来看看这个示例程序中用于显示出“你好,Visual Studip!”消息窗口的那句代码:
MessageBox(NULL,L"你好,Visual Studio!",L"消息窗口",0);
**说明:它用于显示一个消息框**
我们在MSDN中查到这个函数有如下原型:
int WINAPI MessageBox
(
_In_opt_ HWND hWnd,
_In_opt_ LPCTSTR lpText,
_In_opt_ LPCTSTR lpCaption,
_In_ UINT uType
);
说明:这里的 _In_opt 类似于之前提到过的 _in, 只不过后面多了一个 _opt, 表示可选的, 两个词组合在一起就表示为“可选的输入参数”了, 就是说这个参数我们可以自己填内容,不填具体内容的话直接填NULL也是可以的, 这个选择权在于我们。
● 第一个参数, HWND 类型的hWnd, 表示我们显示的消息框所属窗口的句柄,在后面会介绍句柄的含义, 在此程序示例中,这个参数设置为了NULL, 表示消息框是从属桌面的。
● 第二个参数,LPCTSTR类型的 lpText , 它是一个以NULL结尾的字符串, 表示所要显示的消息的内容。
● 第三个参数, LPCTSTR类型的 lpCaption, 它也是一个以NULL结尾的字符串, 在其中填写我们要显示的消息框的标题的内容。
● 第四个参数, UINT 类型的 uType , 表示我们消息窗口需要什么样的样式, 微软已经为我们定义好了许多可供选择的样式和消息对应的图标, 一些常用的样式列表如下:
常用的图标我们也是通过一些标识名来指定, 有如下几种:
这里我们只是列出了一些常用的标识, 完整版可以自行查阅MSDN
注意: 如果想要多个标识一起使用的话, 我们可以使用逻辑或 把不同的标识连接起来, 具体的符号是 那条斜杠 “ | ”, 注意不是两条斜杠, 比如要创建一个具有Yes和No按钮, 并带有“问号”图标的消息框, 我们就把uType 填成这样 MB_YESNO | MB_ICONQUESTION ,非常直观。 当需要多个标识同时使用的场合, 用一下这条斜杠 “ | ” 连接一下就好了 。
(5) PlaySound 函数
实现音效播放的核心API函数PlaySound 函数的定义如下:
BOOL PlaySound
(
LPCTSTR pszSound,
HMODULE hmod,
DWORD fdwSound
);
说明: 如果要使用PlaySound函数的话, 必须在编译之前连接 winmm.lib 库文件。
● 第一个参数, LPCTSTR类型的 pszSound, 可以看到作为LPCTSTR类型的此参数为一个字符串, 指定了要播放的声音文件, 这个值设为NULL的话, 就会把所有当前播放的声音全部停掉
● 第二个参数, HMODULE类型的 hmod, 包含了我们在第一个参数中指定的声音文件作为资源的可执行文件的句柄, 这里我们把这个参数设为NULL就可以了。
● 第三个参数, DWORD 类型的fdwSound, 是一个用来控制声音播放的一个标志, 下面是一些常用标识的列表, 我们可以使用一个或者多个标识, 标识之间用 “ | ”连接。
在下一小节的FirstBlood 示例程序中, 用的 是 SND_FILENAME 和 SND_ASYNC 这两个标识, 这样PlaySound 函数就会知道第一个参数 pazSound 中填的是文件名, 而且声音是伊布播放的了, 异步播放的意思是 PlaySound 函数会在播放后立即返回调用点。
(6) 示例程序 Firstblood !
● Firstblood 示例程序的代码:
#include<Windows.h>
#progma comment(lib,"winmm.lib")
int WINAPI WinMain(HINSTANCE hInstancem, 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段代码的含义:
● 第一行代码剖析: 包含了一下Windows.h 头文件, 如果我们要编写基于Windows API 的程序,这个头文件一般都要 include 一下,
● 第二段代码剖析,