收藏 分享(赏)

游戏编程指南.doc

上传人:涵涵文库 文档编号:12195599 上传时间:2021-11-03 格式:DOC 页数:203 大小:1.71MB
下载 相关 举报
游戏编程指南.doc_第1页
第1页 / 共203页
游戏编程指南.doc_第2页
第2页 / 共203页
游戏编程指南.doc_第3页
第3页 / 共203页
游戏编程指南.doc_第4页
第4页 / 共203页
游戏编程指南.doc_第5页
第5页 / 共203页
亲,该文档总共203页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述

1、游戏编程指南A Guide to Game Programmingv1.10alpha最后更新于2003.1.14本文基于VC7.0 / DirectX 9.0 / Winsock 2.2推荐使用Word 2000及以上版本阅读大家看完之后如果有什么意见和建议请务必在留言簿提出,谢谢!如果你认为任何地方写错了,请告诉我如果你认为任何地方难以理解,请告诉我如果你觉得这篇东西还不算太垃圾,欢迎推荐给你的朋友J本文99%为原创内容,转载时请只给出连接,谢谢!也希望大家不要随便修改,谢谢!使用查看-文档结构图可大大方便阅读本文档彭博 著By Peng BoEmail: Kane_PQQ: 498252

2、6http:/目录6目 录游戏编程指南1目 录1导 读1第一章 表述游戏的语言11.1 VC.net概述11.2 入门知识41.2.1 数与数据类型41.2.2 变量与常量41.2.3 Namespace51.2.4 操作符与表达式61.3 预编译指令71.4 结构,联合和枚举81.4.1 结构81.4.2 联合91.4.3 枚举101.5 控制语句101.5.1 判断和跳转语句101.5.2 选择语句111.5.3 循环语句131.6 函数131.7 指针、数组与字符串171.7.1 指针171.7.2 数组191.7.3 字符串221.7.4 小结231.8 多文件程序的结构231.9 常

3、用函数25第二章 如何说得更地道292.1 定义和使用类292.2 类的构造函数322.3 类的静态成员342.4 运算符重载352.5 类的继承382.6 虚函数和抽象类412.7 模板422.8 优化程序452.9 调试程序47第三章 容纳游戏的空间493.1 基本Windows程序493.2 WinMain函数533.2.1 简介533.2.2 注册窗口类533.2.3 创建窗口553.2.4 显示和更新窗口563.2.5 消息循环573.3 消息处理函数583.4 常用Windows函数593.4.1 显示对话框593.4.2 定时器593.4.3 得到时间603.4.4 播放声音60

4、第四章 描绘游戏的画笔614.1 初始化DirectDraw614.1.1 简介614.1.2 DirectDraw对象624.1.3 设置控制级和显示模式634.1.4 创建页面644.2 后台缓存和换页664.3 调入图像674.4 页面的丢失与恢复674.5 透明色684.6 图像传送684.7 程序实例724.8 图像缩放724.9 释放DirectDraw对象72第五章 丰富画面的技巧745.1 填涂颜色745.2 输出文字755.3 GDI作图755.4 程序实例765.5 锁定页面765.6 程序提速785.7 特殊效果825.7.1 减暗和加亮825.7.2 淡入淡出835.7

5、.3 半透明835.7.4 光照845.7.5 动态光照855.7.6 光照系统885.7.7 天气效果88第六章 加速游戏的魔法896.1 内嵌汇编简介896.2 基本指令906.3 算术指令916.4 逻辑与移位指令936.5 比较、测试、转移与循环指令936.6 MMX指令集之基本指令966.7 MMX指令集之算术与比较指令986.8 MMX指令集之逻辑与移位指令996.9 MMX指令集之格式调整指令100第七章 我没有想好名字1027.1 读取键盘数据1027.2 读取鼠标数据1037.3 恢复和关闭DirectInput1047.3.1 恢复DirectInput设备1047.3.2

6、 关闭DirectInput1047.4 初始化和关闭DirectX Audio1047.4.1 初始化DirectX Audio1047.4.2 关闭DirectX Audio1057.5 播放MIDI和WAV音乐1057.5.1 调入MIDI和WAV文件1057.5.2 播放MIDI和WAV文件1067.5.3 停止播放1077.6 在3D空间中播放音乐1077.7 播放MP3音乐1097.7.1 调入MP3文件1097.7.2 播放MP3文件1097.7.3 停止播放和释放对象110第八章 支撑游戏的基石1118.1 链表1118.2 哈希表1118.3 快速排序1128.4 深度优先搜

7、索1138.5 广度优先搜索1178.6 启发式搜索1208.7 动态规划1268.8 神经网络1288.9 遗传规划129第九章 向三维世界迈进1319.1 概述1319.2基本知识1339.2.1 初始化DXGraphics1339.2.2 关闭DXGraphics1359.2.3 恢复DXGraphics设备1359.3 设置场景1359.3.1 设置渲染状态1359.3.2 设置矩阵1369.4 创建场景1379.4.1 调入3D场景1389.4.2 调入2D图像1399.5 刷新场景1409.6 渲染场景1419.6.1 渲染3D场景1419.6.2 渲染2D图像1419.7 改变场

8、景1419.8 显示文字1429.9程序实例143第十章 我没有想好名字14410.1 灯光14410.2 半透明14510.3 纹理混合14610.4 雾14810.5 凹凸贴图与环境贴图14910.6 粒子系统14910.7 骨骼动画14910.8 镜子15110.9 影子151第十一章 我没有想好名字15211.1 基本概念15211.2 程序流程15211.2.1 服务器端15211.2.2 客户端15311.3 程序实例15311.4 错误处理15811.5 显示IP地址15811.6 更有效地传送数据159第十二章 创造我们的世界16112.1 程序流程16112.2 程序结构16

9、212.3 基本方法16312.4 SLG编程要点16312.4.1 电脑AI16312.5 RPG & ARPG编程要点16312.5.1 迷宫的生成16312.5.2 脚本技术16312.6 RTS编程要点16312.6.1 寻路16312.6.2 电脑AI16312.7 FPS编程要点16412.7.1 移动16412.7.2 碰撞检测16412.8 游戏中的物理学165附 录166附录一 Windows常见消息列表166附录二 虚拟键列表171Windows消息中的虚拟键171DirectInput中的虚拟键172附录三 DirectX函数返回值列表174DirectDraw部分174

10、Direct3D部分181附录四 Winsock函数返回值列表183附录五 游戏编程常用网址187附录六 中英文名词对照188附录七 常见问题及解决办法1891. 程序编译时出现Warning1892. Cannot Execute Program1893. Unresolved External Symbol1894. 运行时出错1895. 大家还有什么问题,可以告诉我189导读导 读在开始阅读全文之前,希望你能抽出一些时间阅读这里的内容一、你想编一个怎样的游戏?(1)星际争霸,帝国时代,英雄无敌,大富翁4,轩辕剑3,传奇,石器时代这些都是正宗的2D游戏,其标志是:视角完全固定或只有四个观察

11、方向。这些游戏中特效不多,即使有也不需要使用汇编进行加速。推荐阅读:第1、2、3、4、5章及第12章的相关部分。可选阅读:第7、8章。如果需要网络功能,需阅读第11章。(2)暗黑2,秦殇这是一类比较特殊的2D游戏,其特点在于各种特效(半透明,光影效果等)的大规模使用。有的此类游戏还可以使用3D加速卡来加速2D特效。推荐阅读:第1、2、3、4、5、6章及第12章的相关部分。可选阅读:第7、8、9、10章。如果需要网络功能,需阅读第11章。由于现在的显卡几乎都能很好地支持3D加速功能,所以如果你打算放弃对没有3D加速卡的计算机的支持,可不阅读第4、5、6章,而推荐阅读第9章和第10章的第1、2节。

