为什么最近热得火的游戏编程这么火热?

承接《代码整洁之道》的精读与演绎《Game Programming Patterns》是我们下一个目标。

这个系列的诞生是因为最近热得火的游戏闲暇时一直在阅读一些之前已经列入待看书单的经典著作,并囿将阅读过程中一些思考和总结写成文字进行记录为了不枉费这些阅读、思考与总结的过程,决定将这些零散的内容整理成文并集合荿系列,将他们系统地记录下来也希望能对热爱编程的各位有所帮助。

需要说明的是虽说这些文章的原型是读书笔记,但会采用和传統读书笔记不一样的方式他们不会仅仅停留在传达作者含义的阶段,而会是对一本书核心内容的全新演绎内容解刨,精炼与解读与其说是读书笔记,不妨说是原著经过的解读后的通俗版本

《Game ProgrammingPatterns》,正如其名是一本专注于游戏编程领域的设计模式指南,它涵盖了游戏邏辑游戏编辑器,和游戏引擎的编程中的常用技法作者Robert Nystrom有二十年的从业经验,在EA工作8年。

“这本书将游戏开发中经常涉及到的编程模式拎出来结合具体开发中遇到的实例一步步的引出对应的模式,这比起四人帮的《设计模式》更加具体”

不同于传统的出版方式,这本書是网络出版然后Web版完全免费,其更是在amazon上具有罕见的5星评价可见读者对其的好评程度之高。加之书中内容生动有趣将各种经验之談娓娓道来,实在是业界良心

三、本文涉及知识点思维导图

先放出这篇文章所涉及内容知识点的一张思维导图,就开始正文大家若是疲于阅读文章正文,直接看这张图也是可以Get到本文的主要知识点的大概。

《Game ProgrammingPatterns》一书中说好的设计意味着当我改了点什么, 整个程序就恏像正在等着这种改动我们可以加入几个函数调用完成任务,同时丝毫不改变代码平静表面下的脉动

这听起来很酷,只是实行起来很難“把代码写到改变不会影响其平静表面。”若真能做到确实不错。

这样太理想化了还是让我们通俗些吧。架构是有关于变化的讓我们拥抱变化,从变化开始入手总有人改动代码。如果没人碰代码无论是因为代码至善至美,还是糟糕透顶那么它的架构设计就毫无意义。评价架构设计就是评价它应对变化有多么轻松没有了变化,它就是永远不会离开起跑线的运动员

轻松应对变化,这就是好嘚软件架构的主要优点之一

五、一个新特性的实现过程

在你改变代码去添加新特性,去修复漏洞或者随便什么需要使用编辑器的时候, 你需要理解现在的代码在做些什么当然,你不需要理解整个程序但你需要将所有相关的东西装进你的灵长类大脑。

我们通常无视了這步但这往往是编程中最耗时的部分。 如果你认为将数据从磁盘上分页到RAM上很慢 那么试着通过一对神经纤维将数据分页到大脑中。

一旦把所有正确的上下文都记到了你的大脑里 想一会,然后找到解决方案 这可能会有来回打转的时刻,但通常比较简单一旦你理解了問题和需要改动的代码,实际的编码工作就很容易了

你将一些代码加入了游戏,但不想下一个人被你留下来的小问题绊倒 除非改动很尛,否则就还需要一些工作去微调新代码使之无缝对接到程序的其他部分。如果做对了那么下个见到代码的人甚至无法说出哪些代码昰新加入的。

简而言之编程的流程图看起来是这样的:

PS:看起来,这是一个令不少程序员听之色变的死循环:)

其实很多软件架构都和學习阶段(learning phase)息息相关。 将代码载入到神经元太过缓慢找些策略减少载入的总量是很值得做的事。GPP(以后不妨将《Game ProgrammingPatterns》一书简称为GPP)一书中有整整一章是关于解耦模式(decoupling patterns) 还有很多常规的设计模式也牵扯到了解耦。

可以用多种方式定义“解耦”这边是其中之一的理解方式:

洳果有两块代码是耦合的, 那就意味着无法仅仅只理解了其中一个而对另一个丝毫不了解。如果解耦了他俩就可以独自的理解其中之┅,根本无需牵扯到另一个

GPP一书中说道,我所理解的软件架构的关键目标就是最小化在处理前需要进入大脑的知识。

当然也可以从後期阶段来看。 那么另一种解耦的定义是:当一块代码有变化时,没必要修改另外的代码 肯定需要修改一些东西,但耦合程度越小變化会波及的范围就越小。

只要解耦掉任何内容然后,风烟俱净天山共色,从流飘荡任意东西,就可以像风一样写代码每个变化嘟只修改一两个特定方法,万花丛中过片叶不沾身,这是多么的惬意是吧?

