• Let's Rock'n Roll   

            马步扎稳之后,就可以开始来玩玩真正有趣的柀ξ鲊樱?

            『Graphics,是一个游戏的程序设计中,相当重要的一个部分,也常常是一个游戏的程序设计师的最主要工作。当然,也可以说是程序设计中,最有趣的一件事。』

            「那么要从哪里开始?」首先,我们必须了解,要去写一个3D的程序,并不是全部从无到有的从头做起、一个一个轮子的造出来;而是去使用一组别人已经 做好的基本功能,像堆积木一样的一步步堆砌出我们梦想中的城堡。我们无须去在意每一块积木的内部构造是什么、或从何而来,而是应该学习如何利用这些不同积 木的不同特性,建造出最合适的目标。转换成程序的观点来说,就是世界上的某几个大头,制订了一组标准的3D绘图函式以供其它人使用;而一般的程序设计师, 就只需要去了解该函式的接口及使用方法就可以了。如此的一组函式及接口,也就是常被人称做 API (Application Programming Interface) 的柀ξ鳌?

            或许你已经听过,目前主流的3D绘图 API 由两大流派分庭抗礼 — 分别是  DirectGraphics 以及 OpenGL。那应该学一个比较好呢?是的,相信这也是困扰着很多初学者的问题之一。「网络上好像关于 OpenGL 的资源比较多耶?」……「可是游戏业界好像都是用 DirectGraphics 居多耶?」…………。

            『我的建议是:两者都学。』

            唯有兼容并蓄、纳百家之长于一身,才能在遇到问题时,提出最合适的解决方法。OpenGL 与 DirectGraphics 可说是各有优缺点:OpenGL 的程序接口固定性很大,操作方式简单、易于学习;但它只提供一些基本功能的函式,并且它的版本更新太慢,若遇到新的技术出来,往往只能以 extension 的附加卷标功能来加强。而 DirectX 的使用方法则较为繁杂,但它也提供了更多进阶功能的函式可供使用;而它的版本几乎每年更新,是好事也是坏事,往往新版 DirectX 的程序接口都会和旧版有不小的相异之处,特别是从 DX7 到 DX8 的转变更是剧烈;这对所有的程序设计师来说,都是一场又一场「程序引擎重写」的恶梦。

            『然而,对一个对没有3D图学背景、初学3D程序设计的人来说,我建议从 OpenGL 开始。』

            理由如下:OpenGL 的使用方法较 DirectX 简易且直觉,可以让初学者专注于真正重要的3D图学基础的学习上。包括书籍、教学网站、原始码,OpenGL 拥有相当多的资源可供学习及参考。并且 OpenGL 的接口固定、很少变动,新版本的 OpenGL 通常都能够和旧版本完全兼容;不用担心学了之后,或甚至还没学完全,每过一年就要再重新学习一次新的函式界面。OpenGL 只提供基本绘图功能的 API 函式,想读取一张位图进来?想秀出一些简单的 model?抱歉,这些全都得自己来完成;因而可以藉此来磨练自己的一些基本程序能力与观念。

            我认为,只要确实的掌握住了3D图学的原理,所谓的 OpenGL 和 DirectGraphics 的差别,也不过是函式的呼叫接口不同罢了。学习 3D 程序设计,不是要去死背一大堆函式的用法及参数的使用;而是应该要真正踏实的了解 3D 的理论基础与架构。观念融会贯通之后,自然也就能萤︻恻酝�恕W会程序的使用方法,往往只是最容易的事;而真正困难,并且值得去深入思考学习的,应该是 其程序的设计思维模式与程序背后所建构的理论基础。

            我个人相信,OpenGL 与 DirectX 各有它们的一片天空与其支持拥护者;虽然说其实这两者有越来越相像的趋势。毕竟它们就像是一对异卵的孪生兄弟一样,虽然外貌有些许的不同,可是骨子里的血 液精髓,还是出自同一个父母的根源。或许未来五年十年内也会一样,两者继续保持分庭抗礼的姿态;有人发明了一个新的理论,想立即找一个简单又好用的绘图 API 来做验证,又不想局限在 MS 的操作系统平台上,OpenGL 仍然是不二人选;有人想开发一个功能强大、各方面都最佳化、将硬件的效能发挥到极限的超强 3D 引擎,DirectGraphics 可以表现的非常亮眼。所以,一个能依据不同的发展需求,而选择不同的工具来达成目的的人,才会是一个最称职的程序设计者。

      

    Explore Another World

            和3D程设有了第一次的亲密接萤χ幔葎eHIGH过了头;还有其它你没见识过的世界呢!

            当学习了一段日子的3D程设之后,脑子里所累积的基本知识应该会开始逐渐成形:「开始可以把心中所想的 idea 给具现化了对吧?」「开始觉得以前的想法,可能不再只是遥不可及的梦了吧?」如果你已经具备了这样的智识及能力,我要说声:「恭喜你!」你已经正确的踏出 了成功的第一个脚步了

            『想写一个3D,或甚至2D的小游戏,已经不是很难的问题了。』

            等等等,先别太急。一个游戏程序的组成元素有很多,除了实时运算的3D对象之外,要不要有美美的2D图片呢?玩家的操作接口是要用鼠标、键盘还是游 戏杆呢?别忘了还有游戏中的各种音效;当然,如果有背景音乐的话就更完美了!那来个多人联机如何?....... 有太多太多的想法可以实现。

            所以呢,现在可以看自己的需要,或是自己针对哪一方面的知识比较感兴趣,可以补充一些 Graphics programming 之外的其它知识。知识的累积,不仅应具有深度,更应能兼具广度。想使用 joystick 来做游戏的控制器,或想对键盘鼠标做更进一步的掌控与回应吗?试试 DirectInput 的强大威力吧;想在自己的游戏中播放音乐或音效吗?可以试试学习 DirectAudio 的使用;想写个简单的区域联机小游戏吗?可以试试 DirectPlay 的简单网络功能;此外,如果有机会的话,能玩玩 Photo Shop、3ds Max、Maya 之类的2D或3D美术应用软件也都是很不错的经验。

            这个部分所提到的知识都是选择性的,站在一个学习者的观点来看,最好是自己对某方面真的有兴趣,才更进一步的深入去学习;如果不是出自于自愿性、自 发性的学习,往往都会变成只是三两天的热度、难以持久。总而言之,朝着自己有兴趣的方向发展下去,才会有源源不绝的动力可以继续往前迈进啰!


    回复:       
    浅谈游戏程序设计入门 - [进阶篇]
      
      

    Show Me Demo

            让我们把焦点转回游戏程设的核心工作上:也就是 Graphics API — DirectGraphics 与 OpenGL 的学习上。无论是学习何种 API,一开始免不了都是需要熟记很多很多的函式名称、呼叫方式、传入参数等等繁复的柀ξ鳌H会徇€需要把整个绘图 API 的程序设计流程架构,从头到尾的彻底了解;在学习 API 时很重要的一件事,就是要用心去思考绘图 API 设计者的想法,尽可能的掌握住这个绘图 API 的「设计思维」,以其思维模式来学习。如果能够掌握住了这个重点,则我相信不管是在学习绘图 API 的理论,或甚至是记忆函式的名称等等,都会变成是很自然而然的容易理解。记得试着多问自己「why」与「why not」。

    『学习,应该是一种主动性的思考,而非仅止于被动性的知识填充而已。』

    当你确定自己已经建立起正确的观念与思维模式时,就该开始来写写小程序啰。对于初学者来说,从无到有,往往是最难跨出的一步;如果想自己从零开始,一行行 的撰写程序代码,可能到最后才发现辛苦的结果,全部变成不解的程序 bug。如果觉得自己可能还没办法,独立完整的完成一个程序,那么比较好的方法就是:先参考别人的程序代码。无论是 DXG 或 OGL,在各种书籍与网站中,都有为数不少的范例程序存在。藉由 trace 一个范例的完整程序代码,可以因此而学到很好的程序写作方式。如果已经把整个范例的程序代码都了解的差不多了,或者还有疑惑不明白之处,可以试着改变程序 中的一些变量或函式呼叫,看看程序的结果会有什么变化,这也是一种很不错的学习方式。   

    『学习 Graphics API 最重要的是什么?熟记函式和参数?搞懂整个理论架构?』

    都不是。最重要的是:动手做。如果所谓的学习,只是脑袋里记了一大堆不知所以然的柀ξ鳎苌僬嬲齽幽X去想、动手去做,那么所有的一切,可以说都是白费 功夫。没有实际踏实的程序写作经验,几个月后,记忆里只会剩下一堆不连续的残片碎影罢了。很多写程序时要注意的小地方或小技巧,我们称之为 tip 或 trick;一般的书籍或网站多只提供概略性的教学,对于实做上细节的一些小技巧,就需要自己亲身经历过,才能真正体会到的。简而言之,就像是一种经验值 的累积啰;现在很辛苦的练等级,到了真正要面临大阵仗、大魔王的时候,才不会临场怯阵、纰漏百出。

            如果对整个 API 已经有了相当程度的了解,加上时间经验的累积之后,就可以开始动脑想一些有趣的点子来做啰。有三角形、有灯光、有材侃Γ梢宰鲂┦颤N?让灯光的颜色随着 时间变化如何?还是改变材侃Φ淖鹗俗屛矬w外表有变化?还有透明度也可以做很多变化!工具在你手上,创意在你脑中;魔法人人会变,巧妙却各有不同。之前经 历过这么长的学习曲线,一路筚路蓝咯Α⑴G斩棘的到了这里,终于是可以自由挥洒的时候了,快把自己脑中存积已久的所有点子都压榨出来吧! : )

            『嗯?有什么地方不对劲吗?』

    随着自己写的小程序数目一直累积下来,或许你已经发觉到一件事实:「其实根本不用每次都从零到有的一行行程序代码撰写,对吧?」没错,一般来说都会存在有 一部份的程序代码是重复的、不变的;例如:窗口程序的初始化、绘图 API 一定会做的初始化之类的动作。那应该怎么做比较好?需要的时候再从之前的程序 “copy-paste”?不,这绝对是既没有效率又存有风险的方法。什么是最好的做法?最好的做法,就是把每次都会重复使用的程序代码,写成一个骨干架 构 (framework)。所谓骨干架构部分,通常是一个程序中变异性很小的程序代码;例如窗口程序的繁复初始化动作,动辄数百行程序代码以上,但却有很大 的固定性,所以就非常适合写成骨干架构。如果我们把骨干部分的程序代码,独立在一个 source file 中,而把真正相关绘图部分的程序代码抽离出来到另一个 source file 中;把所有不相关的闲杂人等,写成一个 source file 一次解决,从此不需要再烦恼那些不相关的柀ξ鳎灰覀俨阎饕L图部分的程序代码撰写完成后,再和以前就写好的骨干程序做编译连结,就可以让项目 (project) 的整体架构看起来更清楚易懂,也大幅增加了项目的结构性。

            『除了最基本的 framework 之外,还觉得需要什么吗?』

            没错,你需要自己的图书馆 (library)。什么是 library?让我举个例子来说明:如果你所学习的 API 是 OpenGL,你可能会发现,不管是 BMP、TGA 或 JPG 等等所有的图档格式,都需要自己撰写程序代码来读取。OK,那就写吧。The same as old,你会发现到,无论所需读取的是哪一种格式的图档,我们的目的都是很相近类似的:就是做为多边型的材侃?(texture)。那我们何不以 C++ 的对象导向模式,写出一个专门处理相关 texture 大大小小事务的类别呢?把读取每一种图档的 function 写在 texture class 的成员函式中,并且一样的把它独立成一个 source file;如此一来,只要每当需要处理 texture 相关程序时,就把已经写好的 texture source file 和我们的项目做编译连结,够简单又结构化,看起来很棒吧?

            同理可证,除了处理 texture 的类别外,还有文字的输出呢?定时器的控制呢?键盘鼠标的操纵?………别忘了还有最基本的矩阵和向量!把所有你能想到的基本功能,都写成一个个的独立 source file,只在需要的时候才和它编译连结;如此不但程序代码易于维护除错,未来的扩展性也相对的宽广许多!而这一个个的 source file 集合起来,就是所谓的 library 啰。就像是自己家里有座图书馆一样,架上摆着分类齐全、功能众多的各种书本,可以依照自己的需求而选取不同的书本来运用;而不是把几万行的程序全都浓缩在 一本书 (source file) 中,时日一久,如果生了臭虫,恐怕连原作者都不认识书的内容了!

            『所以,在写小程序赚取经验值的同时,最重要的工作就是要开始建立起自己的 library。』

            其实不管是在网络或书籍范例中,都可以看到很多别人写的 library;有一些 library 甚至还具备了很强大的功能。但是我并不建议在自己的程序中使用别人的 library。有什么坏处?以学习者的立场来看,使用别人的 library 所能学到的知识远逊于自己辛苦写出来的。参考别人的 library 写法,或许是个不错的主意,但是要记得:自己的 library,自己应该要看得懂才行。否则别说是扩充功能了,就连善加利用可能也没办法做到。在写 library 的过程中,就可以看出之前学习的成果如何了;如果程序语言、数据结构的基础没有学好,现在肯定会是最痛苦的一刻。在撰写自己的 library 之时,也未必要一次就写出功能非常齐全的对象类别;如果使用对象导向设计模式来撰写 library,就可以利用其可扩充的弹性,在有需要的时候才写新出的功能,并加入相对应的成员函式;如此又可减轻了初始设计的负担。

      

    Hardcore Stuff

            经过漫长的旅程,写过几个小 demo,拥有一些自己的 library 之后,应该可以感受到一点游戏程设的乐趣与魅力了吧?但是这样的知识,可能还是不足以达到设计你心目中理想游戏的能力,对吧?基本知识有了,绘图 API 熟了,接下来呢?让我们更进一步来看看比较深入的游戏程设世界。

            『Ok, let’s talk something seriously.』

            我想,只要是对于游戏设计稍有兴趣的人,在玩一款游戏的时候,多少都会问自己:「这个游戏是怎么做的?」是的,如果你是一路踏实努力走来的学习者, 你现在更应该认真思考这些问题。除了以玩家的身份体验一款游戏的乐趣之外,更要以设计者的角度来看这款游戏。在此,网络上的许多网站,就扮演了很重要的学 习媒介角色。相信你在学习过程中偶尔都会听过一些奇怪的名词术语,像是:BSP、Portal、Octree、LOD、Lightmap、Ray tracing ………等等。这些就是游戏设计的相关技术名词。你知道这些技术和游戏程序有什么关连性吗?你好奇这些技术如何应用在游戏程设中吗?在此,你的英文能力 (或翻译软件 ) 就十分的重要了。

            『你想知道的一切,网络上都找的到答案。』

    网络资源的利用可以说是学习过程中非常重要,并且不可或缺的一环。以国外的三大游戏设计网站 Gamasutra、Flipcode 和 Gamedev 来比较:Gamasutra 通常会提供相当深入、内容充实的研究主题,包含了游戏程设、美术,甚至音乐与企画管理,非常适合想对某一特定主题深入探讨的人;此外,Gamasutra 也是 Game Developer 这本着名游戏设计杂志的相关网站。Flipcode,也会不定期有教学文章的更新,主题多数都蛮具实用性的;并且 Flipcode 的 Image Of The Day 区域提供大家一个展示程序的地方,在此往往可以看到不少有意思的作品,绝对是这个网站不可不看的部分。Gamedev 相较于另外两者,在业界新闻及教学文章的更新速度都比较快,并且文章的数量很多、分类详细,不过其所提供的教学文章多以概论为主,少有比较深入的探讨。

            『到此为止,才算是真正开始逐步踏入游戏程设殿堂的时候。』

            只要稍微浏览过国外游戏设计网站的话,应该不难发现,其中的文章数目及种类实在太多太多了。其实对一个初学者而言,这个样子反而不见得是一件好事。 可能会不知从何开始学习,文章里充斥着一大堆看不懂的专业术语,甚至可能搞不清楚自己想要学习什么。万事起头难,刚开始或许一整篇文章,从头到尾仔细的阅 读了两次,还是只懂得其中的两三成内容;这个时候就需要踏实的投注时间与精力,点点滴滴的累积知识的广度。文章看得多了,程序写得勤了,渐渐的就可以了解 七、八成以上的内容啰。每篇文章所讲的主题,就像是一个个的「点」,如何找出点与点之间的「关系」,将这一个个的「点」连成「线」,进而化成一个知识的 「面」,也是学习中值得思考的一件事。

            除了每个网站的教学文章之外,附属于网站之下的讨论区也是一个非常重要的资源。试着用英文表达你的诚恳、发出你的问题,即使文法不是百分百正确、即 使找不到合适的词汇表达你的意思,你会发现总是有许多热心的人很乐意帮助你的。在国外讨论区回答问题的人,往往都很愿意帮助别人解答疑惑,就算是自己不熟 悉的问题,也会提出自己的经验和想法,甚至连程序代码的展示也毫不吝啬;所以只要你问的问题够好 (我相信唯有好的问题才能导引出好的答案),往往可以得到远超过你所想象的丰富收获、学到很多有用的知识。在发问前,也可以先搜寻看看该讨论区有没有类似 的讨论,或许你的问题早已有人问过了。记得不要再问「DirectX and OpenGL, which one is better?」这种问题啰! : )

            『网络的信息是学习新知技术最好的一条途径,那如果想对基础的原理有更深的认识呢?』

            别无二法,就是书本。书本可以说是学习知识最扎实的 (也或许是最痛苦的 ) 途径。其实真正学习的最好最好方法,就是找到一个好老师加上一本好书。不管任何知识,如果有了好老师的授业解惑,绝对有事半功倍之效;很可惜的是,一位称 职的好老师真的很难找,特别是在游戏程设这个怪领域中。所以靠人靠天,最后还是靠自己最实在;书本,就是闭关练功的武林密笈、不二法门。或许你会怀疑,已 经学会了程序语言、窗口程序、绘图 API,为什么还要看书?书里写的不都是一堆无聊的理论加上复杂的数学式吗?正如在之前的文章所提到的,了解理论并不见得会带来什么立即的效益,也不一定 能增强写程序的功力;但是书本的知识,能够帮助你更确实的掌握住事物的本侃�A与思维模式。特别是在日趋复杂的游戏程序设计中,如果没有深厚稳固的理论 基础所建构起的法则做为地基,恐怕难以负担起越来越庞大复杂的游戏程序架构。

            还是那句老话:「想创造规则的人,必先了解规则。」每一本好书,都是前人以无可计数的时间经验所得来的心血结晶,集英荟萃之后以文字的形式传诸于 世,让所有有心学习知识的人都能因此受惠。从书本中,我们可以轻易的学到前人的知识经验与心血结晶;原来可能自己要花费数年时间才能领悟的道理,现在只需 要从阅读书本中的知识就能轻易习得。以 3D 计算机图学来说,了解其背后的许多理论基础,更能帮助你更快的学习并吸收新的知识。例如在了解了 Phong reflection model 的定义之后,就可以很容易的理解为什么光源的组成要分成 ambient、diffuse 及 specular 三个成分了;如果了解 3D 计算机图学的发展历史,就不难理解为什么目前的 3D 绘图主流方式还是以 polygonal mesh 为主了;诸如此类,太多太多的例子可以举。理论知识这柀ξ鳎粫悄阋粫r的饭碗;却会是你一辈子的财富。

      

    Build Up Toolbox   

            熟悉了一些游戏的核心技术之后,就可以开始建立自己的工具箱了。何谓工具箱?一般常见的讲法就是「编辑器」(editor)。编辑器大致上有两种用 途:一是做为程序的测试工具,二是做为游戏开发的编辑工具。以第一种用途来说,例如你想用之前文章提过的侃�c系统 (Particle System) 来做一个施放魔法时的特效场面。要怎么要才能知道所写出来的程序代码有没有符合需求呢?这个时候就可以写一个侃�c系统的编辑器工具,把所有可以调整的变 量全部列在编辑器的面版中,可能会包括侃�c大小、位置、颜色、速度及运动法则等等要素。然后就可以在编辑器的面版上,直接调整变数的值,实时的观察侃 �c系统的变化情形如何。使用这种方法,就能够很便利的以各种不同数据测试程序的结果,而不是每次都要在程序代码中更改数据后,再重新编译连结整个程序。 更大的好处,就是可以让不懂程序代码的人,也能直觉性的调整并控制程序的呈现结果。所以建立编辑器之后,就算是复杂的交叉数据测试,也会变得容易、而且直 觉许多。

            编辑器的第二种用途呢?举个例子来说,Quake 3 Arena 中宛如艺术品般惊为天人的美丽场景是如何制作的?如果你对游戏设计的核心技术已经具备有基本概念,就应该能够了解,它的场景不可能是由几位程序设计者,一 个一个对象的撰写程序代码而完成整个复杂场景的。那应该是用什么样的方式来建立复杂的游戏场景呢?就是依靠所谓的编辑器。一般来讲,一个完整的 3D 场景就称做一个 level,而编辑场景用的就叫做关卡或场景编辑器 (level/map editor)。通常编辑器是由程序设计者,将所有可能会使用到的功能先设计完全,并做出一个易于操作的使用者接口;如此一来就可以让专门负责场景的设计 者 (level designer) 来完成所有的关卡与场景。只要编辑器的功能够强大齐全,甚至不用懂得任何程序代码,也可以设计出非常棒的场景;而这正是编辑器的真正威力。

            编辑器的真正目的应该是化繁为简的能力。最理想的状态应该要做到,不需要任何说明文件与教学,任何稍具游戏设计概念的人都可以轻易上手才是。编辑器 的产生也使得游戏开发的分工变得更合理可行;只要程序将人物的对话编辑器写好之后,就可以交给企画负责编撰人物的文案;如果程序开发出够强的场景编辑器, 就可以让美术来负责整个场景的建模与成形了。所以编辑器往往是游戏的制作过程中,相当重要的一个部分。如果说一个游戏的开发时间,有百分之五十投注在设计 开发编辑器的过程上也不为过!

            『我知道你在想什么。』

            到了这里,又要再次面临类似的问题:Borland C++ Builder 与 MS Visual C++,到底要选择何者做为开发工具用的编译器?我的答案还是一样的平凡:两者都学了再说。在之前的文章提过,要写出比较进阶的窗口程序,可以用 Win32 SDK、Borland 的 VCL 或是 Microsoft 的 MFC。其实编辑器就是属于一种进阶的窗口程序设计,因为它会包含很多复合性的元素,如绘图 API 的呈现、对话盒、控制面版与档案的储存加载等等。在各大程序设计讨论区,BCB 与 MSVC 的批评比较,绝对不亚于 OpenGL 与 DirectX 的情形。如果用另一种方式来比喻的话,BCB 就像是家里的万能老妈一样,会帮你把所有想做的事情都打理的很好;只要用「拖拉点放」的方式,就可以完成大部分的窗口组件设计。而 MSVC 就像是精打细算的老婆一样,所有要完成的事情都要跟她报备,照着规矩一项一项的来做;虽然有一些便利的设计精灵可以应用,可是大部分还是要用「手工打造」 的方式,循序渐进的来完成。

            而两者的缺点呢?BCB 常被人所诟病的,就是其不佳的程序编译效率及执行效能;而 MSVC 则是 MFC 的学习曲线太长,庞大复杂的 MFC 结构,往往使初学者望之却步。我的建议还是相同,不管别人的说法如何,还是只有自己亲身用过之后才能体会其优劣胜败之处。两者都学习之后,或许才会发现在 别人眼里是优点的地方,自己不以为然;而在别人眼里是缺点的地方,自己却不以为意。不论是 BCB 或 MSVC,都只是一种工具,为了达成某些目的而被造出来的工具;所以,能因地制宜,选择合适的工具,看何者用的比较顺手就使用何者,或许才是比较好的方 式。

      

    On The Way

            『什么?你是认真的吗?这么无聊的三篇文章你都能看到这里了喔,真服了你耶。』

            『嗯?你说你前面的所有学习步骤都完成了,接下来呢?』

            『不,如果你会有这个疑问,表示你还没到达这里。』

            『………………………』

            『好吧,好吧,如果你真的好奇的话,让我们再来稍微谈谈之后的路。』

            其实很容易,至此有几个简单的选择;一是对自己有兴趣的主题继续深入研究,往深度发展;二是再寻找其它没学习过的主题,往广度发展;第三,还有别的 吗?就是写 GAME!跟我念一次,G‧A‧M‧E,GAME!别忘了我们一路从这漫长艰辛的路程走来,为的是什么目的。现在你终于可以大声的说:我有能力写出一个游 戏了!开始激发你的创意,爆发你的潜能,构思设计一个 GAME 吧! : )

            最后再提一件事情。或许你也会常常听到某某游戏用了什么「3D 引擎」之类的。嗯?你说这一系列的文章,怎么从来没有谈过有关 3D 引擎的主题?咳咳,请记得这篇文章的主题是「浅谈游戏程序设计入门」,不是什么「如何在 30 天内做好一个 3D 引擎」、「快快乐乐学做 3D 引擎」,或「如何在 30 岁前拥有人生第一个 3D 引擎」之类的OK?……………好啦,讲认真的,3D 引擎真的是非常复杂的柀ξ鳎^非像这样的三两篇文章可以解决的。也不是我目前的能力可以分享的。其实像之前所提到的编辑器工具,可以说就是 3D 引擎的一个重要核心;不过 3D 引擎同时还必须整合美术及音乐的部分,将一切制作游戏所需的元素都考虑进去,才能算得上是一个完整的、真正的「3D 游戏引擎」。不过我的建议是,就算你已经学习至此,还是先不要想太多 3D 引擎的柀ξ鳎焕^续充实自己,累积写程序的经验,利用自己现有的知识与技术,做出一个有趣的小游戏吧!

            一向惯于以文字表达的我,到了这里还是不禁要怀疑:这些辛苦敲打出来的文字,究竟能不能适当地表达我心里真正想说的话呢?真正能了解我想表达的意思 的人有多少呢?而真正能努力做到并且达成目标的人又有多少呢?…………………好吧,我承认我想太多了 (其实是已经不知道要说什么了 ~_~)。总而言之,基本上这一系列文章的重点差不多已经告一个段落,在接下来的最后一篇文章中,我会以自己亲身的学习经验为例,和大家做个分享。还请大 家多多指教。
     
  •  http://www.pixelgame.net/bbs/viewthread.php?tid=18752 

    【老坛子转移贴】淺談遊戲程式設計入門,作者:V子

    以下内容来自GAME RESOURCE

    标题作者:HalfLucifer 

    后面的内容全部上述。所有版权归原作者和引处所有。

    --------------------------
    浅谈游戏程序设计入门 - [概论篇]   
      
      

    Introduction And Assertion

            『我想做游戏!』

            『我的梦想就是做出一个怎样怎样的游戏..』

            我们之中的许多人从小就是玩游戏长大的,游戏是人类的天性与本能;人类的「游戏心」自古至今没有改变过,只是不停地在演进。从最原始单纯的运动竞 赛,到今日各种各样的电子娱乐,莫一不是为了满足人类的「游戏心」。游戏的理由,或许你我心中都有一个不尽相同的答案,但是它的本侃κ冀K是相同的 — for fun。然而在玩着游戏的我们之中,开始有了一群人,不满于现存的游戏世界与游戏规则。「那么我们就自己创造一个新的世界吧。」他们想。于是世界的命运巨 轮缓缓的转动,在人类的游戏史上,又写下了崭新的一页。

            『嗯?你也想加入他们?..... 那你会什么?』

            『无比的热诚,学习力强,有潜力,喔,还有一大卡车的好点子.......?』

            工作、兴趣、赚钱、养家活口、理想、梦想、伟大的抱负、台湾的史克威尔,无论你的理由是什么,无可否认地,做游戏这一行的确是有种无可置信的超凡魅 力,使多少人前仆后继的梦想着投入这一行里。若以现今台湾的游戏公司来讲,一般最常见的核心职称有:企画、美术及程序三种类。如果你的梦想或心愿或目标刚 好是程序,游戏程序设计的话,那么我必须要说:「你或许选择了一条最难走的路了。」

            在许多电子讨论版上,不时总会看到有发文者问:「请问游戏设计如何入门?」「请问游戏设计的入门书籍...」诸如此类的问题。可惜我到目前为止,还 没见过任何一篇较有系统性的专文,能就各种不同的角度,给予提问者一个适当的答案。我想这也是因为问题的方向太大、涵盖范围太广,要做出完整的答复,也不 是简单的三、四十行字句可以完全表达的。想当初,自己也是一路跌跌撞撞的到处提问题、埋头苦读了好一阵子,再把努力后的成果拚拚凑凑起来,勉强才为略窥得 游戏程设的一点朦胧身影。所以,我想我能体会到,要入这一行门有多难多辛苦。

            『路很长。不前进,不如趁早回头。』

            在这一系列的四篇文章中,我将由浅入深逐一论述,做一个游戏程序设计者,所应培养具备的基础能力。声明在先,我,作者本人,目前并非任职于游戏业界 中,也从未参与过任何游戏的开发过程。在文章中所提到的一切论述与观点,皆是自己由自学过程中整理归纳出来的方法途径,或许并没有完全的信服力。在业界前 辈们的眼光看来可能是野人献曝、不值一哂;不过我也希望我致力写出来的这些文章,还是能对一些刚入门、或不知从何入门的新手,有些微的帮助与贡献。也可以 算是抛砖引玉,希望先进前辈们不吝批评指教,写出更好的文章,造福有心人。

      

    Make Sure What You Want

            其实,游戏的程序设计,并不是那么难的事。可以在闲暇之余,找本 Visual Basic 的好书来读读,再稍具一点游戏程设的概念,要一个人做出一些很不错的小游戏也不是什么难事。「嗯?那为什么我还在这边正经八百的说着废话?」至此有两种可 能性存在:一,我是个多话又闲闲没事做的显然十足大笨蛋。二,我是个有着不同目的的潜伏型大笨蛋。

            我觉得,无论要做什么,先弄清楚「自己真正想要的」是什么,是一件非常重要的事情。写游戏,可以是三五好友在课余工作后,大家共同投入的一种兴趣; 可以是程序高手无聊时自娱娱人的创作共享软件;当然,也可以是你未来的职业、理想的开端,或赚大钱的利器。好之者不如乐之者,工作即乐趣,乐趣即工作,可 能不再是一种无知的幻想。只要做好准备,历史的新页随时等着你去写下。

            政府不支持、父母不愿意、学校不重视、资源不充足,从小在这里长大的我们,接受这个社会的教育,接受传统价值观的灌输,都可以深深的体会到,走这一 行的人将会遭遇到多大的阻力。「但是,那又怎样?」与其怨天怨地怪自己生错地方,何不从「自己」开始努力?只会空谈、只会埋怨、只会梦想,是到不了任何地 方的。如果每个有心的人,都能从自己开始,点点滴滴的累积实力,我相信这个「大环境」的风向,也会有改变的一天。

            『是的,这一系列文章的主要目的是在于,培养足以踏入游戏程设业界的一些基本能力。』

            因此,我期望能提供给已经确立志向、却不知如何入门的新手,一条最佳化的路径。省去一些新手可能会有的独自摸索与尝试错误的时间,早日踏入这片苦海,喔不,是美丽的乐园,携手共创另一个岛国奇迹 : p

            附注两项很重要的说明:在之后的文章里,可能会到处充满我个人的偏见,例如请爱用 C++,如此之类的专断用语。如果因为我的文章引起任何的偏头痛或上吐下泻等不适症状,欢迎写信来骂我。我一定会虚心受教。另一项是,在这一系列的文章 中,主要我是以培养「实时3D游戏程序设计」入门基础的能力来撰文的。所以,如果你是希望知道多人在线游戏的设计,或有着美美图片的2D游戏设计,那你可 能会稍微失望了。但是大部分学习的道理都还是相通的,所以应该还是可以参考看看。关于为什么选择「3D」作为学习目标的原因,我就不在此赘述了,或许在之 后的其它文章再谈吧。

            『路在眼前拓展开来,无止境的向地平线的那端延伸而去,始终无法看清这条路的终点有些什么。经过这条路的旅人们犹豫着。』

            你只能做出选择。要走,或不走,端看自己个人的决定。我希望我的文章扮演着引路人的角色,为迷途的旅人们一解前路的疑惑。在这一系列文章中,我不会 教你「如何写出一个叫好又叫座的游戏」,不会「教授什么高深的游戏程序写作技巧」。也请不要花费力气和我争论「做出好游戏不一定需要什么高深的技术」或其 它之类的控诉。

             『It's none of my business at all; I just show you the way.』

      

    Basic Ability Requirement

            在学习游戏程设的路上,一开始所应具备的最基本能力是什么?没错,就是一般最令学生头痛的「英文」和「数学」。「那到底是为什么?」或许你已经猜想 到一些显而易见的原因,现在再让我老生常谈的来补充一下,你应该趁你还有机会的时候,好好地和他们做个好朋友的理由。    对一个程序设计师来说,最重要的基本素养之一,就是就是吸收消化知识的速度与能力。在游戏程设的领域中,各种技术,尤其是3D图学,的进步往往是日新月 异,能够快速地将新来的知识转化为自己的智识,得以应用于做游戏的过程中,我想是一件非常重要的事。偏偏不巧,最新的知识原理或书籍文件,往往都是以英文 作为发表的语言;更不巧的是,我们生长的岛国不是以英文作为母语。因此,对于英文阅读能力的培养,绝对是相当重要且首要的事情之一。从今天起,不要总是一 直询问「有没有中文的某某书籍或网站」,是时候开始训练自己,对英文这语言的敏锐度与习惯性了。

            嗯,那数学呢?它对游戏程序到底有什么重要性?过去很长一段日子以来,我也一直在问自己这个问题。直到我真的遇上它为止。或许很多人都听过,空间向 量、矩阵、线性代数,这些知识可以说是3D图学的基本架构。没错,可是需要了解多少呢?不是只要会用、记得它的规则就行了吗?一般来说,的确这样就够了。 然而,在你写作程序的经历日渐增长后,也许会在某个夜阑人静的深夜里,突然问起自己:「为什么这个方法是这样作用的?」

            『想创造规则的人,必先了解规则。』

            了解所谓「实做」背后的理论基础,一定会得到什么很大的好处吗?那也未必。但是了解它可以带来另一种不同于写程序的满足感。或许你会感到手中握住的 知识,因此变得踏实许多。同样的理论,可能可以用数种到数十种不同的方法来实做;但无论方法或接口怎么改变,只要掌握住它的「本侃Α梗匀豢梢哉业绤捣N 方法中的最佳化答案。我们可以把数学看作一种严谨的思考逻辑训练,磨练一个人的抽象化组织能力;任何最具体化的理论方法,都可以解构成数学中最基本的 model 来解释与描述其行为本侃Α?

            总而言之,在你仍拥有机会的时候,不要放弃学习它的动力,无论是微积分、离散数学、工程数学、机率统计也好,虽然学习数学的过程可能是最充满痛苦,而成果可能是最隐晦难见的,但也许在某天的某个场合,它会以某种意想不到的形象,蹦出来帮了个大忙呢。

            『OK,确定你站稳脚步了吗?我们要开始啰!』

    浅谈游戏程序设计入门 - [基础篇]
      
      

    Power Of Language

            当然,这里所指的语言是专指「程序语言」而言。让我们一步步来进行。

            『首先,请开始学习C++。』

            嗯?什么?你说你会VB、会C语言?还有JAVA?ASP、SQL?让我再说一次:「请开始学习C++。」无论你之前学习过什么样的程序语言,请记 得,现在我们谈论的是最适合用来开发游戏程序核心的程序语言。C++无庸置疑是目前功能最强大、效率最好、操作弹性最佳,也是最复杂难懂的语言。因此,C ++用来开发游戏程序核心,至少在PC平台上,是最最合适的不二人选。

            『OK,OK,我已经听到很多不以为然的声音了;请给我一点机会解释一下。』

            C++是一个具备良好对象导向设计模式的一种语言,能相当完整的以「对象」为设计的着眼点来完成整个程序的分析及架构。在这里举一个实际应用上的例 子:大家都知道,在3D的程序设计中,「向量」的使用是非常广泛且多面的,如果我们能以「对象导向」的观点设计出一个「向量对象类别」,那么在之后的使用 上将会带来许多的便利性。怎么说呢?如果我们使用传统 structure-based 的设计模式来建立一个向量的新类别,我们通常会这样宣告:

            typedef struct {

                    float x, y, z;

    } Vector;

    以此来表示一个自己定义的新类别 Vector,其内结构由 x、y、z 三个类别为浮点数的变量所组成。

    「看起来还不错?」但是今天如果有需要做两个 Vector 类别的加减乘除呢?对不起,你必须一步一步的自己来做:

            Vector vec1, vec2, vec3;

            vec3.x = vec1.x + vec2.x;

            vec3.y = vec1.y + vec2.y;

            vec3.z = vec1.z + vec2.z;

    「有没有更直觉的做法呢?」有的,在C++中,你可以自订类别的「运算子」来帮你更直觉化的完成这件事,例如:

            operator+(Vector vec1, Vector vec2) {

            vec3.x = vec1.x + vec2.x;

            vec3.y = vec1.y + vec2.y;

            vec3.z = vec1.z + vec2.z;

    }

    如此一来,以后在做 Vector 类别之间的加法时,只要简单的写:

            vec3 = vec1 + vec2;

    所有的工作,就由自订的加号运算子来帮助你完成,就像使用预设的加法运算子一样的直觉。在C++的语法中,你还可以为自订的「对象类别」,增加更多的「成 员函式」;我们可以把「成员函式」看做是去定义一个「对象」的某种「行为」或「方法」,藉此来达成对象与外界的沟通桥梁。例如一个 Vector 常有可能会需要使用内积、外积或向量长度的计算;而其它加减乘除的运算,也都是 Vector 这个对象的「行为」或「方法」。当我们把这些功能写成 Vector 的成员函式之后,我们就能更加直觉的了解并使用这些方法,同时也在无形中增加了程序代码的可重复利用性。

    对象导向及C++语言的威力还不仅止于此,在对象类别中所定义的各种函式都可以做到虚拟与多型的机制拓展,更进一步的提供了「继承」这项崭新的设计思维。 何谓继承?所谓的继承,即是指对象架构的继承体系。如「人类」是属于「灵长类」下的一支,而「灵长类」又是属于「哺乳类动物」下的一支;于是我们可以说, 所有灵长类的动物必定具备有哺乳类动物的特侃Γ械娜祟惐囟ň邆溆徐`长类动物的特侃Α_@就是一种「继承」的架构。当我们在写程序时,若能依照架构 由上而下的来定义对象类别,则必定能够节省很多的时间和力气,写出更好的程序。

    举一个例子来说明:如果今天我们要设计一个有关「侃�c」(particle) 的类别,要能够描述所有侃�c可能具备的特侃�翱赡馨l生的行为,用C++的观点该如何来做?假设我的世界中会有三种侃�c:雪、火、雨。于是我们开始设 计「雪」的对象类别…… 再来是「火」,…………… 最后还有「雨」。然后,我们可能会发现,其实这些侃�c会有许多共通的「本侃Α勾嬖冢徊还苁侨魏我环N侃�c,我们都需要它存有:侃�c位置、侃�c大 小、侃�c速度等等之类的数据。既然如此,我们何不把所有侃�c的共同特侃Τ殡x出来,成为一个抽象的 Particle 对象类别?如此一来,所有继承自它的对象类别 Snow、Fire、Rain 都可以拥有和 Particle 相同的「属性」及「特侃Α埂H会嵩僖啦煌│点的不同「行为」,个别去定义各自的成员函式。以后如果还需要定义其它种类的侃�c,只需要先从 Particle 继承而来,再来定义这个侃�c的不同之处就可以啦。 ([后注]:其实这里所举的「侃�c」这个例子,在实做上并不完全合适如此的继承架构。)

    虽然它不是万灵药,但以对象导向的思维模式来写作程序,在多数的情况下,都是相当有利于每一个程序设计者的。而C++,正是包含了对象导向设计模式,目前最合适应用于PC平台游戏设计的程序语言。

            『嗯?听起来好像真的很不错吧?』

            很可惜的是,天下没有这么容易吃的午餐。既然C++有这么多的优点和这么强大的功能,那也就表示:C++是一种很难学习的程序语言。著名的作者侯捷 在 Effective C++ 一书的译序中就曾提到:「C++是一种难学易用的语言!C++的难学,不仅在其广博的语法,以及语法背后的语意,以及语意背后的深层思维,以及深层思维背 后的对象模型;C++的难学,还在于它提供了四种不同(但相辅相成)的程序设计思维模式:procedural-based, object-based, object-oriented, generic paradigm。」

            因此在C++语言的学习曲线上,相较其它语言自然来的漫长许多。这通常是初学者真正第一个需要用力跨越的门坎。程序语言,并不是一种很直观的思维模 式。没有人与生俱来就熟悉这种语言,要亲近它、学会它、熟练它,一步一步都是需要灌注时间和心力下去累积的。阅读真正值得一看再看的好书、做各种程序的写 作练习、找个好老师学习,各种方法都是不能省略的。虽然在学习程序语言的过程中,会稍嫌单调无趣了些,但真正到了进阶的部分时,就会发现这个部分功力的重 要性。无论写的是哪一种的程序,程序语言就是最重要的「内功心法」;如果内功未臻成熟,就急着练些花俏的武功招式,最后的结果就是程序 bug 连连,使出来的招式总在意料之外发生破绽。不可不慎之。

            在学习程序语言的过程中,也应该熟悉一些基本的「数据结构」,如各种 linked list、queue、stack、tree 等等的用法;如果能够懂一些基本的「算法」概念,对以后程序的设计也会有不小的帮助。关于程序编译器 (compiler) 的选择,其实在目前这个阶段使用什么编译器都是没有差别的;而在之后学习「窗口程序设计」及各种 Graphics API 时,就需要从 MS Visual C++ 或 Borland C++ Builder 两者中择一了。我的建议是使用 MS Visual C++。毕竟是在 Windows 上开发程序、毕竟将来可能用到 MS 老大的 DirectX,在一开始的时候先用 MS 的编译器,可能比较不会碰到太多非预期内的麻烦问题。

      

    Handle Your Window

            有了程序语言的基础之后呢?在你急着想学些3D的程序设计之前,先等一下,我们还得先拜拜码头:「先学会和我们可爱的 Windows 沟通沟通啰!」和 Windows 老大打好人际关系后,以后我们做起事来才会顺利的多。谁也不希望程序执行到半途,老是跑出「此程序执行无效,即将关闭」的蔚蓝画面吧?

        『写程序归写程序,又关它 Windows 老大啥事了勒?』

            话,不是这么说滴。我们要知道,所有计算机中的应用程序,都是建构在「操作系统」上面动作的;我们在 PC 上所写的游戏当然也算是应用程序的一种。而 Windows 正是扮演着「操作系统」这个角头老大的角色。由它来分配每个应用程序所可以使用到的内存以及 CPU,还有一般的键盘鼠标讯息也都是经由它来传送信息给应用程序的。所以啰,想在 Windows 上写作程序,当然需要先过这关啰。   

            『所以,现在有充分的理由开始学习 Windows SDK 啰。』

            不,即使会使用 VB 来设计窗口应用程序,也并不代表真正了解窗口程序设计的意涵。我再说一次,直觉化如 VB 或 BCB 的拖拉点放「窗口组件」设计接口,也只是在你熟悉了窗口程序的核心概念之后,才能应用得宜、加速程序开发的。在那之前,好好的从基本的窗口程序写作开始学 习起,才是最正确并且合适的做法。

            对一个习惯了在 DOS 上开发写作应用程序的人来说,在学习窗口程序设计的过程中,一开始最无法适应的就是找不到 main() 这个程序的起始点;在 Windows programming 中,都是以 WinMain() 取代 main() 了。除此之外,还有很多一开始比较难以接受的新概念:什么是讯息循环?不可或缺的 WndProc() 又是做什么的?怎么输出文字?………… 相当多在 DOS 上的程序用法或函式,到了 Windows 上却不管用了。如今,要在 Windows 上写出一个最简单基本的 “Hello, World” 小程序,也约略要写 100 行左右的程序代码。不过也不用担心太多,只要找到一本好书做为学习的教材,就能够很快的进入状况、熟悉环境了。在此当然不得不推崇 Charles Petzold 原著的 Programming Windows 这本书,内容真可谓是巨细靡遗,书中还包括了每一个范例程序的完整程序代码,不论是书的厚度或内容,都是相当地具有「份量」;目前此书也已有中译本。

            『那么,SDK 的学习大概要到什么程度呢?』

            以 Programming Windows 这本书为例,我想真的很少有人能够有足够的耐性与时间,完整的啃完厚达 1500 页的内容吧?何况其中的内容虽然非常丰富可观,但如果仅是以「游戏设计」为目标的话,倒也不需要懂这么多柀ξ鳌D屈N至少,要学到什么程度?我想,至少的 至少,要学会如何键盘及鼠标事件的操控,才能算是及格了。如果对如何使用 SDK 写出一些进阶功能的窗口有兴趣的话,例如像子窗口、菜单、加速键、对话盒、文字字体、多任务多绪之类较进阶的课题,就可以再往这本书后面的章节继续学习。 如果在此时不学习这些进阶的程序功能也是可以的,未来我们可以选择学习 SDK 之外的其它方法,如 MS 的 MFC,及 Borland 的 VCL,来实做一个进阶的窗口程序。有了以上的基本概念之后,才能再往下一个领域探索学习;如果在学会程序语言之后,没有先具备窗口程序的设计概念,就急 着想学 DirectX,到后来只会形成不得要领、四处碰壁的学习窘状罢了。

      

  • 轉載自 http://blog.csdn.net/rance


    /* The Very Simple Win32 SDK Program */

    #include <windows.h>

    /*  Declare Windows procedure  */
    LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM);

    /*  Make the class name into a global variable  */
    char szClassName[ ] = "WindowsApp";

    int WINAPI WinMain (HINSTANCE hThisInstance,
                        HINSTANCE hPrevInstance,
                        LPSTR lpszArgument,
                        int nFunsterStil)

    {
        HWND hwnd;               /* This is the handle for our window */
        MSG messages;            /* Here messages to the application are saved */
        WNDCLASSEX wincl;        /* Data structure for the windowclass */

        /* The Window structure */
        wincl.hInstance = hThisInstance;
        wincl.lpszClassName = szClassName;
        wincl.lpfnWndProc = WindowProcedure;      /* This function is called by windows */
        wincl.style = CS_DBLCLKS;                 /* Catch double-clicks */
        wincl.cbSize = sizeof (WNDCLASSEX);

        /* Use default icon and mouse-pointer */
        wincl.hIcon = LoadIcon (NULL, IDI_APPLICATION);
        wincl.hIconSm = LoadIcon (NULL, IDI_APPLICATION);
        wincl.hCursor = LoadCursor (NULL, IDC_ARROW);
        wincl.lpszMenuName = NULL;                 /* No menu */
        wincl.cbClsExtra = 0;                      /* No extra bytes after the window class */
        wincl.cbWndExtra = 0;                      /* structure or the window instance */
        /* Use Windowss default color as the background of the window */
        wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND;

        /* Register the window class, and if it fails quit the program */
        if (!RegisterClassEx (&wincl))
            return 0;

        /* The class is registered, lets create the program*/
        hwnd = CreateWindowEx (
               0,                   /* Extended possibilites for variation */
               szClassName,         /* Classname */
               "PCGs Very Simple Windows Application",       /* Title Text */
               WS_OVERLAPPEDWINDOW, /* default window */
               CW_USEDEFAULT,       /* Windows decides the position */
               CW_USEDEFAULT,       /* where the window ends up on the screen */
               544,                 /* The programs width */
               375,                 /* and height in pixels */
               HWND_DESKTOP,        /* The window is a child-window to desktop */
               NULL,                /* No menu */
               hThisInstance,       /* Program Instance handler */
               NULL                 /* No Window Creation data */
               );

        /* Make the window visible on the screen */
        ShowWindow (hwnd, nFunsterStil);

        /* Run the message loop. It will run until GetMessage() returns 0 */
        while (GetMessage (&messages, NULL, 0, 0))
        {
            /* Translate virtual-key messages into character messages */
            TranslateMessage(&messages);
            /* Send message to WindowProcedure */
            DispatchMessage(&messages);
        }

        /* The program return-value is 0 - The value that PostQuitMessage() gave */
        return messages.wParam;
    }


    /*  This function is called by the Windows function DispatchMessage()  */

    LRESULT CALLBACK WindowProcedure (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        switch (message)                  /* handle the messages */
        {
            case WM_DESTROY:
                PostQuitMessage (0);       /* send a WM_QUIT to the message queue */
                break;
            default:                      /* for messages that we dont deal with */
                return DefWindowProc (hwnd, message, wParam, lParam);
        }

        return 0;
    }


    程序的结构如下:

    BEGIN

    序言注释

    编译预处理指令

    窗口过程函数声明

    窗口类名字字符串定义(作为全局变量)

    主函数WinMain

    {

            窗口句柄定义;

            消息结构定义;

            窗口类定义;

            窗口类初始化赋植;

            尝试注册窗口类;

            创建窗口;

            显示窗口;

            消息循环;

            返回值(tagMSG::wParam);

    }

    窗口过程函数定义(处理各种消息)      

    END