12、(3)反恐精英,雷神,魔兽争霸3,地牢围攻,FIFA,极品飞车,MU这些都是纯3D游戏,也代表了目前游戏的发展趋势。推荐阅读:第1、2、3、7、9、10章及第12章的相关部分。可选阅读:第8章。如果需要网络功能,需阅读第11章。第一章 表述游戏的语言 28第一章 表述游戏的语言想必大家都听说过“计算机语言”吧,我们就要靠它来向计算机表述我们的游戏到底是怎样的-这个过程就是所谓“编程”。由于游戏对速度的要求较高,过去我们一般使用C语言,因为用它编制的程序不仅执行速度快,还可以充分地使用硬件的各种资源。而现在(不过也是十多年前的事了J)有了C+语言,它是对C语言的重大改进。C+语言的最大特点是提供

13、了“类” ,成为了“面向对象”的语言。关于此,我们会在第二章详细介绍。本章将先介绍一些游戏编程所必需的C+语言基础知识。最后需要提醒大家的是,在学习本章时最好边学边实践,自己试着写写C+程序。1.1 VC.net概述在切入C+语言之前,我们有必要简略地介绍一下VC.net的基本使用方法。首先当然是安装VC.net,值得注意的是,VC.net中附带的DirectX SDK并不是8.1最终版,推荐访问http:/ Page,在Profile一栏选择Visual C+ Developer。第二步是转到Get Started一栏,选择New Project,并在出现的窗口选择Visual C+ Pro

14、jects一栏中的Win32 Project,填好Name和Location,按OK,这时会出现一个Win32 Application Wizard。此时需要在Application Settings一栏把Empty project前的方框勾上,以防VC.net在工程中加入一些无意义的垃圾;如果想编DOS窗口下的程序,例如这一章和下一章的程序,还要把Console Application选上。最后按Finish就完成了工程的创建。图1.1 Start Page在屏幕的左边,我们可以看到出现了Solution Explorer和Dynamic Help两栏,其中Solution Explorer

15、又可变为Class View或Resource View,其内容分别为:工程中包含有什么文件,工程中的类、变量和函数的结构,工程中包含有什么资源。至于Dynamic Help就是动态帮助,非常方便。大家会注意到现在工程还没有文件,所以接下去我们需要学习如何新建一个文件,如果你想新建的文件是C+程序文件(.cpp),那么应该在Source Files上按右键,选择Add - Add New Item,在出现的窗口中选择C+ File,定好名字,再按Open即可(假如你加入的文件叫Haha.cpp,Solution Explorer将如右图所示);如果你想新建的文件是头文件(现在先不要管头文件是什

16、么),在Header Files按右键,也选择Add - Add New Item,在出现的窗口中选择Header File,也定好名字并按Open就行了。在工具栏的中部可以更改程序的模式:Debug或是Release。在一般情况下,建议大家选择Release,可以减少文件大小并增加运行速度;而在调试程序时,必须选择Debug。在默认的情况下,编译好的程序会相应的放在工程目录下的Debug或Release子目录内。最后我们来看看一个重要的操作,即如何把LIB文件(现在也不要管LIB文件是什么)加入工程中:首先在Solution Explorer窗口中找到工程名,然后在上面按右图1.2 键并选择

17、Properties,在出现的窗口中选择Linker - Input - Additional Dependencies,最后填上要加入的LIB文件名即可。OK,下面让我们看一个简单的C+程序:/*- First C+ Program -*/#include /现在你只需知道要使用输入输出语句就必须写这行。 /这一行结尾不用加分号因为它不是真正的C+语句。 /在1.3节将会对此做出解释。using namespace std; /这是什么意思呢在1.2.3节会有解释。int a=5; /声明变量a,同时顺便赋5给它。C+中变量都需先声明后使用。 /int说明了a的数据类型为整数。int squ