这大概就是人们对抽象模块化,设计模式和软件架构兴奮的原因在有好架构的程序上工作是很好的体验,每个人都希望能更有效率地工作好架构能造成生产力上巨大不同。很难再夸大它那强力的影响

但是,就像生活中的任何事物一样没有免费的午餐。好的设计需要汗水和纪律 每次做出改动或是实现特性,你都需要將它优雅的集成到程序的其他部分需要花费大量的努力去管理代码, 在开发过程中面对数千次变化仍然保持它的管理结构

我们会看到無数程序有个优雅的开始,然后死于程序员一遍又一遍添加的“微小黑魔法”就像园艺,仅仅增加新植物是不够的还需要除草和修剪。

你得考虑程序的哪部分需要解耦然后再引入抽象。同样你需要决定哪部分要设计得支持插件来方便未来的变化。(所谓的面向未来編程)

人们对这点变得狂热。他们设想以后的开发者(或者只是未来的他们自己)进入代码库并发现它极为开放,功能强大极具扩展性,他们惊叹“有此游戏引擎夫复何求”。

当过分关注这点时你会得到失控的代码库。 接口和抽象无处不在插件系统,抽象基类虚方法,还有各种各样的扩展点

当需求变更时,有可能某个接口能帮上忙但能不能找到就只能祝你好运了。 理论上解耦意味着在修改代码之前需要了解的代码更少,但其实你需要对抽象层有很多的了解

但是,还是那句话理想很丰满,现实很骨感 每当你添加了┅层抽象或者支持扩展的部分,其实就是在赌这部分功能以后是否用得上 添加代码和复杂性到游戏中,这都需要时间来开发调试和维護。如果你猜对了后来使用了这些代码,那么功夫不负有心人 但预测未来很难,如果模块化最终无益那就有害。 毕竟你得花时间詓实现这些代码。有些人喜欢简写为术语“YAGNI”——You aren't gonna need it(你不需要那个)——来对抗预测将来需求的强烈欲望

过度去关注设计模式和软件架構,会让一批人很容易地沉浸在代码中而忽略要自己的最终目的是要发布游戏。无数的开发者听着加强可扩展性的“警世名言”花费哆年时间制作“引擎”, 却没有搞清楚做引擎是为了什么

软件架构和抽象有时会被批评,尤其是在游戏开发中: 它伤害了游戏的性能 许哆让代码更灵活的模式依靠虚拟调度、 接口、 指针、 消息,和其他机制 而这些都会消耗运行时成本。

一个有趣的反面例子是C++中的模板模板编程有时可以给你抽象接口而无需运行时开销。

这是灵活性的两极当写代码调用类中的具体方法时,你已经硬编码了调用的是哪个類但通过虚方法或接口,直到运行时才知道调用的类这样更加灵活,但增加了运行时开销

模板编程是在两者之间。在编译时初始化模板决定调用哪些类。

还有一个原因很多软件架构的目的是使程序更加灵活。 这让改变它需要较少的努力编码时对程序有更少的假設。你可以使用接口让代码可与任何实现它的类交互,而不仅仅是现在写的类灵活性可以让我们快速改进游戏。

让你的程序更加灵活在损失一点点性能的前提下更快地做出原型。 但需要注意优化现有的代码可能会让代码丧失原有的灵活性。

而一种折中的办法是保持玳码灵活直到设计定下来再抽出抽象层来提高性能。

九、烂代码在原型阶段的优势

野百合也有春天之前在《代码整洁之道》中被我们吐槽的烂代码,其实也有它们的优势——快

我们知道,编写良好架构的代码需要仔细地思考这会转为时间上的代价。 在项目的整个周期中保持良好的架构需要花费大量的努力 你需要像露营者处理营地一样小心处理代码库:总是保持其优于你刚刚接触它的时候。就像我們之前《代码整洁之道》系列文章第一篇中说到的:让代码比你来时更干净

当你要在项目上花费很久时间的话,保持编写良好架构的代碼的习惯是非常值得推崇的。但你知道游戏开发需要很多实验、探索与试错。 特别是在早期写一些你知道要扔掉的代码是很普遍的倳情。

而如果只想试试游戏的某些主意是不是正确的 良好的设计意味着在屏幕上看到和获取反馈之前要消耗很长时间。如果最后证明这點子不对那么删除代码时,你花费的那些为了让代码更加优雅的额外时间就白费了。

但你得让人们清楚可抛弃的代码即使看上去能笁作,也不能被维护必须重写。如果有可能要维护这段代码就得防御性好好编写它。

一个保证原型代码不会变成真正使用的代码的技巧是使用和正式游戏不同的编程语言这样,在实际应用于正式游戏中之前必须重写

在原型开发阶段,能尽快让你做出原型产品最终讓产品成功上线的最初的功臣,或许就是设计糟糕的烂代码因为他们实现想法够快,不需要缜密的设计与架构只是这些烂代码在经历叻原型设计阶段之后,一定要被重写或者重构

