原文:http://www.flipcode.com/archives/Elements_Of_A_Game_Engine.shtml
Introduction (簡(jiǎn)介)
現(xiàn)在我們來(lái)說(shuō)說(shuō)你將如何寫(xiě)出一個(gè)支持華麗特性的3D引擎。你的引擎需要提供的包括:曲面(curved surfaces)、動(dòng)態(tài)光(dynamic lighting)、體積霧(volumetric fog)、鏡面(mirrors)、入口(portals)、天空盒(skyboxes)、頂點(diǎn)Shader(vertex shaders)、粒子系統(tǒng)(particle systems)、靜態(tài)網(wǎng)格模型(static mesh models)、動(dòng)畫(huà)網(wǎng)格模型(animated mesh models)。如果你對(duì)上面這些都很熟悉了,你也許急著把這些東西整合到引擎當(dāng)中。9 h: z( V0 G* m) m6 Z0 i p% a
但是請(qǐng)稍等!在你開(kāi)始寫(xiě)代碼前,你必須先思考一下你將用你的引擎來(lái)做什么。通常情況下,你應(yīng)該想拿來(lái)做游戲,但如果你馬上就開(kāi)始寫(xiě)你的引擎,你會(huì)死得很慘,到后期你可能會(huì)因?yàn)橐黾有碌奶匦Ш涂刂浦貜?fù)編寫(xiě)大量的部分代碼,最后很有可能以失敗而告終。所以事先思考一下你的引擎設(shè)計(jì),會(huì)為你節(jié)省大量時(shí)間和麻煩。你也不要一開(kāi)始就指望建立一個(gè)大的工程,這樣你可能也會(huì)力不從心,最后不了了之。其實(shí)這是一個(gè)學(xué)習(xí)所有東西的辦法,從小從起,因?yàn)槿藷o(wú)完人,所以,你最好是能完成你的項(xiàng)目,那樣你會(huì)感到很自豪。
工具/數(shù)據(jù)
在開(kāi)發(fā)的時(shí)候,你可能會(huì)需要一些數(shù)據(jù),但不幸的是,如果用txt文件來(lái)定義一個(gè)立方體,是一件非常不容易的事情。所以,至少你得要一個(gè)3D建模軟件(3d model editors),關(guān)卡編輯器( level editors)和圖形程序(graphics programs)。這些東西都可以買(mǎi)到,但你也可以在網(wǎng)上找一些免費(fèi)的。但更不幸的是,你有可能會(huì)需要更多網(wǎng)上沒(méi)有的工具,所以,就需要你自已寫(xiě)了。如果你在網(wǎng)上找不到你想要的關(guān)卡編輯器時(shí),你就需要自已寫(xiě)一個(gè)了。你還需要寫(xiě)一些代碼來(lái)打包你的文件。因?yàn)橐鎸?duì)成百上千的文件是一件痛苦的事情。你還需要寫(xiě)轉(zhuǎn)換器或是插件來(lái)將你3D建模軟件導(dǎo)出的文件格式轉(zhuǎn)換成你自已的。你還需要一些其它工具來(lái)處理你的游戲數(shù)據(jù),比如能見(jiàn)度分析,光照貼圖等。: j; O1 }1 }3 |) _2 K. L
有一個(gè)基本規(guī)律,那就是有可能你寫(xiě)工具的時(shí)間,可能比和寫(xiě)游戲花同樣多的時(shí)間,或者說(shuō)更多。前期你可以找你想要的工具和文件格式來(lái)用,但是總有一天你會(huì)意識(shí)到,對(duì)于你的引擎來(lái)說(shuō)那些東西太普通了,于是你會(huì)意無(wú)反顧地寫(xiě)你自已的專(zhuān)用版本。
雖然使用現(xiàn)成的東西已經(jīng)成習(xí)慣,但你應(yīng)該注重你的代碼質(zhì)量。因?yàn)橐苍S有一天有人想要使用,擴(kuò)展或是修改你的工具。特別是如果你將要把你的引擎發(fā)布成開(kāi)源,或是可以讓人隨意修改的時(shí)候,你更應(yīng)該注意。( j3 R. T+ `' w9 _8 o
% x# Z) ^ K+ g
有可能你會(huì)花時(shí)間去做圖形,關(guān)卡,聲音,音樂(lè)和模型,工作量也和你寫(xiě)游戲,工具,引擎差不多。
系統(tǒng)是你的引擎和機(jī)器交互的部分,如果一個(gè)引擎寫(xiě)得非常好的話,那么將它從一個(gè)平臺(tái)移殖到另一個(gè)平臺(tái),應(yīng)該只會(huì)改動(dòng)與系統(tǒng)相關(guān)的部分。系統(tǒng)包含了許多子系統(tǒng),其中包括圖形,輸入,聲音,定時(shí)器和配置。主系統(tǒng)負(fù)責(zé)初始化,更新和關(guān)閉這些子系統(tǒng)。( z v+ W4 v3 K; q$ v" B
圖形子系統(tǒng):它是一個(gè)非常直觀的子系統(tǒng),它就負(fù)責(zé)把東西顯示到屏幕上。許多人都采有OPENGL,D3D,Glide或是軟渲染等圖形API來(lái)實(shí)現(xiàn)。但如果做得更好的話,你應(yīng)該實(shí)現(xiàn)多種圖形API的接口并在它們上面設(shè)置一個(gè)圖形層,這樣用戶可以有多種選擇,也提高了性能和兼容性。這個(gè)東西會(huì)有一點(diǎn)難度,特別是因?yàn)椴皇撬械膱D形API都擁有同樣的結(jié)構(gòu)。。。
輸入子系統(tǒng):它將獲取所有的輸入(Keyboard, Mouse, Gamepad and Joystick)并統(tǒng)一進(jìn)行相應(yīng)的控制。例如:在游戲邏輯中,用戶希望向前移動(dòng)他的位置。比起逐個(gè)檢測(cè)輸入類(lèi)型并處理來(lái)講,更好的做法是調(diào)用子系統(tǒng),由子系統(tǒng)完成透明的設(shè)備檢測(cè)過(guò)程。用戶與玩家可以非常自由地切換輸入裝置,這樣玩家就可以很容易地通過(guò)不同的輸入裝置來(lái)獲取同一行為。
聲音子系統(tǒng):它負(fù)責(zé)載入、播放聲音。該子系統(tǒng)功能非常簡(jiǎn)潔明了,但當(dāng)前很多游戲都支持3D聲音,實(shí)現(xiàn)起來(lái)會(huì)稍許復(fù)雜一些。1 e9 Z F8 @8 C. R% m7 Q% T
3D 游戲引擎中很多出色的表現(xiàn)都是基于“時(shí)間系統(tǒng)”的。因此你需要一段時(shí)間來(lái)好好構(gòu)思一下這個(gè)系統(tǒng)。即使它非常的簡(jiǎn)單,(游戲里)基本上所有東西都是通過(guò)時(shí)間觸發(fā)來(lái)做移動(dòng)變化,所以,如果你設(shè)計(jì)得比較好的話,就可以少寫(xiě)很多冗余代碼。4 ~3 j l" z/ I- ^# c
配置系統(tǒng):位于所有子系統(tǒng)的頂端。它負(fù)責(zé)讀取配置文件,命令行參數(shù), 或是實(shí)現(xiàn)修改設(shè)置(setup)。在系統(tǒng)初始化以及運(yùn)行期間,所有子系統(tǒng)都將一直與它保持通訊。比如:切換圖象分辯率(resolution),色深 (color depth),綁定按鍵(key bindings),聲音支持選項(xiàng)(sound support options),載入游戲等。這個(gè)系統(tǒng)將這些實(shí)現(xiàn)顯得格外的簡(jiǎn)單和方便。如果你的引擎支持配置系統(tǒng),那這調(diào)試和測(cè)試就方便多了,玩家與 用戶也可以方便地選擇他(她)們喜歡的運(yùn)行方式。
控制臺(tái)
我知道所有人都樂(lè)意去跟風(fēng)做一個(gè)象Quake那樣的控制臺(tái)系統(tǒng)。但這的確是一個(gè)非常好的想法。通過(guò)命令行變量與函數(shù),你就能夠在運(yùn)行時(shí)改變你的游戲或是引擎的設(shè)置,而不需要重啟。開(kāi)發(fā)期間輸出調(diào)試信息也非常的有效。很多時(shí)間你都需要測(cè)試一系列變量的值,將這些值輸出到控制臺(tái)上要比 運(yùn)行一個(gè)debugger速度顯然要快得多。你的引擎在運(yùn)行期間,一旦發(fā)現(xiàn)了一個(gè)錯(cuò)誤,你不必立即退出程序。通過(guò)控制臺(tái),你可以做些非常靈活的控制,并將 這個(gè)錯(cuò)誤信息打印出來(lái)。假如你不希望你的最終用戶看見(jiàn)或是使用該控制臺(tái),你可以非常方便地將其隱藏,有人看得見(jiàn)就奇怪了。 ^2 l @8 H, d3 }: A
支持系統(tǒng)% `9 w1 m3 q; Q; F# ^. p' Z, U
這個(gè)系統(tǒng)在你引擎中到處都在用。它包含了你引擎中所有的數(shù)學(xué)成分(點(diǎn),面,矩陣等),(內(nèi))存儲(chǔ)管理器,文件載入器,數(shù)據(jù)容器(假如你不愿自己寫(xiě),也可以使用STL)。該模塊任務(wù)針對(duì)于基礎(chǔ)和底層,你也可以將它復(fù)用到其它相關(guān)項(xiàng)目中去。
渲染器/引擎內(nèi)核
( ~是的,每個(gè)人都喜歡渲染3D圖形。但是渲染一個(gè)3D世界有太多不同方法,那想要描述清楚所有圖形管線工作的情況實(shí)在是太難了。
所以,暫時(shí)不管你如何實(shí)現(xiàn)渲染器吧,最重要的事情是讓你的渲染器組件建立起來(lái),并保持清析的結(jié)構(gòu)。確保你的模塊界線分明(不要把這個(gè)模塊的放到哪個(gè)模塊了,要放對(duì)哦)。我試著將渲染器拆分為以下幾個(gè)部份:可見(jiàn)性(Visibility)、碰撞檢測(cè)與反饋 (Collision Detection and Response)、攝像機(jī)(Camera)、靜態(tài)模型(Static Geometry)、動(dòng)態(tài)模型(Dynamic Geometry)、粒子系統(tǒng)(Particle Systems)、公告板(Billboarding)、網(wǎng)格(Meshes)、天空盒(Skybox)、光線(Lighting)、霧 (Fogging)、頂點(diǎn)SHADER(Vertex Shading)和輸出(Output)。( Z6 z" n( o4 E5 g ]
) e4 \6 Y$ E, X2 }
所有的這些子模塊都需要一個(gè)接口,用來(lái)更改它的設(shè)置,位置,朝向以及其它的一些與系統(tǒng)相關(guān)的設(shè)置
設(shè)計(jì)這個(gè)子系統(tǒng)的時(shí)候,主要克服的困難就是防止特性膨脹,因此,你應(yīng)該在設(shè)計(jì)期間決定你想要實(shí)現(xiàn)什么樣的特性。如果到最后你發(fā)現(xiàn)你不得不新增加特性的話,那說(shuō)明你先前的設(shè)計(jì)很爛。
一個(gè)好而方便的事情就是你將所有的三角面最終提交給渲染管線中同樣的點(diǎn)。(不是同一時(shí)間一個(gè)三角形,我是說(shuō)三角形構(gòu)成的方式 lists, fans, strips等等)多花一些時(shí)間讓所有物體的具有同一格式,這樣它們就都能使用相同的光照計(jì)算、霧、以及填充代碼。但是到最后你會(huì)很高興,因?yàn)檫@樣你就能非常便利地僅通過(guò)切換材質(zhì)與紋理id就使任何多邊形具有不同的渲染效果。" h1 t6 g9 P3 J w
這不會(huì)對(duì)具有多種點(diǎn)的物體繪制造成影響,但是一旦你不當(dāng)心,它可能會(huì)導(dǎo)致大量的冗余代碼。7 n# [ b4 I, S4 u1 I. n3 V
/ A# m) a# H2 a: M" T* Q1 l# G
你最后會(huì)發(fā)現(xiàn),當(dāng)你實(shí)現(xiàn)所有這些NB的效果后,你的工作才做了15%或更少。這是就對(duì)了,圖形效果在一個(gè)游戲引擎中的比重不大。
游戲接口- Z9 E4 `, b9 u+ ^
1 X) P W; E* _2 q' j5 f
一個(gè)3D游戲引擎最重要的就是它是一個(gè)游戲引擎,不是游戲。具體的游戲中的組件將不會(huì)被放到游戲引擎中去。在游戲引擎與游戲之間有一些薄薄的層(接口)。這樣能夠保持引擎的結(jié)構(gòu)清析,也能讓引擎能夠便于使用。這是一些額外的代碼,但是它使游戲引擎能夠被復(fù)用并且可以使用腳本語(yǔ)言輕松地控制游戲邏輯,或者把游戲代碼放到一個(gè)庫(kù)中。如果你嵌入你的游戲邏輯到你的引擎中,那你以后想復(fù)用的時(shí)候,就不要幻想可以直接用了。
我想到現(xiàn)在你最迷惑的應(yīng)該就是介于游戲和引擎之間的那層接口提供了些什么。答案是:控制。引擎的任何部分都有一些動(dòng)態(tài)屬性,因此,游戲/引擎層便是用來(lái)修改這些屬性的一組相關(guān)接口。這些屬性包括了攝相機(jī),模型屬性,光源,粒子系統(tǒng),物理,播放聲音,播放音樂(lè),處理輸入,更改關(guān)卡,碰撞檢測(cè)和反應(yīng),移動(dòng)一個(gè)2D圖片到頭上顯示,屏幕標(biāo)記等等。基本上,如果你想要你的游戲能夠做這些事情,你的引擎就需要提供一個(gè)接口來(lái)讓游戲邏輯使用。
b
游戲% y7 l+ E+ b4 K2 I* L
6 [6 L# f" }! K; F
這里,我無(wú)法告訴你如何去寫(xiě)你的游戲。這該輪到你了。如果你已經(jīng)為你那令人贊異的引擎設(shè)計(jì)出了一套出色的接口的話,我想你在編寫(xiě)游戲過(guò)程中一定會(huì)少很多麻煩。9 s W2 D: b3 v3 f. b) f
: p+ A4 S3 W- ]
3D游戲引擎設(shè)計(jì)是一項(xiàng)巨大的軟件工程。一個(gè)人也能寫(xiě)出一個(gè)游戲,但這不只是熬一兩個(gè)晚上便能搞定的,你很可能會(huì)出寫(xiě)出幾兆的源代碼量。如果你沒(méi)有持久的信念與激情,你早晚會(huì)放棄。4 y4 g# c. p7 ~$ h1 P+ R+ v
5 S6 q, Z; \! _; `1 o$ I
當(dāng)然,別指望你的第一次嘗試就能寫(xiě)出完整的引擎,選擇一個(gè)對(duì)引擎需求較小的項(xiàng)目。努力,你就能成功。
本文來(lái)自CSDN博客,轉(zhuǎn)載請(qǐng)標(biāo)明出處:http://blog.csdn.net/wqjqepr/archive/2010/04/26/5531974.aspx