羅林 李俊琴
摘要:2D游戲具有很大的應(yīng)用前景。游戲軟件是一種復(fù)雜度較高的軟件,利用游戲框架可以降低游戲開發(fā)難度,提高游戲開發(fā)效率,因此設(shè)計(jì)2D游戲框架具有現(xiàn)實(shí)的意義。該文探討了框架的概念,分析了2D游戲軟件開發(fā)的特征,從中總結(jié)出2D游戲框架需要實(shí)現(xiàn)的功能,結(jié)合Windows的圖形設(shè)備接口(GDI),提供了一個(gè)2D游戲框架的設(shè)計(jì),其中實(shí)現(xiàn)了精靈創(chuàng)建、釋放、渲染、資源管理、幀頻鎖定、事件傳遞等2D游戲中必需的功能,并留出了可擴(kuò)展的接口。該文最后給出了框架的使用方法。
關(guān)鍵詞:2D游戲;GDI;框架設(shè)計(jì)
中圖分類號(hào):TP311 文獻(xiàn)標(biāo)識(shí)碼:A 文章編號(hào):1009-3044(2014)27-6480-03
Abstract: 2D Game has great application prospect. Game software is a higher complexity software, and the use of game framework can reduce the difficulty of game development, improve the efficiency of game development, so design a 2D game framework has practical significance. This paper discusses the concept of a framework, analyze the characteristics of 2D game software development, summed up the 2D game framework needed to achieve the functionality, provides the framework for the design of a 2D game with Windows Graphics Device Interface (GDI), realize the sprite to create, release, render, resource management, frame frequency locking, events dispatcher and other necessary function in 2D game, and set aside a scalable interface. Lastly, the paper proposes the framework of the method of use.
Key word: 2D Game;GDI; Framework Design
在軟件開發(fā)中,利用框架可以在保證質(zhì)量的情況下提高軟件開發(fā)效率,降低軟件開發(fā)難度,是目前開發(fā)軟件的一種主流方法。游戲軟件一般要求響應(yīng)快速精確,需要同時(shí)處理聲音、圖像等很多資源,開發(fā)難度較高?,F(xiàn)實(shí)開發(fā)中,通常利用各種框架或者引擎來(lái)降低開發(fā)難度,提高效率。因此,研究游戲開發(fā)中的框架設(shè)計(jì)具有實(shí)際意義。
1 框架的概念
框架(Framework)是整個(gè)或部分系統(tǒng)的可重用設(shè)計(jì),表現(xiàn)為一組抽象構(gòu)件及構(gòu)件實(shí)例間交互的方法。另一種定義認(rèn)為,框架是可被應(yīng)用開發(fā)者定制的應(yīng)用骨架。
從軟件設(shè)計(jì)的角度來(lái)看,框架首先是解決一類問(wèn)題的規(guī)范??蚣苡刑囟ǖ膽?yīng)用領(lǐng)域,不同的框架用于解決不同的軟件開發(fā)需求??蚣芤彩且环N規(guī)范,它向使用者承諾,使用框架可以正確完成某些特定的功能,幫助軟件開發(fā)者快速準(zhǔn)確地完成軟件開發(fā)任務(wù)。同時(shí),軟件開發(fā)者只能遵循框架所約定的特定的調(diào)用方法,才可以正確的使用框架完成軟件開發(fā)任務(wù)。其次,框架抽象了共同的部分。設(shè)計(jì)框架的目的是幫助開發(fā)者快速搭建好軟件開發(fā)的骨架,提供某一類軟件開發(fā)任務(wù)中共同的解決方案。因此框架有必要將某一類軟件開發(fā)過(guò)程中不變的、共同的解決方法抽象出來(lái),形成類結(jié)構(gòu)體系,便于軟件開發(fā)者調(diào)用。最后,框架還應(yīng)該提供可擴(kuò)展的接口。開發(fā)者使用框架的目的是為了方便開發(fā)出自己想要的軟件,因此框架必須是可擴(kuò)展的,便于開發(fā)者在框架的基礎(chǔ)上設(shè)計(jì)出不同的軟件項(xiàng)目。
因此,框架設(shè)計(jì)中要注意面向?qū)ο笤O(shè)計(jì)思想中的“開—閉”原則的使用,即對(duì)修改封閉,對(duì)擴(kuò)展開放,才能達(dá)到既抽象共同部分,又留下可擴(kuò)展接口的設(shè)計(jì)目標(biāo)。
2 基于GDI的2D游戲框架
游戲軟件開發(fā)中,如何高效的管理、渲染各種圖像是關(guān)鍵技術(shù)點(diǎn)。GDI是Windows操作系統(tǒng)中圖形設(shè)備接口(Graphics Devices Interface)的簡(jiǎn)稱。GDI提供了與設(shè)備無(wú)關(guān)的圖形圖像顯示接口,開發(fā)者通過(guò)GDI可以方便地驅(qū)動(dòng)硬件設(shè)備顯示指定的圖形圖像。
游戲框架有多種,該文僅討論一種2D游戲框架的設(shè)計(jì)思路。其中渲染相關(guān)的操作將借助GDI完成,因此在框架設(shè)計(jì)時(shí)必須考慮GDI所需要的渲染環(huán)境準(zhǔn)備。
3 框架的設(shè)計(jì)分析
總結(jié)一下2D游戲的特點(diǎn)可以發(fā)現(xiàn),所有的2D游戲都具有共同的一些特征:
1) 加載必要的資源(圖像,聲音等)
游戲包含豐富多彩的多媒體效果,這些效果離不開圖像和聲音。其中重點(diǎn)是各種圖像效果的呈現(xiàn),簡(jiǎn)單起見,該文僅討論游戲中的圖像呈現(xiàn)部分,框架設(shè)計(jì)也圍繞圖像的呈現(xiàn)來(lái)展開。
在屏幕上顯示的圖像,就是把存放在存儲(chǔ)設(shè)備上的圖像文件加載到內(nèi)存中,按一定的方式顯示。因此,圖像顯示的第一步是需要將圖像文件作為資源加載到計(jì)算機(jī)內(nèi)存中。資源加載需要用到一定的策略。游戲中將呈現(xiàn)眾多圖元,如100架敵機(jī),它們對(duì)應(yīng)了同一個(gè)圖像文件??梢栽O(shè)計(jì)一個(gè)資源池,將所有資源載入,在內(nèi)存中以一定的方式組織和管理起來(lái),在需要用到某資源時(shí),從內(nèi)存中將其讀出并應(yīng)用。
2) 開始游戲后,按與用戶的交互情況推進(jìn)游戲的發(fā)展,直到用戶退出游戲
游戲的發(fā)生、發(fā)展需要按照一個(gè)時(shí)間軸往前推進(jìn)。在推進(jìn)的過(guò)程中,需要接受用戶的輸入事件,根據(jù)用戶的操作,執(zhí)行游戲邏輯,推進(jìn)劇情的發(fā)展。根據(jù)與用戶的交互結(jié)果,顯示當(dāng)前的游戲畫面和聲音變化。值得注意的是,在游戲推進(jìn)過(guò)程中,需要考慮在不同性能的機(jī)器上獲得大致相同的執(zhí)行速度,也就說(shuō)框架需要有一個(gè)鎖定幀頻的機(jī)制。
3) 釋放加載的資源
所有的資源的加載,都會(huì)花費(fèi)一定的內(nèi)存空間。這些內(nèi)存空間需要在特定的時(shí)候由開發(fā)者主動(dòng)釋放,否則會(huì)導(dǎo)致內(nèi)存泄漏,影響操作系統(tǒng)的運(yùn)行性能。因此,框架也需要引入一種機(jī)制,可以在需要時(shí)把所加載的資源卸載,回收相應(yīng)的空間。
分析以上所描述的游戲特征,可以總結(jié)出框架設(shè)計(jì)時(shí)應(yīng)該達(dá)到的設(shè)計(jì)目標(biāo):系統(tǒng)的時(shí)間的傳遞,鎖定幀頻和準(zhǔn)備渲染環(huán)境;資源管理;圖像呈現(xiàn)和管理;鍵盤和鼠標(biāo)事件的處理;可擴(kuò)展的接口設(shè)計(jì)等。
4 框架設(shè)計(jì)與實(shí)現(xiàn)
基于C++的實(shí)現(xiàn)環(huán)境,框架功能的實(shí)現(xiàn)依靠類和類的有序組合來(lái)實(shí)現(xiàn),類的設(shè)計(jì)依賴于設(shè)計(jì)目標(biāo)。各類的設(shè)計(jì)重點(diǎn)詳細(xì)描述如下:
1) CSprit類
制作2D游戲首要解決的問(wèn)題是怎樣將形形色色的精靈顯示在屏幕指定的位置上,同時(shí)還能對(duì)精靈進(jìn)行旋轉(zhuǎn)、縮放和透明等一系列操作。在GDI的繪圖環(huán)境里,圖像通過(guò)LoadImage函數(shù)載入到內(nèi)存,這個(gè)內(nèi)存區(qū)域稱作為“離屏緩沖”,之后使用BitBlt函數(shù)族(BitBlt,StretchBlt和TransparentBlt)將“離屏緩沖”縮放或透明地渲染到顯示設(shè)備的指定位置上。
因此CSprite類里設(shè)計(jì)了一個(gè)渲染函數(shù)Render將上述內(nèi)容進(jìn)行封裝,完成渲染操作。另外,在游戲中存在各種不同的精靈類型,比如可以播放幀序列動(dòng)畫的精靈,可以按自己固定軌跡移動(dòng)的精靈等。這些不同類型的精靈在渲染圖像方面的操作是一樣的,不同的是它們隨著時(shí)間的流逝,各自的行為有所不同。所以在CSprite類里為更新精靈留出可擴(kuò)展的接口Update,這是一個(gè)虛函數(shù):
virtual void Update(float fDeltaTime){}
該函數(shù)的參數(shù)是系統(tǒng)從上一幀到這一幀流逝的時(shí)間。因?yàn)镃Sprite類本身不需要更新自己,所以該函數(shù)的實(shí)現(xiàn)是空的,留給子類進(jìn)行擴(kuò)展。
2) CAnimationSprite類
CAnimationSprite類用于描述動(dòng)畫精靈。動(dòng)畫精靈的紋理不是固定的一幀,而是由若干幀組成。動(dòng)畫精靈在表現(xiàn)角色動(dòng)作方面特別有用,比如角色的行走、戰(zhàn)斗等動(dòng)作都不是用固定的一幀圖像能表現(xiàn)出來(lái)的,有了動(dòng)畫精靈,就可以把多幅圖像按照指定的速度播放出來(lái),這樣能較好地表達(dá)角色的動(dòng)作行為。
CSprite類已經(jīng)具備一般的渲染能力,因此CAnimationSprite類只需要擴(kuò)展CSprite類,重寫Update函數(shù),為其添加加載圖片播放控制部分的功能即可。播放控制主要體現(xiàn)在速度控制和紋理坐標(biāo)截取兩方面。為此,動(dòng)畫精靈需要在每幀里計(jì)算自己需要顯示哪一幀圖片。這個(gè)計(jì)算包含兩方面的意思:一是計(jì)算時(shí)間,以決定是否該更新到下一幀;二是如果需要更新,下一幀的紋理坐標(biāo)如何計(jì)算。
3) CResourceManager類
如前所述,游戲中的資源需要利用資源池統(tǒng)一管理。在設(shè)計(jì)CResourceManager類時(shí)需要考慮資源如何加載、存儲(chǔ)、獲取。在GDI環(huán)境里,資源的加載是通過(guò)LoadImage函數(shù)完成,加載后以離屏緩沖的形式存儲(chǔ)在內(nèi)存中。資源加載后的數(shù)據(jù)可以以標(biāo)準(zhǔn)模板庫(kù)中的list容器方式來(lái)存儲(chǔ)。在設(shè)計(jì)list容器中的節(jié)點(diǎn)數(shù)據(jù)類型時(shí),要考慮資源數(shù)據(jù)的存儲(chǔ)和獲取兩方面;由于游戲中用到的資源較多,可以將資源分為多種類型或組別。在資源管理類中,設(shè)計(jì)新增、刪除、獲取資源節(jié)點(diǎn)的方法即可。
4) CSpriteManager類
2D游戲中將不斷的有精靈產(chǎn)生和消亡,同一時(shí)刻,游戲中的精靈數(shù)目是不確定的。而這些不確定數(shù)目的精靈,都需要在每幀通知它們更新和渲染自身,因此需要把它們有序的組織起來(lái)。
精靈的組織和管理包括以下方面:創(chuàng)建精靈、刪除精靈、通知所有精靈更新、通知所有精靈渲染、釋放所有精靈對(duì)象所占內(nèi)存。其中很多操作都需要遍歷所有精靈,而且精靈產(chǎn)生和消亡是不確定的,所以精靈采用標(biāo)準(zhǔn)模板庫(kù)中的list容器作為數(shù)據(jù)存儲(chǔ)結(jié)構(gòu),由此創(chuàng)建、刪除和遍歷的操作就轉(zhuǎn)化為對(duì)list容器的相應(yīng)的操作。list容器中節(jié)點(diǎn)的數(shù)據(jù)類型是指向CSprite的指針。注意到CSprite是精靈體系的基類,那么當(dāng)把精靈存儲(chǔ)到list中后,在進(jìn)行遍歷操作時(shí),由于多態(tài),將把更新、渲染、釋放等操作事件通知到不同類型的精靈??蚣苤心壳疤峁┝薈Sprite和CAnimationSprite兩中精靈類型,那么CSpriteManager類也提供了兩種對(duì)應(yīng)的創(chuàng)建函數(shù)。
5) CGame類
CGame類是框架和系統(tǒng)事件之間的橋梁,是整個(gè)框架的骨干。CGame類需要具備以下功能:通過(guò)消息循環(huán)來(lái)獲得推動(dòng)時(shí)間軸向前的動(dòng)力,對(duì)不同性能的計(jì)算機(jī)保持大致相同的幀頻;為渲染做好準(zhǔn)備;在每一幀,通過(guò)CSpriteManager對(duì)象通知游戲中所有精靈更新和渲染自身;在游戲中,將鍵盤和鼠標(biāo)事件傳達(dá)給每個(gè)可視對(duì)象;在游戲結(jié)束之前,通過(guò)CSpriteManager的析構(gòu)函數(shù)釋放所創(chuàng)建的精靈對(duì)象等等。
因此,CGame類中設(shè)計(jì)了初始化函數(shù)Init,幀函數(shù)FrameFunc,更新函數(shù)Update,渲染函數(shù)Render,CSpriteManager指針類型成員。在消息循環(huán)中調(diào)用幀函數(shù),主要完成鎖定幀頻、調(diào)用Update函數(shù)更新精靈,調(diào)用Render函數(shù)渲染精靈。這里的Update函數(shù)和Render函數(shù)都要設(shè)計(jì)成虛函數(shù),便于子類繼承擴(kuò)展,完成對(duì)游戲邏輯和游戲渲染的重寫。在初始化函數(shù)中完成GDI繪圖環(huán)境的準(zhǔn)備,主要是要完成“雙緩沖”的創(chuàng)建,以避免游戲中的屏幕產(chǎn)生閃爍的現(xiàn)象。同時(shí),該函數(shù)定義成虛函數(shù),其目的是方便子類繼承擴(kuò)展,用以完成不同類型的資源加載和不同游戲環(huán)境的初始化操作。
5 框架的使用
CGame類是整個(gè)框架的骨干,也就是整個(gè)游戲的核心。為此,使用本框架首先要定義一個(gè)類,繼承自CGame類,在其中重寫Init函數(shù),完成加載資源和初始化工作。而游戲邏輯可以放在Update函數(shù)里,特定的渲染相關(guān)的操作可以放在Render函數(shù)里完成。總結(jié)使用該框架的一般步驟如下:
1) 建立一個(gè)類,繼承自CGame,如CDemoGame;
2) 重寫Init,加載各種資源;
3) 如有必要,重寫Update函數(shù),實(shí)現(xiàn)特定的游戲邏輯;
4) 如有必要,重寫Render函數(shù),實(shí)現(xiàn)特定的渲染操作;
5) 在進(jìn)入消息循環(huán)之前創(chuàng)建CDemoGame對(duì)象;
6) 在消息循環(huán)的空閑段,調(diào)用創(chuàng)建的CDemoGame對(duì)象的FrameFunc函數(shù)更新一幀;
7) 如果有需要,攔截相應(yīng)的消息,調(diào)用創(chuàng)建的對(duì)象的相應(yīng)的消息處理函數(shù);
8) 在程序結(jié)束之前,釋放創(chuàng)建的對(duì)象。
6 結(jié)束語(yǔ)
游戲開發(fā)是比較復(fù)雜的軟件開發(fā),一個(gè)好的框架可以大大簡(jiǎn)化游戲開發(fā)的復(fù)雜程度。該文就這個(gè)問(wèn)題給出了一個(gè)確實(shí)可行的解決方案,能滿足性能、可擴(kuò)展等方面的要求。該文是基于GDI進(jìn)行討論的,也可以在此基礎(chǔ)上改為通過(guò)Direct3D來(lái)完成渲染的操作,進(jìn)一步提高游戲的運(yùn)行性能。
參考文獻(xiàn):
[1] 全國(guó)科學(xué)技術(shù)名詞審定委員會(huì).框架[EB/OL].http://baike.baidu.com/view/66971.htm.
[2] 羅林.2D游戲中的精靈管理[J].科技創(chuàng)新導(dǎo)報(bào),2009(23):176.
[3] 劉生建,羅林.Windows游戲編程中雙緩沖處理技術(shù)的封裝設(shè)計(jì)[J].科技信息,2010,(34):633
[4] 秦海玉.Windows游戲程序設(shè)計(jì)基礎(chǔ)[M].北京:電子工業(yè)出版社,2011.
[5] Stanley B.Lippman,Josée LaJoie,Barbara E.Moo.C++ Primer (4th Edition) [M].李師賢.蔣愛軍,梅曉勇,林瑛.譯.北京:人民郵電出版社,2006.