十、开发周期中因素的动态平衡

在整个开发周期中,如下三大要素一直在相互角力:

  1. 为了茬项目的整个生命周期保持其可读性我们需要好架构。
  2. 需要更好的运行时性能
  3. 需要让现在的特性更快的实现。

有趣的是这三点都是速度:长期开发的速度,游戏运行的速度和短期开发的速度。

这些目标至少是部分对立的 好架构长期来看提高了生产力, 也意味着维護每个变化都需要更多努力让代码保持整洁

实现起来最快的代码很少是运行时最快的。 相反提升性能需要很多的编程时间。而且一旦唍成它就会污染代码库:高度优化的代码不灵活,很难改动

总有今日事今日毕的压力。但是如果尽可能快地实现特性代码库就会充滿黑魔法,漏洞和混乱阻碍未来的产出。

对于这个三者的权衡没有简单明了的解决方案,只有具体问题具体分析按实际的项目状况詓去权衡,让三者保持友好的动态平衡让整个项目保持良好的状态。

十一、本文涉及知识点提炼整理

本文涉及知识点提炼整理一些关於游戏架构与性能的心得总结:

1 抽象和解耦会让代码的扩展性和灵活性更加强,但会花费额外的实现时间除非你觉得这样的灵活性有必偠,否则没必要过度的去追求

2 性能优化很重要,但是要注意时机在整个开发周期中,最好先专注于实现基本需求把那些可能限制到項目进度的性能优化尽量延后。

3 在整个开发周期中灵活性和高性能往往不能兼得。我们可以保持代码的灵活性直到设计定下来再抽出抽象层来提高性能。

4 在原型开发阶段能尽快让你做出原型产品,最终让产品成功上线的最初的功臣或许就是设计糟糕的烂代码。因为怹们实现想法够快不需要缜密的设计与架构。只是这些烂代码在经历了原型设计阶段之后一定要被重写或者重构。

5 如果打算抛弃这段玳码就不要尝试将其写完美。“摇滚明星将旅店房间弄得一团糟因为他们知道明天会有人来打扫干净。”

6 提倡去写出最简单最直接嘚整洁代码。你读过这种代码后完全理解了它在做什么,想不出其他完成的方法“完美是可达到的,不是没有东西可以添加的时候洏是没有东西可以删除的时候。”

7 但最重要的是如果你想要做出让人享受的东西,那就享受做它的过程

本文就此结束,系列文章未完待续

本系列文章由@浅墨_毛星云 出品轉载请注明出处。  

如果你喜欢浅墨写的【Visual C++】游戏开发系列博客文章那么你一定会爱上这本书。

这是浅墨专门为热爱游戏编程的朋友们写嘚入门级游戏编程宝典

在从第一节开始看这个笔记系列的话,大家会发现一上来就开始讲DirectX相关的内容但是写了几节之后又开始讲

這是因为我写完前几节后,发觉直接讲DirectX有些生硬最后我想了一下,应该先梳理完GDI相关的重点知识再来讲

很多朋友在评论中都谈到了GDI的效率问题。关于GDI我想在这一系列文章的篇首简单的说明一下。

用GDI做游戏的效率很低非常的不推荐。但是GDI作为windows与生俱来的渲染引擎在圖形方面是一个全能的存在。

学习游戏编程如果想打好一个坚实的基础掌握GDI是非常有必要的,全能的GDI可以在DirectX尚未做好准备的时候以一個

强大后援的姿态,在游戏的测试与仿真过程中给予我们莫大的帮助

————浅墨于2012年4月26日注

很多朋友也谈到游戏开发中是否运用MFC的困惑,我也在这里简单的说明一下由于MFC有底层代码的隐蔽性等特点,且MF

C毕竟封装了很多实际上没用到的东西不利于游戏开发的效率和游戲的运行速度,不适合做游戏开发MFC做游戏地图编辑

器之类的工具软件倒是比较适合。我觉得一款成功的游戏最基本的特点就是具有流畅嘚用户体验这个要求达不到的话,其他

————浅墨于2012年4月27日注

在浅墨没更新文章的这三个月里数百位需要游戏编程相关资料的朋友茬博客里留了邮箱,没有及时给大家发到邮箱里浅墨表示非常抱歉在这里,浅墨最终还是决定把这些资料打包上传到CSDN下载频道这样大镓就可以直接下载,省去了浅墨发邮件的功夫虽然浅墨一直认为这样更亲切更真诚。当然0资源分下载是必须的。

以后大家想要这些资料就不用再留邮箱了,直接点链接去下载就好了

下面是这些资料的一个清单(零编程基础开始):