18、are(int x); /声明函数square,它有一个参数,为int类型,即整数。返回值也/为int类型。C+中的函数都需要先声明后给出定义。int square(int x) /函数真正定义。return x*x; /返回x*x,可以在一个语句中的间隔位置插入回车将其分成几行。int main( ) /主函数,每个DOS窗口下的C+程序都需要它int A; /声明变量A。C+中变量声明的位置是比较随意的。coutA; /输入A, 注意箭头方向的更改。coutA=Aendl; /依次输出A=、A的值并换行。endl代表换行。couta+A=a+A; coutA*A=表示,小于等于则是=。&表

19、示逻辑与,|表示逻辑或,!表示逻辑非。例如如果a=8,则( (a!=9) & ( (a=3) | (a=6) ) )为false。 (右移)非常好用,作用是把这个数的二进制形式向左或右移位(cin和cout中的被使用了运算符重载,所以意义不同,具体可参阅2.4节),举两个例子也许会好说明些:18(二进制形式为0010010)3得到9(二进制形式为0001001) 我们可以看到,左移和右移可以代替乘或除2的n次方的作用,而且这样做可以节省不少CPU运算时间。在程序优化中这一种方法是十分重要的,例如a*9可用(a3)+a代替(注意,+运算比b)?a:b可返回a和b中的较大者。 值得注意的是由于C+

20、的操作符众多,所以运算先后次序较复杂,如果没有注意到这一点而少加了几个括号将出现出人意料的结果。下面按优先级高到低列出了C+中的操作符:1. ()(小括号) (数组下标).(类的成员) -(指向的类的成员)2. !(逻辑非) .(位取反) -(负号) +(加1) -(减1) &(变量地址)3. *(指针所指内容) sizeof(长度计算)4. *(乘) /(除) %(取模)5. +(加) -(减)6. (位右移)7. (小于) (大于) = (大于等于)8. = (等于)!= (不等于)9. & (位与)10. (位异或)11. | (位或)12. & (逻辑与)13. | (逻辑或)14.

21、? : (?表达式)15. = += -=(联合操作) 在表达式方面,C+基本与其它语言相同。只是C+为了简化程序,提供了联合操作:左值 操作符=表达式等价于左值= 左值 操作符 表达式。例如a*=6+b等价于a=a*(6+b),c+=8等价于c=c+8。在C+中,所有表达式都有返回值。一般来说,(左值 操作符 右值)表达式的返回值与右值相同;条件表达式如(ab)的返回值在条件成立时为1,不成立时为0。1.3 预编译指令现在该解释在第一个例子中#include 的意义了,其实这句是预编译指令。预编译指令指示了在程序正式编译前就由编译器进行的操作,可以放在程序中的任何位置。常见的预编译指令有:(

22、1)#include 指令该指令指示编译器将xxx.xxx文件的全部内容插入此处。若用括起文件则在系统的INCLUDE目录中寻找文件,若用 括起文件则在当前目录中寻找文件。一般来说,该文件后缀名都为h或hpp,被称为头文件,其中主要内容为各种东西的声明。那么为什么在第一个程序中我们可以省略iostream.h的.h呢(大家可以自己找找,会发现并没有一个叫iostream的文件)?这有一个小故事。当初ANSI在规范化C+的时候对iostream.h进行了一些修改,比如说吧其中的所有东西放进了一个叫std的namespace里(还有许多头件都被这样修改了)。但是程序员就不答应了,因为这意味着他们的

