📄 g01.htm
字号:
Clear();<br> //get the input<br> Get_Input();<br> //perform logic and ai<br> Do_Logic();<br> //display the next frame of animation<br> Render_Frame();<br> //synchronize the display<br> Wait();<br> //the only way that state can be changed is<br> //thru user interaction in the<br> //input section or by maybe losing the game.<br> }break;</p> <p> case GAME_RESTART: //the game is restarting<br> {<br> //this section is a cleanup state used to<br> //fix up any loose ends before<br> //running again<br> Fixup();<br> //switch states back to the menu<br> game_state = GAME_MENU;<br> }break;</p> <p> case GAME_EXIT: //the game is exiting<br> {<br> //if the game is in this state then<br> //it's time to bail,kill everything<br> //and cross your fingers<br> Release_And_Cleanup();<br> //set the error word to whatever<br> error = 0;<br> //note: we don't have to switch states<br> //since we are already in this state<br> //on the next loop iteration the code<br> //will fall out of the main while and<br> //exit back to the OS<br> }break;</p> <p> default: break;</p> <p> }//end switch<br> }//end while<br> //return error code to operation system<br> return(error);<br> }//end main</p> <p> 尽管清单1.1是一个没有任何功能的程序,但通过学习其游戏循环的结构可以获得很好的思路。所有的游戏循环大都按照这个结构的一种形式或另一种形式进行设计。图1.5表示了游戏循环逻辑的状态转换图。如读者所见,状态转换是非常连贯的。<br> 关于游戏循环和有限态计算机(FSM)的内容将在本章最后涉及FreakOut演示游戏的章节中再进行更详细的讨论。 </p> <p> <b>常规游戏编程指导</b></p> <p> 下面讨论一下读者所关心,也是游戏编程常用的技术和基本原理,这有利于简化游戏编程的复杂程度。<br> 首先,视频游戏是运行于超高性能计算机上的游戏程序。对于时间或内存要求特别严格的代码部分不能使用高级API来编程,和游戏代码内部盾环有关的部分,大都需自已手工编写,否则游戏将会碰到严重的速度和性能问题。当然,这并不意味着就不能信任DirectX等API编程工具,因为DirectX以高性能和心可能“瘦”的方式编写。但在通常情况下,要避免高级的函数调用。<br> 除上述情况应多加注意外,在编程时还应留意下面的编程技巧。</p> <p> 技巧:不要怕使用全局变量,许多视频游戏不使用大量的带有形参的、与时间相关的函数,而是使用一个全局变量来代替,例如一个函数的代码如下:<br> void Plot(int x,int y,int color)<br> {<br> //在屏幕上画一个点像素<br> video_buffer[x + y * MEMORY_PITCH] = color;<br> }//结束Plot<br> 函数体运行的时间小于函数调用所需的时间。这是由于参数压入和弹出堆栈造成的。在这种情况下,更好的方法可能是创建一个全局变量,然后在调用前进行赋值,像下面一样:<br> int gx,gy,gz,gcolor;//定义一些全局变量<br> void Plot_G(void)<br> {<br> //使用全局变量来画一个点像素<br> video_buffer(gx + gy * MEMORY_PITCH] = gcolor;<br> }//结束Plot_G</p> <p> 技巧:使用内联功能。通过使用内联指令来完全摆脱调用功能甚至能够改善上面的技巧。内联指令不调用函数,而指示编译器将被调用函数代码放在需要调用该函数的最佳位置,这样做会使程序变得更大,但却提高了运行速度。下面是一个实例。<br> inline void Plot_I (int x,int y,int color)<br> {<br> //在屏幕上画一个点像素<br> video_buffer[x + y * MEMORY_PITCH] = color;<br> }//结束Plot_I<br> 注意:这里并没有使用全局变量,因为编辑器有效运行了相同类型数据的别名,但是全局变量迟早会派上用场,如果在函数调用时,一个或两个形参已改变,由于没有重新加载,所以旧的参数值有可能仍被使用。</p> <p> 技巧:尽量使用32位变量而不用8位变量或16位变量,Pentium和之后的处理器全部都是32位的,这就意味着它们并不喜欢8位或16位的数据字符,实际上,更小的数据可能会由于超高速缓存和其他相关的内存寻址异常而使速度下降,例如,读者可能创建一个如下所示的结构:<br> struct CPOINT<br> {<br> short x,y;<br> unsigned char c;<br> }//结束CPINT <br> 尽管这个结构看上去很好,但实际并非如此!首先,结构本身目前是一个5字符长的结构——2个short+1个char=5。这实际上是一个很差的设计,这将导致内存地址崩溃。更好的结构形式如下:<br> struct CPOINT<br> {<br> int x,y;<br> int c;<br> }//结束CPINT</p> <p><br> C++ 提示:除了默认的公共可见性外,C++中的结构更像是“类”。</p> <p> 这种新结构要更好一些。首先,所有的成员都是相同尺寸——也就是说整数的大小为4字节。因此,单个指针可以通过递增DWORD(双字节)的边界访问任何单元。当然,这种新结构的大小 就是3个整数长,即12字节,至少是4的倍数,或者在DWORD边界上。这样将明显地提升性能。<br> 实际上,如果读者真想稳妥地话,应当将所有的结构都变为32字节的倍数。由于Pentium家庭处理器芯片上标准缓存线长度是32倍数,因而这是一个最佳长度。可以通过人工虚设单元或者使用编辑指令(最简单的方法)来满足这个要求。当然,这可能会浪费大量的内存,但是为了提高速度这是值得的。</p> <p> 技巧:注释你的代码,游戏程序员不注释代码是出了名的,不要犯相同的错误。用额外的输入换取整洁,注释良好的代码是值得的。</p> <p> 技巧:程序应以类似RISC(精简指令系统计算机)的形式来编写。换句话说,尽量简化你的代码,而不是使它更复杂。Pentium和PentiumⅡ处理器特别喜欢简单指令,而不是复杂的指令,你的程序可以长些,但应尽量使用简单指令,使程序相对于编辑器来说更加简单些。例如,不要编写类似下面的程序:<br> </p> <p> if((x+=(2*buffer[index++])>10)<br> {<br> //进行工作<br> }//结束</p> <p> 应这样做<br> x+=(2*buffer[index]);<br> index++<br> if(x>10)<br> {<br> //进行工作<br> }//结束if</p> <p> 技巧:按照这种方式来编写代码有两个原因,首先,它允许调试程序在代码各部分之间放置断点;第二,这将更易于编译器向Pentium处理器传送简单指令,这样将使处理器使用更多的执行单元并行地处理代码。复杂的代码就比较糟糕。 </p> <p> 对于简单的、是2的倍数的整数乘法运算,应使用二进制移位运算。因为所有的数据在计算机中都以二进制存储,位组合向左或右移动就等同于乘法和除法运算。例如:<br> int y_pos = 10<br> //将y_pos乘以64<br> y_pos = (y_pos << 6);//2^6=64</p> <p> 相似的有</p> <p> {<br> //将y_pos除以8<br> y_pos = (y_pos >> 3);//1/2^3=1/8<br> 当读者接触到优化那一章时,将会发现更多的、类似的技巧。哈哈,酷吧!</p> <p> 技巧:编写高效的算法。世界上所有的汇编语言都不会将n^2算法运行得更快些,更好的方法是使用整齐、高效的算法而不是蛮干。</p> <p> 技巧:不要在编程过程中优化代码。这通常会浪费时间。等到完成主要的代码块或整个程序后才开始进行繁重的的优化工作。这样可以节省你的时间,因为你必须处理一些模糊的代码或不必要的优化。当游戏编程完成时,才到了剖析代码、查找问题以优化程序的时间。另一方面,程序要注意错落有致,不要杂乱无章。</p> <p> 技巧:不要为简单的对象编写大量的复杂的数据结构,仅仅因为连接的清单非常酷并不意味着必须使用它们,对于静态数组而言,其元素一般为256个,的以只需为之静态分配内存并进行相应的处理即可。视频游戏编程90%都是数据操作,游戏程序的数据应尽可能简单、可见,以便能够迅速地存取它、随意操作它或进行其他处理,确保你的数据结构按照这一原则进行处理。</p> <p> 技巧:使用C++应谨慎。如果读者是位老练的高手,继续前进去做你喜欢的事,但是不要去疯狂追求类,或使游戏程序过于复杂以至于超出一般计算机的承受能力,简单、直观的代码是最好的程序,也最容易调试。我从来都不想看多重的隶属关系。</p> <p> 技巧:如果感到前路荆棘丛生,那就停下来,回头然后绕路而行,我见过许多游戏程序员开始于一条很差的编程路线,然后葬送自己。能够意识到自己所犯的错误,然后重新编写500行的代码要比得到一个不是期望的代码结构要好得多,因此,如果在工作中发现问题,那就要重新评估并确保它是值得花时间补救的。</p> <p> 技巧:经常备份你的工作。在编写游戏代码时,需要相当频繁地锁定系统。重新做一个排序算法比较容易,但是要为一个新角色或碰撞检测重新编写AI则是另一回事。</p> <p> 技巧:在开始你的游戏项目之前,进行一下组织工作,使用合理的文件名和目录名,提出一种一致的变量命名约定,尽量对图形和声音数据使用分开的目录,而不是将其全部都放置在一个目录中。</p> <p><b>使用工具</b></p> <p> 过去编写视频游戏通常只不过需要一个文本编辑器和一个简略的自制图形程序。但是现在事情就变得复杂一点了,读者至少需要一个C/C++编译器、一个2D的图形程序和一个声音处理程序。此外,如果读者想编写一个3D游戏的话,读者可能还需要一个3D的模型,而如果读者想使用任何MIDI设备的话,还要有一个音乐排序程序。<br> 让我们来浏览一下目前流行的产品及其功用。</p> <p><b>C/C++编译器</b></p> <p> 对于Windows 9X/NT的研制来讲,简直没有比MS VC++5.0+更好的编译器了。它可以做任何读者想做的事,甚至更多。所产生的.EXE文件是最快的有效代码。Borland编译器也可以工作得很好(并且它要便宜得多),但是它的特性设置较少。在任何情况下,读者不一定需要上述任何一种编译器增强版本,一个能够产生Win32平台下的.EXE文件的学生版本就已经足够了。</p> <p><b>2D艺术软件</b></p> <p> 这儿读者可以得到图形程序、画图程序和图像处理程序。图形程序主要允许读者以原色一个像素、一个像素地绘制和变换图形。直到现在为止,JASC公司的Paint Shop Pro5.0+还是性价比最佳的软件包。Fractal Design Painter也很好,但是它更适用于传统的艺术家,而且它很昂贵。我喜欢使用Corel Photo-Paint,但是对于网络游戏新手的需要来讲,它的功能的确有点偏大。 <br> 另一方面,画图程序允许读者创建图像,通常用曲线、直线和2D的几何原型来创建图像。这些程序并不是很有用,但如果读者需要的话,Adobe Illustrator是一个很好的选择。<br> 2D艺术程序中的最后一类是图像处理类。这些程序多用于产品的后期制作,而不是前期的艺术创建。Adobe Photoshop是大多数人喜欢的软件,但是我认为Corel Photo-Paint更好一些。读者自己来决定吧。</p> <p><b>声音处理软件</b></p> <p> 目前用于游戏的所有的声音效果(SFX)90%都是数字样本,采用这种类型的声音数据来工作,读者应当需要一个数字声音处理程序。这一类中最好的程序是Sound Forge Xp。目前为止,它具有我所见到的最复杂的声音处理能力,并且使用也最方便。</p> <p><b>3D造型软件</b></p> <p> 这是挑战经济实力的软件。3D造型软件价格可能需要上万美金,但是最近也有大量的低价的3D造型软件上市,并且也具有足够的功能来制作一部影片。我主要是使用简单中等复杂程序的3D造型和动画软件——Caligari trueSpace Ⅲ+。在这种价位上,这是最好的3D造型软件,只要几百美金,并且拥有最好的界面。<br> 如果读者希望功能更加强大并追求绝对的超级现实主义,3D Studio Max Ⅱ+就可以做到这一点,但是它的价格大约要2500美金,因此应当认真考虑一下。然而如果我们使用这些造型软件只是用来创建3D网络,而不是渲染,那么所有的其他修饰也就不需要了。这样tureSpace就足以应付。</p> <p><b>音乐和MIDI排序程序</b></p> <p> 目前的游戏中有两类音乐:纯数字式(像CD一样)和MIDI(乐器数字界面)式,MIDI是一种基于人工记录数据的合成音效。如果想制作MIDI信息和歌曲,读者还需要一个排序软件包。一种性价比最佳的软件包是Cakewalk,因此,如果读者打算记录和制作MIDI音乐的话,建议最好去了解一下这个软件。在涉及DirectMusic内容的第10章“用DirectSound和DirectMusic演奏乐曲中”中,我们将对MIDI数据再作探讨。</p> <p> 技巧:现在是最酷的部分......许多软件制造商将许我在CD上列出了它们软件的共享版或评测版,赶快去体验这些软件吧!</p> <p><b>从准备到完成——使用编译器</b></p> <p> 学习Windows游戏编程的一件最容易令人灰心丧气的事是学习如何使用编译器。大多数情况下,读者对开始编写游戏程序如此激动,以至于全身心地投入到IDC(集成开发环境)中去尝试进行编译,然后就出现了一百万条编译和软件错误!为了有助于解决这个问题,让我们首先回顾一下有关编译器的一些基本概念。<br> 0. 请读者务必阅读全部编译器指令!<br> 1. 必须在你的系统上安装DirectX SDK(软件开发工具包)。你所要做的就是在CD上查找到<DirectX SDK>上当,阅读README.TXT文件,并按说明进行操作(实际上只不过是“单击DiretC SDK INSTALL.EXE程序”)。<br> 2. 我们要制作的是Win32.EXE程序,而不是.DLL文件和ActiveX组件等等。因此如果读者想编译的话,需要做的第一件事情是使用编译器创建一个新的工程或工作区,然后将目标输出文件设定为Win32.EXE。使用VC++5.0编译器进行这一步的工作如图1.6所示。<br> 3. 应用添加文件(ADD Files)命令从主菜单或工程节点本身向工程添加源文件。对于使用VC++5.0编译器而言。其操作过程如图1.7所示。<br> 4. 从接触到DirectX一章时起,就必须要包含下面列出的和图1.8所表示的DirectX COM界面库文件。<br> ·DDRAW.LIB<br> ·DSOUND.LIB<br> ·DSOUND3D.LIB<br> ·DINPUT.LIB<br> ·DMUSIC.LIB<br> ·DSETUP.LIB<br> 这些DirectX.LIB文件位于所安装的DirectX SDK根目录下的<LIB>目录下。必须将这些.LIB库文件添加到读者的工程或工作区中。读者不可能只添加搜索路径,因为搜索引擎会发现编译器本身安装的库文件和旧的DirectX3.0的.LIB文件。如果是这样做的话,读者可能不得不将Windows多媒体扩展库文件——WINMM.LIB加入到工程中去。该文件位于读者的编译器安装目录下的<LIB>目录下。<br> 5. 准备编译你的程序</p>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -