基于VC的飛行模擬游戲的設計及實現計算機畢業(yè)設計論文
《基于VC的飛行模擬游戲的設計及實現計算機畢業(yè)設計論文》由會員分享,可在線閱讀,更多相關《基于VC的飛行模擬游戲的設計及實現計算機畢業(yè)設計論文(36頁珍藏版)》請在裝配圖網上搜索。
1、 畢業(yè)設計(論文) 基于VC的飛行模擬游戲的設計及實現 論文作者姓名: 申請學位專業(yè): 申請學位類別: 指導教師姓名(職稱): 論文提交日期: 基于VC的飛行模擬游戲的設計及實現 摘 要 電子游戲的出現代表了一種全新娛樂方式的誕生。目前,電子游戲正以其獨特的魅力吸引著眾多的玩家。隨著游戲產業(yè)的蓬勃發(fā)展,越來越多的人加入到了游戲開發(fā)的行業(yè)。游戲開發(fā)涵蓋了程序設計、文學、歷史、音樂及美術等諸多方面的內容,除去市場價值的意義,電子游戲的發(fā)展的必要性還在于對我國文化產業(yè)的發(fā)展的重要性,游戲作為一種特殊
2、的創(chuàng)意文化產品形態(tài),是文化產業(yè)鏈中不可缺少的一環(huán)。設計在利用已有的開發(fā)包和已有的游戲框架的基礎上,采用Microsoft Visual C++2005為開發(fā)平臺,這些開發(fā)包和框架已經完美地解決了游戲圖像和音效方面的問題,設計的主要工作就是向框架中添加自己所設計的類,用于實現設計所要實現的功能。在進行類的設計時,運用C++所具有的繼承和派生功能,使很大一部分代碼能夠得到重用,從而實現多態(tài),同時,還要在父類中很好地引入虛函數,為指針能夠指向子類的同名成員提供方便,然后利用開發(fā)包里的方法來實現游戲背景的顯示,最終得到一個在Microsoft Visual C++2005上運行的飛行模擬游戲,同時在運
3、行時不會出現重大尤其是會令游戲崩潰的BUG。 關鍵詞:飛行模擬;多態(tài);代碼重用 Design and realization of a flight simulation game based on VC Abstract The appearance of computer game has represented the naissance of a totally new sort way of entertainment. At present, the computer game has attracted a
4、great deal of players by its unique charm. Along with the game industry flourishing, more and more people has joined the profession of game development. Game development has covered many contents including programming, literature, history, music, arts ,etc. Eliminate the significance of market value
5、, game develop is quite important to the culture evolution of our nation to be a special kind of creativity culture production. Game is indispensable to the chain of culture industry. The design based on the develop package and the game frame which already exist uses Microsoft Visual C++2005 to be t
6、he platform. These develop package and game frame has raveled out the problem which relate to image and sound effect perfectly. The main task of the design is to add classes that planed by oneself to the game frame, to actualize the function which the design have to realize. When we carry through th
7、e classes design, use the inherit and derive function, we need to enable a majority of code can be reused, aim to actualize polymorphism, at the same time. It is necessary to use virtual function in the baseclass, to make pointer can point to the member which has the same name in the subclass more c
8、onvenience, afterwards, utilize the develop package to realize the demonstration of game background, finally obtain a flight simulation game which can run on Microsoft Visual C++2005, and there’s no seriously bugs especially that can make the game crash when running. Key words: flight simulation; p
9、olymorphism; code reuse 目 錄 論文總頁數:26頁 1 引言 1 1.1 課題背景 1 1.2 國內外研究背景 1 1.3 本課題研究的意義 1 1.4 本課題研究的方法 1 2 游戲軟件的現狀和VC的概況 1 2.1 中國游戲軟件的現狀 1 2.2 C++簡介 2 2.3 Microsoft Visual C++簡介 3 2.4 利用Visual C++開發(fā)游戲簡介 3 3 開發(fā)環(huán)境介紹 3 3.1 開發(fā)環(huán)境 3 3.
10、2 關于Allegro 4 4 游戲程序的開發(fā) 4 4.1 游戲的思路和構想 4 4.1.1 游戲想法的產生 4 4.1.2 對游戲設計的初步認識 4 4.1.3 模塊成型階段 4 4.2 程序的類結構 5 4.3 游戲的實現 5 4.3.1 主類Level的實現 5 4.3.2 Object類的實現 11 4.3.3 Plane類的實現 12 4.3.4 Player類的實現 14 4.3.5 Enemy類的實現 15 4.3.6 Bullet類的實現 16 4.3.7 Prize類的實現 17 5 程序設計過程中遇到的一些重要問題 18 5.1 關于碰撞的問
11、題 18 5.2 關于游戲畫面的問題 21 5.3 關于玩家控制的問題 23 結 論 24 參考文獻 24 致 謝 25 聲 明 26 1 引言 1.1 課題背景 現今,游戲軟件已經成為盈利最高的軟件之一,而且還在向著復雜化、大型化發(fā)展,其中,很多由Visual C++作為開發(fā)工具的游戲都取得了巨大的成功,比如暴雪公司的《魔獸爭霸》系列和《魔獸世界》,這說明Visual C++開發(fā)游戲具有一定的優(yōu)勢。所以,在Visual C++平臺上設計游戲是極為方便的,這也是優(yōu)勢所在。 1.2 國內外研究背景 無論是在國內還是國外,游戲編程已經成為了一種時
12、尚,許多程序員都忘我地投入到其中,他們其中有很多人不光是為了盈利,也有很多是純粹為了興趣,許多著名的游戲編程員本身就是狂熱的游戲玩家,所以,無論是國內還是國外,誕生了很多經典的游戲,其中利用Visual C++作為開發(fā)平臺的更是不勝枚舉,但是由于我國的游戲編程相對于國外起步較晚,所以在很多地方還存在不小的差距,甚至成了很多游戲軟件業(yè)比較發(fā)達的國家的游戲加工廠。 1.3 本課題研究的意義 目前,市面上的游戲可以說是層出不窮,并且隨著電腦硬件系統(tǒng)的改良,未來的游戲必將更智能化,更藝術化,更人性化,在高性能的硬件設備支持下,游戲的驅動引擎更具威力,控制功能更加完備,給人們帶來更豐富的娛樂和體驗,
13、好的游戲給人們的生活帶來了健康愉快的補充,唯美的藝術享受,潛默的教育功效,時尚的情感陶冶,如果沒有足夠的優(yōu)質游戲,那么市場就不免會被粗劣的游戲充斥,可以說,對于青少年來說,誰對游戲編程有著更深入的理解和掌握,誰就掌握著游戲的導向權。 1.4 本課題研究的方法 采用Microsoft Visual C++2005為開發(fā)平臺,在利用已有的開發(fā)包和已有的游戲框架的基礎上,這些開發(fā)包和框架已經完美地解決了游戲圖像和音效方面的問題,設計的主要工作就是添加自己所設計的類,用于實現本設計所要實現的功能,在進行類的設計時,運用C++所具有的繼承和派生功能,使很大一部分代碼能夠得到重用,同時,還要在父類中很
14、好地引入虛函數,為指針能夠子類的同名成員提供方便,最后利用開發(fā)包里的方法來實現一個游戲背景的顯示。 2 游戲軟件的現狀和VC的概況 2.1 中國游戲軟件的現狀 軟件產業(yè)是當前世界上增長最快的朝陽產業(yè)之一,并將成為21世紀推動世界經濟發(fā)展和社會進步的重要動力。近年來,主要國家軟件業(yè)平均以11%以上的增長率快速發(fā)展。據“oecd2000年信息技術展望”報告,1997年,其增長率成員國僅軟件包產值就占世界市場份額的94%,達1080億美元,并自1990年以來年11.2%。美國是世界上最大的軟件生產國,1997年的軟件產值為1705.9億美元,占其當年GDP的2.1%,出口額為155.5億
15、美元。日本其次,1998年軟件產值約570億美元,但出口僅為0.82億美元。英國列第三,1999年的軟件產值為377.46億美元,占其GDP的1.2%,出口約16.2億美元。據對各國軟件業(yè)發(fā)展的軌跡分析,雖然各國的產業(yè)規(guī)模和出口額相差較大,但其成功的因素可歸納為以下幾點:1. 對軟件知識產權的嚴格保護,營造一種誰投資誰受益的良好商業(yè)和法治氛圍; 2. 服務到位的融資機構,促進軟件成果轉化快; 3. 高素質的軟件專業(yè)人才,配合制定靈活的技術移民政策; 4. 具有第一流的大學教育,能夠迅速適應市場對人才的需求; 5. 發(fā)達的通信設施; 6. 長期磨煉的企業(yè)家精神; 7. 巨大的市場需求。 相比
16、于其他國家,我國的軟件產業(yè)特別是游戲產業(yè)起步較晚,在很多地方上都不及一些軟件大國,但是近年來我國軟件業(yè)發(fā)展迅速,有關統(tǒng)計數據顯示,2001年,軟件產業(yè)銷售收入僅為796億元,到了2006年年底已經達到4800億元,5年增長了6倍多。但與軟件產業(yè)發(fā)達國家相比,差距依然很大,絕大部分市場被國外軟件業(yè)巨頭壟斷,國產軟件占據的市場份額很少。在國際市場上,2005年國產軟件出口額為35.9億美元,僅占全球軟件市場份額的5.9%。 2.2 C++簡介 C++語言是在C語言的基礎上為支持面向對象的程序設計而研制的通用程序設計語言,它是由AT&T貝爾實驗室的Bjarne Stroustrup博士創(chuàng)建。研制
17、C++的首要目標是使C++首先是一個更好的C語言,所以根除了C語言中存在的問題,增加了許多新功能。C++的另一個目標是支持面向對象的程序設計,因此在C++中引入了類的機制。所研制的這個語言最初被稱為“帶類的C語言”,1983年取名為C++。C++語言的標準化工作從1989年開始,于1994年制定了ANSI C++標準草案。 C++的主要特點有兩個方面:全面支持C語言與面向對象。C++從C語言發(fā)展而來,保持了C語言的簡潔、高效和在某些操作上沿用了匯編語言指令的特點。同時,對C語言的類型進行了系統(tǒng)的改革和擴充,堵塞了C語言中的許多漏洞,C++編譯提供了更好的類型檢查和編譯時的分析,能檢查出更多的
18、類型錯誤。C++改善了C語言的安全性,比C語言更安全。由于C++保持與C語言兼容,這就使許多代碼不經修改就可在C++編譯器下通過,用C語言編寫的眾多庫函數和實用軟件可方便地移植到C++中。因此,使用C語言的程序員能很快學會C++,使用C++進行編程。另外,用C++編寫的程序可讀性好,代碼結構更為合理。C++的最重要的特點是支持面向對象的程序設計,使用C++編程,編程效率高;由于面向對象的方法更接近人類認識世界的方法,C++對于問題更容易描述,程序更容易理解與維護;C++的模板對庫代碼的重用提供了支持;C++更有利于大型程序設計。C++是一種支持多種程序設計方法的語言,提供對過程化和基于對象的程
19、序設計方法的支持。適合于不同使用開發(fā)方法的編程人員。 2.3 Microsoft Visual C++簡介 Visual Studio是微軟公司推出的開發(fā)環(huán)境。是目前最流行的 Windows 平臺應用程序開發(fā)環(huán)境。目前已經開發(fā)到 8.0 版本,也就是 Visual Studio 2005。在Visual Studio中就有面向 Windows 開發(fā)使用的 Visual C++。 Visual C++自誕生以來,一直是Windows環(huán)境下最主要的應用開發(fā)系統(tǒng)之一。Visual C++不僅是C++語言的集成開發(fā)環(huán)境,而且與Win32緊密相連,所以,利用Visual C++開發(fā)系統(tǒng)可以完成各種
20、各樣的應用程序的開發(fā),從底層軟件直到上層直接面向用戶的軟件。而且,Visual C++強大的調試功能也為大型復雜軟件的開發(fā)提供了有效的排錯手段。 進入21世紀以來,隨著多媒體技術和圖像技術的不斷發(fā)展,可視化技術得到廣泛的重視,越來越多的計算機專業(yè)人員和非專業(yè)人員都開始研究并應用可視化技術。所謂可視化技術,一般是指軟件開發(fā)階段的可視化和對計算機圖形技術和方法的應用。Visual C++是一個很好的可視化編程工具,使用Visual C++環(huán)境來開發(fā)基于Windows的應用程序大大縮短了開發(fā)時間,而且它的界面更友好,便于程序員操作。 2.4 利用Visual C++開發(fā)游戲簡介 進入上個世紀9
21、0年代以來,游戲開發(fā)進入了可視化階段,并且Visual C++是首選的開發(fā)工具,在此期間,誕生了許多用Visual C++開發(fā)的經典游戲,比如任天堂公司Family Computer主機上的《小蜜蜂》以及大名鼎鼎的《星際爭霸》,這些游戲不僅在當時取得了巨大的成功,而且到現在也被奉為經典。可以說在這個時期,Visual C++在游戲開發(fā)領域是獨領風騷。 進入了新千年,JAVA語言開始崛起,由于JAVA具有較高的可移植性,許多游戲,特別是很多手機游戲都轉向了JAVA平臺,但是縱觀市面上最火的單機游戲《魔獸爭霸3》和最火的網絡游戲《魔獸世界》,都清一色的是用Visual C++開發(fā)的,這說明就算在
22、新時期的游戲開發(fā)中, 利用Visual C++作為開發(fā)平臺還是具有一定優(yōu)勢的。 3 開發(fā)環(huán)境介紹 3.1 開發(fā)環(huán)境 操作系統(tǒng):Microsoft Windows XP 程序語言:C++ 開發(fā)平臺:Visual C++ 2005 開發(fā)工具:Allegro 3.2 關于Allegro Allegro是一個免費為C和C++的開發(fā)人員提供的一個游戲編程庫,它支持以下操作系統(tǒng):DOS, Unix (Linux, FreeBSD, Irix, Solaris, Darwin), Windows, QNX, BeOS 和 MacOS X。它還提供了很多諸如圖形,聲音,玩家輸入(鍵盤,鼠標和手
23、柄)和定時器的功能。它也提供了浮點運算功能,3D功能,文件管理功能和GUI。當前最新版本為4.3.1,官方網址為 4 游戲程序的開發(fā) 4.1 游戲的思路和構想 4.1.1 游戲想法的產生 資料顯示,在上個世紀風靡一時的任天堂FC主機上,最火爆的飛行游戲便是《小蜜蜂》,這款游戲已其獨特的游戲方式征服了億萬玩家,這款游戲的游戲方式雖然極為簡單,但是卻極為有趣,停留在屏幕上方的蜜蜂不停地向下攻擊玩家所控制的飛機,玩家不僅必須要避開蜜蜂的攻擊,還要控制飛機還擊蜜蜂而玩家擊中這些蜜蜂以后,他們死亡后會有一定幾率掉落增加玩家生命,玩家子彈速度和玩家得分的獎子,而這款《小蜜蜂》,正是用C++語言開發(fā)
24、的,這說明,在Visual C++平臺下開發(fā)一個類似于《小蜜蜂》的飛行射擊游戲是可行的。 4.1.2 對游戲設計的初步認識 整個設計的關鍵詞如下:游戲、飛機、敵機、子彈、關卡、玩家、獎子、屏幕、三發(fā)子彈、雙發(fā)子彈、改變玩家子彈類型變化的獎子、增加玩家生命的獎子、爆炸,這些關鍵字都需要定義一個獨立的類來描述它們,并且,可以把飛機類設定為敵機類和玩家類的父類,因為飛機類中的一些方法也可以用于敵機類和玩家類,同理,也應該把獎子類設定為改變玩家子彈類型變化的獎子類和增加玩家生命的獎子類的父類,至于子彈,則不必用到繼承和派生,因為無論是三發(fā)子彈還是雙發(fā)子彈,他們的屬性和功能都是一樣的,差別只是存
25、在于視圖上。 4.1.3 模塊成型階段 進一步熟悉了編程知識后,對框架做出了一些修改,逐步把游戲的基本功能確定。 1.Level類主要實現負責管理游戲中的所有物體,包括管理顯示,碰撞,創(chuàng)建和回收等,還提供了一些服務,方便查詢關卡中的一些物體的信息。 2.Object類主要負責控制可見性,坐標位置,設置速度等,其中就主要的一個功能就是判斷物體是否越界。 3.Plane類主要就是實現設定飛機的爆炸類型,子彈類型,實現開火以及設定開火冷卻時間,而其子類Enemy類則進一步實現了設定敵機的生命值和掉落的獎子類型。另一個子類Player類增加了實現玩家在被擊毀后誕生時的無敵時間。 4.B
26、ullet類主要實現了子彈的創(chuàng)造。 5.Explosion類主要實現了爆炸的創(chuàng)造。 6.Prize類主要實現玩家“吃”掉獎子后改變玩家屬性。 4.2 程序的類結構 圖1 游戲類結構圖 4.3 游戲的實現 4.3.1 主類Level的實現 Level類是最核心的類,他實現了最初關卡的創(chuàng)建,最終關卡的銷毀,并實現了檢測碰撞,為Object類里的物體實現碰撞提供了接口,同時,Level類中的兩個方法getNearestEnemy和getNumCompanies則為敵機對玩家實行攻擊策略提供了函數,最后,玩家“吃”掉獎子后生命增加和得分增加的函數實現也包含在Level類中,所謂關卡,
27、就必須要有一定的運行狀態(tài),關卡運行有三種狀態(tài),可以定義一個枚舉類型來定義三個不同的狀態(tài),這里用到枚舉類型的原因是,關卡運行的狀態(tài)只有運行,結束和失敗三種,只有有限的幾種可能值,雖然可以用int, char等類型來表示他們,但是對數據的合法性檢查卻是一件很麻煩的事情,而C++中的枚類型就是專門來解決這類問題的 typedef enum Status //關卡狀態(tài)定義一個名為Status的枚舉類型 { LEVEL_END, //關卡結束 LEVEL_FAILED, //關卡失敗 LEVEL_RUN,
28、 //關卡運行 }; 同時,在游戲運行中會發(fā)生不同的事件,也需要一一定義,由于游戲事件較多,同理,也需要定義一個枚舉類型來定義眾多的事件 enum Event { E_RenewPlayer,//! 創(chuàng)建玩家,關閉所有事件 E_ReadyDelay,//! 顯示‘ready’前的等待,并啟動E_Ready 事件 E_Ready,//! 顯示‘ready’,啟動E_RenewPlayer 事件 E_LevelEnd,//! 使關卡處于完成狀態(tài),表
29、示通關 E_LevelFailed,//! 使關卡處于失敗狀態(tài) E_LevelFailedDelay,//! 關卡失敗前的等待,并啟動E_LevelFailed 事件 E_LevelEndDelay,//! 關卡通關前的等待,并啟動E_LevelEnd 事件 }; 接下來,我們所要做的,便是創(chuàng)建關卡,從關卡文件中讀入物體數據,創(chuàng)建物體并加入到關卡中 bool create (char *name, dev::ResourceManager* rs, dev::KeyBoard *kb); 在關卡最初創(chuàng)建時,需要把敵機數目設置為0,把關
30、卡狀態(tài)設置為運行,同時應該關閉定時器。接著就是使用io包內的ReadFile創(chuàng)建對象rf,方便讀取文件,以實現關卡中敵機的初始化,由于IO包不透明,所以無法了解其內部是如何實現這一功能的,在此,只能列出在文本中的格式,格式如下: 視圖 獎子 爆炸 子彈 體力 坐標X 坐標Y 策略號 視圖有兩種:編號1表示使用第一個敵機圖片,編號2表示使用第二個敵機圖片;獎子有四種:編號0表示沒有獎子,編號1表示獎一個生命的獎子,編號2表示獎勵三發(fā)子彈武器的獎子,編號3表示獎勵20分的獎子;爆炸有三種:編號0表示小型爆炸,編號1表示普通爆炸,編號2表示大型爆炸;子彈有四種:編號0表示小單發(fā)子彈,編號1表示雙
31、發(fā)子彈,編號2表示三發(fā)子彈,編號3表示反彈型單發(fā)子彈,編號4表示高速雙發(fā)子彈;體力的數值就表示可以被攻擊多少次;坐標的兩個數值即為敵機在關卡中的坐標位置。 比如說,要設置一個使用第一張敵機圖片,掉落一個獎勵20分的獎子,爆炸類型為普通爆炸,發(fā)射小單發(fā)的子彈,可被攻擊1次,坐標為60 80的敵機,那么就在文本文件中輸入1 3 1 0 1 60 80 由于這里涉及設備層中的資源管理器,提供加載圖片和聲音的服務以及設備層中的鍵盤,提供輸入查詢,具體的實現將放到重要問題說明中詳細介紹。 關卡創(chuàng)建完畢,就應該向其中添加我們想要的東西,并使其工作 void Level::add (Object *
32、o)//向關卡里添加敵機的實現 { int id = o->getRuntimeClassID();//獲取物體運行時的類ID if (id==Enemy::ClassID)//如果物體是敵機,增加敵機數目 { mNumEnemies++; } 在這里向關卡中添加敵機時先要判斷當前被添加物體是否為敵機,如果是才添加,如果不是,則不添加。 敵機添加完畢就需要創(chuàng)建玩家,玩家的位置是固定的,把玩家的坐標位置設置為:X軸坐標設置為當前關卡X軸的二分之一,Y軸坐標設置為當前關卡Y軸最大值減20 p->setPos (&Vector(mArea.x2/2, m
33、Area.y2-20)); 要添加,就必須要移出,所以相應的,也就有摧毀物體,比如在關卡結束后,我們需要摧毀關卡中所有的資源,所以我們定義一個destroy方法,摧毀關卡中的所有物體,釋放資源給資源管理器,比如圖片和聲音 void destroy (dev::ResourceManager* rs); 同時,關卡還需要處理玩家或者敵機的死亡,我們定義一個processDie的方法來實現,流程如下 圖2 處理飛機死亡流程 其中在判斷物體的類別,并且完成玩家和或者敵機的死亡
34、后繼續(xù)判斷玩家的生命是否用盡和敵機數目是否為0,這樣做的目的是為了避免在玩家和最后一個敵機同歸于盡的時候依然進入關卡結束事件。 而update方法算是Level類中比較關鍵的方法,他更新關卡中的所有物體,包括檢測碰撞,更新定時器,處理碰撞等,其中最主要的方法便是物體的越界處理,首先計算物體的坐標與關卡邊緣是否發(fā)生相交,其中判斷是否在X軸越界的算法為:取出物體的坐標,判斷其是否小于關卡的坐標X1或者其是否大于關卡的坐標X2,若滿足一項時,則調用Object類中的onOutOfArea方法,實現每個物體不停的越界實現,流程圖如下 開始 取出當前物體的坐標 是否大于關卡坐標X2 或者小
35、于關卡坐標X3 通知物體做越界處理 結束開始 圖 3 判斷物體是否在X軸上越界流程 其中,關于檢測物體碰撞由于是本設計的重點和難點,將放在后面的重要說明中具體說明。 關卡還需要實現兩個方法,那就是getNearestEnemy和getNumCompanies,它們主要是用來實現敵機的攻擊策略的,這里首先要聲明一下,當玩家,敵機和獎子類被創(chuàng)建時,都會獲取一個ID,以表明其身份,同樣的,凡是通過這幾個類創(chuàng)建的對象也具有與其所屬類相同的ID,通過這樣的方法,就可以把關卡中眾多的物體相互之間區(qū)分開。 getNearestEnemy主要
36、是實現敵機將離其最近的玩家作為目標,以實現跟蹤策略,其基本思想是,以當前物體作為中心,對整個關卡中的物體進行一個遍歷,若它們同為敵機,則繼續(xù),若它們一個為玩家,一個為敵機,則計算出與其的距離,選出其中與自己距離最小的物體,判斷其是否小于最小距離,若小于,則把當前物體鎖定為自己的目標,流程如下 圖4 鎖定最近敵人的流程 getNumCompanies方法主要是用于給敵機策略提供一個接口,它是基于這樣一個想法,那就是當敵機總數大于一個數值時,敵機不會做出任何攻擊動作,而當玩家消滅
37、一定數量后,敵機便會實行攻擊策略,getNumCompanies就是讓敵機獲取當前敵機總數,當其返回值小于一定的值時便執(zhí)行攻擊策略,實現的方法仍然是對以當前所指向的物體為中心進行遍歷,若被遍歷到的物體與其為同一隊伍且同為敵機或玩家,則同伴數目增加1,最開始時,同伴數目設置為0,流程如下 圖5 取得同伴數目流程 此外,關卡還需要管理增加玩家生命和得分,用于實現玩家“吃”掉獎子后的屬性改變,分別定義為addPlayerLife和addScore方法實現,實現方法為他們實現自加即可。 4.3.2 Object類的實現
38、 Object類主要管理物體的可視性,速度,以及判斷設置物體的隊伍和判斷隊伍是否一樣等,他抽象了所有的物體,也就是說,其中所有的屬性和方法是一切物體都具有的,這樣做是為了增加代碼的重用量,這也是運用C++開發(fā)游戲的好處之一,但是,這樣做就要求把Object類的析構函數設為虛函數,這是因為如果不將析構函數設為虛函數的話,那么當用一個Object類的指針刪除一個其子類的對象時,子類的析構函數就不會被調用,雖然這樣做并沒有什么實際意義,但是這卻符合用C++進行軟件開發(fā)的時候一般用來做基類的類的析構函數設為虛函數的默認規(guī)定,因此,需要將析構函數設為虛函數。 此外,還有幾個方法是需要重點提及的: O
39、bjectTracer* setTracer是設置越界處理器,這個處理器將處理物體的越界事件 ObjectTracer* setTracer (ObjectTracer* tr) //指針指向新的越界處理器 { ObjectTracer* old = mTracer; mTracer = tr; return old; //返回舊的越界處理器 } setDirection是用來設置物體的移動方向,這個方向為用來修改物體的當前運動速度 void setDirection (Vector* dir) //指針指向新方向向量 {
40、 Vector* vel = getVelocity(); dir->normalize ();// 單位化這個向量 vel->multiply (dir);// 應用這個向量到速度上 } onOutOfArea方法是為了實現物體越界的處理函數,將任務代理給mTrancer處理,這樣實現了ObjectTracer接口的類都可以處理物體的越界 void onOutOfArea (bool onX) //onX 為真的話表示在X軸上越界,否則在Y軸上 { if (mTracer) mTracer->onOutOfArea (th
41、is, onX); } 通過這樣的方法,在前面提及的Level類中的update方法就可以成功地實現越界處理。 另外,顧名思義,所謂Object類,肯定是要設定所有物體的屬性的,這些屬性包括是否可見Visible,是否可碰撞Collidable,物體所屬隊伍號Team,設置位置setPos和獲取位置getPos,設定速度setVelocity和獲取速度getVelocity,需要說明的是,這里的速度不是普通的標量,而是一個矢量,即它是有方向的,這樣做的好處就是由于飛機是只能向前開火,并且其面朝的方向應該和其速度的方向一致,那么如何來實現這兩點呢?這就需要把速度設置為一個矢量,這樣一來
42、,就可以把飛機的開火方向和面朝方向與速度方向取一致。 4.3.3 Plane類的實現 Plane類是Object類的子類,它通過Object類公有繼承而來,所以,凡是Object類中有的方法和屬性,它也具有,當然,我們必須為起添加新的函數或者數據,那么飛機相對于其他物體特有的屬性是什么呢?對,那就是它們死亡的時候會發(fā)生爆炸,它們也能發(fā)射子彈,而每種飛機所產生的爆炸類型和所發(fā)射的子彈類型都是不同的,所以,我們在Plane類中就設定幾個方法來設定物體的爆炸類型,所發(fā)射的子彈類型以及他們的速度 飛機的死亡會產生爆炸,同時也會變得不可見 void Plane::die(void)
43、 //死亡的實現 { Object *obj = mEF->create (mExplType); if (obj) { obj->setPos (this->getPos()); mLevel->add (obj); } disappear (); } 凡是玩過飛機游戲的人都知道,飛機是不能連續(xù)發(fā)射子彈的,在兩次發(fā)射子彈之間,必須要有一定的冷卻時間,,而這個功能是由Plane類的一個update方法實現,思路為:對每一個飛機都設定一個定時器CoolTimer,初始值為10,然后不斷對它進行檢查,只要它的值不為0,就進行自減,如果某個
44、飛機有開火請求的話,就檢查定時器的值是否為0,如果為0,則允許開火,同時定時器的值復位為初值,如果定時器的值不為0,則開火請求無效,流程如下: 圖6 飛機開火冷卻流程 同時,由于假定飛機只能向前運動,而不能向后運動,所以飛機的朝向向量也就必須和它的速度向量一致,在前面已經介紹過,在設定Object類中設定了物體的速度為矢量,這樣就可以把飛機的朝向向量與其速度矢量取一致了 if (getVelocity()->length()) // 如果物體有速度,那么物體的朝向向量就根據他的速度來進行調整 { mFaceDirection.sca
45、le(0); mFaceDirection.add (getVelocity()); mFaceDirection.normalize (); } Object::update(); } 此外還有一個問題,那就是本游戲假定的是所有飛機都只能向前方發(fā)射子彈,所以在發(fā)射子彈的實現中,就必須把子彈的方向與飛機所面對的方向取一致,同樣的,也只需要把子彈的方向與飛機的速度方向取一致就可以了 void Plane::fire () { Bullet* b = mBF->create (getBulletType(), getTeam()); if (
46、b==0) return; b->setPos (getPos ()); b->setDirection (&mFaceDirection); //將子彈的方向與飛機面朝的方向取一致 mLevel->add (b); } 4.3.4 Player類的實現 Player類主要實現了玩家的一些方法,它繼承了飛機類的所有參數和方法,玩家和敵機除了操作不一樣以外,其余的屬性基本一致,比如說,玩家一樣有開火的冷卻時間,另外,為了和所有已有的飛行游戲接軌,需要將玩家剛誕生時的一段時間設為無敵時間,即在這段時間內,所有敵機的攻擊都對玩家無效,而且,照以往飛行游戲的
47、慣例,在這段無敵時間內,玩家是在不停閃爍的,為此,我們設定為其無敵時間為100,再取名一個為MatchlessTimer的定時器,讓其不停自減,當減為0時,無敵效果取消,那么,如何實現玩家的閃爍呢?其實所謂“閃爍”,意思就是其可視性在不停地變化,在這100時間內,不停地對其視圖可視性取非運算,以實現其閃爍的效果,當無敵時間耗盡時,只需要干兩件事:第一,取消玩家無敵狀態(tài),通過設置玩家Collidable屬性為真實現;第二,取消玩家的閃爍,通過設置玩家Visible屬性為真實現。 關于玩家的控制,將在后面的重要問題中說明。 4.3.5 Enemy類的實現 Enemy類主要實現的功能是設定
48、敵機的生命值,設定掉落獎子類型,其他一些行為全部由父類Plane繼承而來,但是對于update這個方法,Enemy類進行了重寫,目的就是為了實現在不同時間敵機采用不同的攻擊策略來攻擊玩家,我們現在設定敵機每5個周期就執(zhí)行一次攻擊策略,那么如何實現敵機每5個周期就更新一次其攻擊策略呢?這同樣需要設置一個定時器UpdateAITimer來實現,首先設置UpdateAITimer的初值為0,然后對它進行自加,同時對UpdateAITimer的值進行檢查,當它的值為5的倍數時,敵機的攻擊策略就進行更新,再進一步,如何判斷UpdateAITimer的值是否為5的倍數呢?當然通過把 UpdateAITim
49、er的值對5取余,當得到的值等于0時,UpdateAITimer的值即為5的倍數,敵機的攻擊策略也就進行相應的更新。 那敵機的攻擊策略由誰負責管理?所有敵機的攻擊策略都是由AI指針管理,在關卡剛創(chuàng)建時,AI指針指向的是DefaultAI,這時敵機的攻擊策略是不作出任何動,作在敵機執(zhí)行DefaultAI時,他會調用Level中的getNumCompanies方法,當返回值小于最小友軍數目時,它便會調用Level中的getNearestEnemy方法,它的目的是尋找是否有玩家,若玩家已被擊毀,則執(zhí)行DefaultAI,停止任何動作,如果玩家仍然存在,那么就把玩家的坐標取出,與自己的坐標相減,算出
50、距離,若距離小于最小距離mMinDist,則實施隨機開火策略,開火幾率是1%到100%之間的一個隨機數,流程如下: 圖7 敵機攻擊策略更新流程 那么,如何保證開火幾率為0%至100%之間的一個隨機數呢?這就要通過一個隨機數rnd來實現,把它的值設為rand()%100,這樣就保證rnd總是小于100了。 4.3.6 Bullet類的實現 Bullet類主要實現的就是子彈的創(chuàng)造了銷毀,以及設定子彈與飛機的碰撞,它也是Object類的子類,繼承了Object類的所有屬性和方法,其中,子彈都是
51、由子彈工廠BulletFct創(chuàng)造的,也是由其銷毀的,子彈共有3種,同前面介紹的一樣,為了方便,可以定義一個枚舉類型來描述它 typedef enum BulletType { BT_NORMAL, BT_DOUBLE, BT_THREE, }; 接下來,就要創(chuàng)建子彈,但是由于 BulletFct不知道是要創(chuàng)建哪種子彈,所以在創(chuàng)建子彈的時候,需要一條switch語句來判斷所要創(chuàng)建子彈的類型,共有3種子彈類型,所以switch語句就應該有3種case,分別對每一種子彈進行相
52、應的視圖創(chuàng)建。 在這里有一個問題,那就是BulletFct一次性地創(chuàng)建了200個子彈,如果不對其進行回收,這就勢必會大大增加了系統(tǒng)的開銷,導致運行速度的緩慢,如何解決著一問題呢?可以創(chuàng)建一個“池子”,創(chuàng)建的所有子彈都先放入這個池子中,當飛機開火需要子彈時,再從池中取出子彈供其使用,同理,當關卡中有不用的子彈時,也放入池中以供以后使用,這樣就大大增強了資源的重利用,也節(jié)省了許多不必要的系統(tǒng)開銷,這個表的主要思想是:存放一群物體。根據物體的使用情況,存放到兩個表內。一個表存放所有物體,另外一個表存放無效的物體。當用戶需要物體時,從無效的物體表內取給用戶。當用戶用完后回收時,存放這個物體到無效物體
53、表內以供下次使用,流程如下: 圖8 子彈調用和回收流程 在本游戲中,所有的子彈只能是直線向上或者向下運動,所以它的更新方法比較簡單,只需要先判定子彈是否誕生,如果誕生的話,就取出它的坐標以及它的速度向量,然后以其速度向量為方向對其坐標作加。 4.3.7 Prize類的實現 Prize類和Bullet類似,也是Object類的子類,它的主要功能是實現獎子的創(chuàng)建和銷毀,以及設定和玩家的碰撞行為,獎子一共有3種,但是我們把沒有獎子也算成一種,所以共有4種獎子,同樣用一個枚舉類型來定義它 typedef enum Prize
54、Type { BT_NO, //沒有獎子 BT_LIFE, //增加玩家生命的獎子 BT_THREE_BULLET, //子彈變?yōu)槿l(fā)的獎子 BT_SCORE, //增加玩家得分的獎子 }; 獎子都是由PrizeFct創(chuàng)建的,3種不同的獎子的創(chuàng)建方法是不同的,所以,也需要一條switch語句來分別實現4種(其實只有3種,因為沒有獎子是不需要創(chuàng)建任何東西的)不同獎子的創(chuàng)建。 在本游戲中,子彈的更新方法只是與子彈類似,也同樣是取出它的坐標以及它的速度向量,然后以其速度向量為方向對其坐標作加。
55、 那么獎子如何實現改變玩家的相關屬性的呢?為了實現不同獎子改變玩家不同屬性,我們又用 Prize類派生出3個子類:AddLifePrize 類,ChangeBulletPrize類和ScorePrize類,分別用來實現增加玩家生命值,改變玩家子彈和增加玩家得分,以AddLifePrize 類舉例,它增加玩家的生命就通過調用Level類中的addPlayerLife函數實現 void AddLifePrize::changeAttribute(Player *p)//增加玩家生命的實現 { mLevel->addPlayerLife (); } 同樣,ChangeBulletPr
56、ize類改變玩家子彈通過調用Player類中的SetBulletType函數來實現 void ChangeBulletPrize::changeAttribute (Player* p)//改變玩家子彈類型的實現 { p->setBulletType (mType); } ScorePrize類增加玩家得分通過調用Level類中的addScore來實現 void ScorePrize::changeAttribute(Player *p) //增加玩家得分 { mLevel->addScore (mScore); } 5 程序設計過程中遇到的一些重要問題 5.1
57、關于碰撞的問題 碰撞檢測問題是本程序的難點和重點,也是所有飛行射擊游戲的難點和重點,所謂碰撞檢測,就是指檢測在某一時刻是否有2個或者以上的碰撞矩形相交。那么我們首先要做的就是設定一個物體的碰撞矩形,具體做法為,在PlaneView中以此物體視圖的中心為點,上,下,各取視圖高度的一半,左,右各取視圖寬度的一半,然后調用Object類中的setCollShape方法來設定其碰撞矩形 void PlaneView::changeShape (Object *obj) { float w = m_plane->getW(), h = m_plane->getH (); obj->
58、setCollShape (&Rect(-w/2,-h/2, w/2, h/2)); } 雖然給物體的碰撞矩形設定完畢了,但是我們設想一下,當物體開始移動時,也就是視圖開始移動,但是它的碰撞矩形卻還留在原地,這顯然會造成碰撞檢測不能正確地完成,如何解決呢? virtual void update(void) { mNewShape = mCollShape; mNewShape.translate (&mPos);//將碰撞矩形移動到物體的當前坐標上 }; 接下
59、來,我們所要做的就是進行碰撞檢測,這個方法是由Level類實現的,先從一個物體A開始,若A被設定為不能碰撞,則繼續(xù)從下一個物體開始,若A能發(fā)生碰撞,則又判斷是否有物體B的碰撞矩形和其相交,若有,則判斷A和B是否屬于同一隊伍以及物體B是否為不能碰撞,若其中有一為真,則不進行任何處理,否則就調用Object類中的onCollide方法實現碰撞,流程如下: 圖9 物體實現碰撞流程 而Object類中的onCollide方法很簡單,就是令發(fā)生碰撞的物體消失 void Object::onColli
60、de(Object* obj) { disappear (); //令物體消失 } 而disappear方法又調用Level類中的processDie方法,processDie方法在之前已經清楚地利用流程圖進行了表示。至此,玩家與敵機的碰撞就完美解決了,但是子彈與玩家,子彈與敵機,獎子和玩家之間的碰撞還沒有實現,為了實現子彈與玩家和子彈與敵機之間的碰撞,在Bullet類中重寫Object類中的onCollide方法,因為各個子彈之間和子彈與獎子之間是不能發(fā)生碰撞的,所以,還必須先對與子彈的碰撞矩形相交的物體進
61、行檢測 void Bullet::onCollide (Object* obj) { int id = obj->getRuntimeClassID(); if (id==Prize::ClassID || id==Bullet::ClassID) //子彈與獎子,子彈之間不能發(fā)生碰撞 { } else //子彈與玩家和敵機碰撞的實現 { Explosion* ep = mEF->create (ExplFct::ET_SMALL); if (ep) { e
62、p->setPos (getPos()); mLevel->add (ep); } Object::onCollide (obj); } } 最后,便是獎子與玩家碰撞的實現,同樣,在Prize類中也重寫Object 類中的onCollide方法,因為獎子和子彈以及敵機是不能發(fā)生碰撞的,所以我們也必須對與獎子的碰撞矩形相交的物體進行檢測 void Prize::onCollide (Object* obj) { int id = obj->getRuntimeClassID(); if (id==Bullet::ClassID ||
63、 id==Enemy::ClassID) //獎子不能與敵機和子彈發(fā)生碰撞 { } else { Object::onCollide (obj); //獎子可以與玩家發(fā)生碰撞 mBeEaten = true; } } 5.2 關于游戲畫面的問題 由于我之前對于游戲編程只是一個初步認識,所以完全沒有接觸過關于圖像渲染及其他方面的知識,所以之前這個方面我感到無能為力,所以我只有使用了同學給我提供的整個游戲框架,在這個框架中,所有的關于圖像資源的初始化,渲染和摧毀都已完成,而且實現這些功能的開發(fā)包alleg,dev
64、,io對外都是不透明的,所以無法看到其內部的方法,但是我還是通過這幾個包實現了游戲背景的顯示,背景主要就是表現一些星星不停地閃爍,這主要是通過Background類實現的。 首先把星星放入關卡中,因為放置星星的區(qū)域不能超過關卡的區(qū)域,所以要設定放置星星的區(qū)域的寬度為關卡坐標X2-X1,高度設為關卡坐標Y2-Y1,同理,星星的位置也不能超過放置星星的區(qū)域,所以令星星的X坐標和Y坐標分別取放置星星區(qū)域的寬和高的一個隨機值,通過如下語句來實現 s->pos.x = rand () % w; s->pos.y = rand () % h; 為了讓星星閃爍,就必須讓其每隔一段時間更新一次,現在設
65、定每30個周期更新一次,這只需要判斷時間是否為30的倍數即可(s->delay = rand () % 30)另外,要實現閃爍,就要有顏色的變化,那么如何實現顏色的變化呢?dev包中有一個方法Color,只要賦給其一定的值,便能顯示出一定的顏色,顏色左端點的值為col1,右端點的值為col2,當前顏色為col,開始時設定col=col1。 接下來的工作就是令星星開始閃爍,閃爍是通過定時器timer實現的,其基本思想是:對每一個星星都設置一個定時器timer,把其初值設為0,對它進行自加,然后隨時對其進行檢測,如果它的值大于delay,則把它復位為0,如果它的值小于delay,則計算其占del
66、ay的比例(float sc = (float)s->timer / s->delay),然后根據比例對兩個顏色端點進行線形插值計算當前顏色(color方法規(guī)定顏色有3個分量,所以顏色的每個分量都要計算),最后根據計算出的新顏色并更新星星的當前顏色,流程如下:
圖10 星星顏色變化流程
到這里,我們的工作似乎結束了,但是運行游戲會發(fā)現背景并沒有星星的顯示,為什么呢?這是因為我們定義的一個星星只是一個像素點,對于我們人的肉眼來說是很小的,我們自然看不見,所以只有把其放大成為一個矩形,這樣我們就能夠看見了
int rg = 1;
for (int i=0; i
- 溫馨提示:
1: 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
2: 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權益歸上傳用戶所有。
3.本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
4. 未經權益所有人同意不得將文件中的內容挪作商業(yè)或盈利用途。
5. 裝配圖網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
6. 下載文件中如有侵權或不適當內容,請與我們聯(lián)系,我們立即糾正。
7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。