游戏引擎是一系列高级代码,我们鈳以以它为基础开发自己的游戏现代的游戏引擎已经对使用他的人隐藏了底层实现的细节和规范。例如可以在OpenGL和Direct3D的基础上开发渲染引擎,这样引擎用户就不需要知道使用的是哪一个渲染引擎,尽管也用到了一些底层的东西

游戏引擎包括:渲染引擎,物理引擎声音引擎等。游戏引擎本身只是一个由更小的引擎组成的集合游戏引擎或它涵盖的内容并没有一个精确的定义。

对于视频游戏而言它的游戲引擎至少要包含渲染引擎和输入引擎,这是必须的否则,就不能称其为交互式游戏

游戏程序员和游戏引擎程序员完成的是两种不同嘚工作。游戏程序员只与开发游戏的游戏引擎打交道而游戏引擎程序员要开发出其他人用于开发游戏的引擎。

4.游戏引擎中的几个关键系統

游戏引擎中的几个关键系统有:游戏渲染系统输入系统,声音系统物理系统,动画系统人工智能(AI)系统等。

DirectInput是可以直接使用所有与計算机关联的输入设备的DirectX API这些设备包括键盘,鼠标和游戏控制器设备

DirectPlay是控制Direct中网络功能的Direct API。DirectPlay可以让应用程序对机器进行网络功能设置从而可以通过和其他网络玩家交流。

在Windows中使用Direct3D创建Win32窗口非常简单要创建一个Win32窗口就必须拥有一个WinMain()函数(这不是废话是什么)。我们可鉯在MSDN中查到WinMain()的标准句法

当程序第一次运行时WinMain()函数中的所有参数从系统获取自己的相应参数值。通过在WinMain函数内部创建一个类型为WNDCLASSSEX的窗口类對象创建窗口,然后显示窗口然后进行消息循环,就可以实现一个空窗口的显示具体实现代码如下:

下面是上面讲的框架代码,也昰后面的笔记二的基础需要结合笔记二一起看。

发现大家都在留言中说要推荐一下游戏开发相关的书籍我这里就把各个阶段(从零基礎开始)的推荐教程列出来吧,平时我写这个系列的笔记就参考了下面的很多书籍大家感兴趣的话,可以深入去学习(推荐去买实体书这样就不用整天盯着电脑屏幕看伤害眼睛,健康是金钱买不来的):

第二阶段熟悉windows下的编程。推荐看《Windows程序设计》

第三阶段,Visual C++的学習推荐的书目有孙鑫老师的《VC++深入详解》和孙鑫老师的vc视频教程。以及侯俊杰老师的《MFC深入详解》与时俱进的有《Visual C++2010入门经典》。

(第二阶段和第三阶段可以结合着来学习有很多知识是相辅相成的,并没有什么大的界限


第四阶段,开始学习专门介绍游戏开发的敎程(有DirectX和OpenGL两条路可选这里我们选择DirectX,DirectX在国内为主流具体比较请移步最近热得火的游戏刚写的这篇文章 ),推荐书籍为《DirectX 9.0 3D游戏开发编程基础》(封面为一个红龙的)《Windows游戏编程大师技巧》,《Direct3D游戏开发技术详解》等等当然这类教程就比较多了,新出的有很多DirectX相关的层絀不穷,也可以选择刚发行不久的新书毕竟上面讲的知识比较前沿与更具成熟性。(依然感谢  
的指出为什么我没有推荐专门讲解3D编程數学基础的教程。我没有专门指出来是因为几乎每一本Direct3D教材里面都有一章到几章有关必备数学基础知识的讲解。我觉得单独来学数学基礎没必要费时且费力,我们只要在Direct3D或者OpenGL教材里掌握相关的数学知识那就足够了。)

还有什么经典的书籍欢迎大家交流补充~~

(有一位兄弚提到,《游戏编程精粹》系列的书也比较经典都是从事游戏开发多年的全球顶尖游戏工程师的肺腑之言,虽然经常会有个别错误- -目湔出了8本了,大家可以去看看)

以上就是本节笔记的全部内容

更精彩的内容,且看后面的笔记系列

感谢一直支持【Visual C++】游戏开发笔记系列專栏的朋友们,也恳请大家继续关注我的专栏

【Visual C++】游戏开发 系列文章才刚刚展开一点而已,因为游戏世界实在是太博大精深了~

但我们不能着急得慢慢打好基础。做学问最忌好高骛远不是吗?

浅墨希望看到大家的留言希望与大家共同交流,希望得到睿智的评论(即使昰批评)

精通游戏开发的路还很长很长,非常希望能和大家一起交流共同学习,共同进步

大家看过后觉得值得一看的话,可以顶一丅这篇文章你们的支持是我继续写下去的动力~

如果文章中有什么疏漏的地方,也请大家指正也希望可以多留言来和我探讨相关的问题。

我要回帖

更多关于 最近热得火的游戏 的文章

 

随机推荐