23、程序都要被修改才能适应新编译器。于是ANSI只好保留了对原来调用iostream.h的方法(#include )的支持,并把调用新的iostream.h的方法修改成现在的样子(#include )。言归正传,我们#include 之后编译器会看到iostream.h中对输入输出函数的声明,于是知道你要使用这些函数,就会将包含有输入输出函数定义的库文件与编译好的你的程序连接,形成可执行程序。注意不会在当前目录下搜索头文件,如果我们不用而用把头文件名扩起,其意义为在先在当前目录下搜索头文件,再在系统默认目录下搜索。(2)#define指令该指令有三种用法,第一种是定义标识,标识有效范围为整个程序,

24、形如#define XXX,常与#if配合使用;第二种是定义常数,如#define max_sprite 100,则max_sprite代表100(建议大家尽量使用const定义常数);第三种是定义函数,如#define get_max(a, b) (a)(b)?(a):(b) 则以后使用get_max(x,y)可得到x和y中大者(这种方法存在一些弊病,例如get_max(a+, b)时,a+会被执行多少次取决于a和b的大小!所以建议大家还是用内联函数而不是这种方法提高速度。关于函数,请参阅1.6节。不过这种方法的确非常灵活,因为a和b可以是各种数据类型,这个特点我们可以换用2.7节介绍的模板

25、实现)。(3)#if、#else和#endif指令这些指令一般这样配合使用:#if defined(标识) /如果定义了标识 要执行的指令 #else 要执行的指令 #endif在头文件中为了避免重复调用(比如说两个头文件互相包含对方),常采用这样的结构:#if !(defined XXX) /XXX为一个在你的程序中唯一的标识符, /每个头文件的标识符都不应相同。/起标识符的常见方法是若头文件名为abc.h/则标识为abc_h#define XXX真正的内容,如函数声明之类#endif1.4 结构,联合和枚举1.4.1 结构结构可以把不同变量变为一个变量的成员。例如:struct S /定义

26、结构Sshort hi; /结构S的第一个成员short lo; /结构S的第二个成员;S s; /定义S类型的变量s然后我们就可以像s.hi和s.lo一样使用s的成员。1.4.2 联合联合可以让不同变量共享相同的一块空间,举个例子:#include using namespace std;struct Sshort hi;short lo;union MIXlongl;Ss;charc4;void main ( )MIX mix;mix.l=100000;coutmix.s.hiendl;cout=9) a+; else a-;值得注意的是C+中的“真”与“假”的意义就是这条表达式不为0 还

27、是为0。比如if (a-b) do_stuff; 的作用与 if (a!=b) do_stuff; 相同。 臭名昭著的跳转语句(不过有时候你还是不得不用)则是这样的: 标号:语句;(一般来说标号用_开头) goto标号; 举个例子方便大家理解:#include using namespace std;void main( ) int target=245; int a; cout欢迎您玩这个无聊的猜数游戏endl;cout您的目标是猜中我想好的数endl; couta; if (atarget) cout您刚才输入的数太大了!endl; cout; goto _input; else if (

28、atarget) cout您刚才输入的数太小了!endl; cout再猜一次:; goto _input; else cout恭喜你,猜对了!endl; 1.5.2 选择语句C+中的选择语句很灵活,我们先看看与其它高级语言相似的形式:switch (变量)case常量/常数1: 语句;/注意,这里可有多个语句且不需用 括起,不过其中不能定义变量。 break; /为什么要加这一句呢?下面会解释。case常量/常数2: 语句; break; case 常量/常数n: 语句; break;default: /如所有条件都不满足则执行这里的语句。 语句;/这后面就没有必要加break;了。break

29、的作用其实是防止继续执行后面的语句,试试下面的程序: #include using namespace std; const aaa=5; void main( ) int a; cina; switch(a) case 0: coutendl您输入的是0; case 3: coutendl您输入的是3; case aaa: coutendl您输入的数与aaa相等; default: coutendl?; 按照一般人的想法,当你输入0、2、3、5时会分别得到您输入的是0、 ?、 您输入的是3、 您输入的数与aaa相等,不过你可以试试结果是否真的是这样。试完后,你可以加上一些break再看看结果又将是怎样。1.5.3 循环语句 先介绍while循环语句,共有两种形式:第一种是while (条件) 语句,意义为先判断条件是否满足,如果满足则执行语句(否则退出循环),然后重复这个过程。第二种形式是do 语句 while (条件),意义为先执行语句再判断条件,如果条件成立则继续执行语句(不成立就退出循环),这个过程也会不断重复下去。例如while(x+=

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 高等教育 > 大学课件

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报