




版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)
文檔簡(jiǎn)介
第11章飛機(jī)大戰(zhàn)《Python快速編程入門(第3版))》學(xué)習(xí)目標(biāo)/Target010203游戲簡(jiǎn)介項(xiàng)目準(zhǔn)備游戲框架搭建04游戲背景和英雄飛機(jī)學(xué)習(xí)目標(biāo)/Target050607指示器面板逐幀動(dòng)畫和飛機(jī)類碰撞檢測(cè)08音樂和音效章節(jié)概述/Summary飛機(jī)大戰(zhàn)是一款由騰訊公司微信團(tuán)隊(duì)推出的內(nèi)置軟件小游戲,擁有簡(jiǎn)潔有趣的畫面、易于理解的規(guī)則和簡(jiǎn)單易上手的操作,在移動(dòng)應(yīng)用興起初期曾一度風(fēng)靡。本章將帶領(lǐng)大家使用Pygame庫開發(fā)一個(gè)功能較為完整的飛機(jī)大戰(zhàn)游戲項(xiàng)目,引導(dǎo)大家在實(shí)際開發(fā)中靈活應(yīng)用面向?qū)ο蟮木幊趟枷?,讓大家在學(xué)習(xí)中體驗(yàn)使用Python語言開發(fā)游戲項(xiàng)目的樂趣。游戲簡(jiǎn)介11.1
先定一個(gè)小目標(biāo)!了解飛機(jī)大戰(zhàn)游戲的規(guī)則,能夠復(fù)述出飛機(jī)大戰(zhàn)游戲的規(guī)則11.1游戲簡(jiǎn)介飛機(jī)大戰(zhàn)游戲主要以太空主題的畫面為游戲背景,由玩家通過鍵盤控制英雄飛機(jī)向敵機(jī)總部發(fā)動(dòng)進(jìn)攻,在進(jìn)攻的過程中既可以讓英雄飛機(jī)發(fā)射子彈或引爆炮彈擊毀敵機(jī)以贏取分?jǐn)?shù),也可以拾取道具以增強(qiáng)英雄飛機(jī)的戰(zhàn)斗力,一旦被敵機(jī)撞毀且生命值為0就結(jié)束游戲。飛機(jī)大戰(zhàn)游戲的部分場(chǎng)景如圖所示。11.1游戲簡(jiǎn)介飛機(jī)大戰(zhàn)游戲中包含眾多游戲元素,例如,大小各異的飛機(jī)、連發(fā)的子彈、左上角的游戲分?jǐn)?shù)等。飛機(jī)大戰(zhàn)游戲中主要的元素如圖所示。11.1游戲簡(jiǎn)介1.背景游戲窗口的整體背景是一張星空?qǐng)D像,它會(huì)以恒定的速度向下緩慢地滾動(dòng),讓玩家感覺自己的英雄飛機(jī)在向上飛行。2.英雄飛機(jī)英雄飛機(jī)是由玩家控制的飛機(jī),是飛機(jī)大戰(zhàn)游戲的主角,其相關(guān)說明具體如下。(1)英雄飛機(jī)在游戲開始時(shí)顯示在游戲窗口下方的中央位置。(2)英雄飛機(jī)在出場(chǎng)后3秒內(nèi)處于無敵狀態(tài),此時(shí)它不會(huì)被任何敵機(jī)撞毀,也不會(huì)撞毀任何敵機(jī)。11.1游戲簡(jiǎn)介2.英雄飛機(jī)(3)玩家可以通過方向鍵↑、↓、←、→控制英雄飛機(jī)在游戲窗口范圍內(nèi)向上方、下方、左方和右方移動(dòng)。(4)英雄飛機(jī)出場(chǎng)后每隔0.2秒會(huì)自動(dòng)連續(xù)發(fā)射3顆子彈,即單排子彈。子彈的特征和行為具體介紹如下。特征:子彈的速度為12,殺傷力為1。行為:子彈從英雄飛機(jī)的正上方位置發(fā)射,并沿著窗口的垂直方向向上飛行;子彈在被發(fā)射時(shí)需要播放發(fā)射子彈的音效;如果子彈在飛行途中擊中敵機(jī),則它會(huì)對(duì)敵機(jī)造成傷害;如果子彈已經(jīng)飛出窗口且在飛行途中未擊中任何敵機(jī),則它會(huì)被銷毀。11.1游戲簡(jiǎn)介2.英雄飛機(jī)(5)英雄飛機(jī)出場(chǎng)時(shí)默認(rèn)攜帶3個(gè)炸彈,玩家按下“b”鍵可引爆1枚炸彈,此時(shí)炸彈數(shù)量減1。炸彈數(shù)量為0時(shí),無法繼續(xù)使用。(6)英雄飛機(jī)具有多個(gè)動(dòng)畫和音效。當(dāng)英雄飛機(jī)飛行時(shí),顯示飛行動(dòng)畫;當(dāng)英雄飛機(jī)被敵機(jī)撞毀時(shí),顯示被撞毀動(dòng)畫,并播放被撞毀的音效;當(dāng)英雄飛機(jī)升級(jí)時(shí),播放升級(jí)音效。(7)英雄飛機(jī)具有多條生命。英雄飛機(jī)的初始生命為3;英雄飛機(jī)被敵機(jī)撞毀時(shí),生命數(shù)量減1;英雄飛機(jī)得分每增加10萬,生命數(shù)量加1;英雄飛機(jī)的生命數(shù)量歸0時(shí),游戲結(jié)束。游戲窗口的右下方位置會(huì)實(shí)時(shí)顯示英雄飛機(jī)的生命數(shù)量。11.1游戲簡(jiǎn)介3.敵機(jī)敵機(jī)的機(jī)型有小、中、大三種,各機(jī)型均有生命值、速度、分值、圖片和音效等多個(gè)特征,且不同類型的敵機(jī)所具有的特征也不盡相同,后續(xù)在設(shè)計(jì)飛機(jī)類時(shí)會(huì)有詳細(xì)說明。飛機(jī)大戰(zhàn)游戲中的敵機(jī)具有以下行為:(1)敵機(jī)出現(xiàn)在游戲窗口頂部的隨機(jī)位置。(2)敵機(jī)按照各自不同的速度,沿著垂直方向從游戲窗口頂部向下方飛行。(3)若敵機(jī)與英雄飛機(jī)相撞,則會(huì)撞毀英雄飛機(jī)。11.1游戲簡(jiǎn)介3.敵機(jī)(4)若敵機(jī)被子彈擊中,則敵機(jī)的生命值需要減去子彈的傷害值,此時(shí)根據(jù)敵機(jī)的生命值可以分如下兩種情況進(jìn)行處理:如果敵機(jī)的生命值大于0,那么將顯示敵機(jī)被擊中圖片,讓敵機(jī)繼續(xù)向屏幕下方飛行。如果敵機(jī)的生命值等于0,那么播放敵機(jī)被撞毀動(dòng)畫與被撞毀音效。在被撞毀動(dòng)畫播放過程中,該敵機(jī)不會(huì)在屏幕上移動(dòng);在被撞毀動(dòng)畫播放完成后,該敵機(jī)被設(shè)為初始狀態(tài),重新出現(xiàn)在游戲窗口頂部的隨機(jī)位置。(5)若敵機(jī)飛出了游戲窗口且飛行途中沒有被擊毀,該敵機(jī)被設(shè)為初始狀態(tài)。值得一提的是,正在播放被撞毀動(dòng)畫的敵機(jī)屬于已經(jīng)被摧毀的敵機(jī),它既不能被子彈擊中,也不能撞擊英雄飛機(jī)。11.1游戲簡(jiǎn)介4.道具在游戲過程中,道具每隔30秒會(huì)從游戲窗口上方的隨機(jī)位置向下飛出,一旦飛出的過程中碰撞到英雄飛機(jī),就會(huì)被英雄飛機(jī)拾取。飛機(jī)大戰(zhàn)游戲總共有兩種道具:炸彈補(bǔ)給和子彈增強(qiáng),關(guān)于這兩種道具的功能描述如表所示。道具名稱功能描述速度播放音效炸彈補(bǔ)給英雄飛機(jī)拾取后,炸彈數(shù)量加15是子彈增強(qiáng)英雄飛機(jī)拾取后,發(fā)射的子彈由單排改為雙排,且持續(xù)時(shí)長(zhǎng)20秒5是11.1游戲簡(jiǎn)介5.分?jǐn)?shù)當(dāng)英雄飛機(jī)通過子彈或炸彈擊毀敵機(jī)時(shí),會(huì)獲得與敵機(jī)分值相對(duì)應(yīng)的分?jǐn)?shù),并將獲得的分?jǐn)?shù)實(shí)時(shí)地顯示在游戲窗口的左上方位置。同一局游戲的分?jǐn)?shù)會(huì)不斷累加,并在下一局開始時(shí)自動(dòng)清零。系統(tǒng)會(huì)記錄玩家歷次游戲所得到的最高分,并在游戲暫停和結(jié)束時(shí)顯示在游戲窗口上。11.1游戲簡(jiǎn)介6.關(guān)卡設(shè)定飛機(jī)大戰(zhàn)游戲一共設(shè)立了3個(gè)關(guān)卡,依次是關(guān)卡1、關(guān)卡2和關(guān)卡3,其中關(guān)卡1為起始關(guān)卡。在英雄飛機(jī)的得分超過當(dāng)前關(guān)卡的預(yù)設(shè)分值之后,游戲會(huì)自動(dòng)進(jìn)入下一個(gè)關(guān)卡。關(guān)卡越高難度越高,敵機(jī)數(shù)量和種類越多,速度也更快。3個(gè)關(guān)卡的設(shè)定規(guī)則如表所示。關(guān)卡名稱分值范圍小敵機(jī)數(shù)量(速度)中敵機(jī)數(shù)量(速度)大敵機(jī)數(shù)量(速度)關(guān)卡1<1000016(1~3)0(1)0(1)關(guān)卡2<5000024(1~5)2(1)0(1)關(guān)卡3>=5000032(1~7)4(1~3)2(1)11.1游戲簡(jiǎn)介
先定一個(gè)小目標(biāo)!了解飛機(jī)大戰(zhàn)游戲典型場(chǎng)景,能夠復(fù)述出各場(chǎng)景要實(shí)現(xiàn)的功能11.2游戲典型場(chǎng)景11.2游戲典型場(chǎng)景飛機(jī)大戰(zhàn)游戲的典型事件組成了各個(gè)典型場(chǎng)景,除了游戲進(jìn)行中的場(chǎng)景之外,還包括游戲開始、飛機(jī)碰撞、游戲暫停、游戲結(jié)束幾個(gè)場(chǎng)景。1.游戲開始游戲開始的場(chǎng)景如圖所示。11.2游戲典型場(chǎng)景在圖中,游戲窗口下方的中心位置顯示了英雄飛機(jī),英雄飛機(jī)是游戲的主角,它具備移動(dòng)自身位置、發(fā)射子彈、引爆炸彈以及拾取道具等功能;游戲窗口右下角顯示了小飛機(jī)圖像以及文字“×3”,其中數(shù)字3表示英雄飛機(jī)的命數(shù);游戲窗口左下角顯示了炸彈圖像及文字“×3”,其中數(shù)字3表示英雄飛機(jī)擁有的炸彈數(shù)量;游戲窗口左上角顯示了游戲狀態(tài)圖像(暫停)和英雄飛機(jī)的當(dāng)前得分(0)。需要說明的是,在圖中,除了英雄飛機(jī)和背景這兩個(gè)元素之外,其他元素的位置都是固定的,但顯示的圖像或者數(shù)字在游戲過程中會(huì)發(fā)生改變。2.飛機(jī)碰撞英雄飛機(jī)與敵機(jī)發(fā)生碰撞后被撞毀的某個(gè)場(chǎng)景如圖所示。11.2游戲典型場(chǎng)景如果英雄飛機(jī)與敵機(jī)發(fā)生碰撞,那么它們各自都需要做一些處理,具體如下。(1)英雄飛機(jī)發(fā)生碰撞的英雄飛機(jī)會(huì)被撞毀,并播放被撞毀動(dòng)畫以及被撞毀音效。被撞毀動(dòng)畫播放過程中,玩家無法操作英雄飛機(jī);被撞毀動(dòng)畫播放完成后,英雄飛機(jī)的生命數(shù)量減少1。若英雄飛機(jī)的生命數(shù)量減少1之后還有剩余命數(shù),則在英雄飛機(jī)被撞毀的位置出現(xiàn)一個(gè)新的英雄飛機(jī),并由玩家操控新的英雄飛機(jī)繼續(xù)戰(zhàn)斗;若英雄飛機(jī)沒有剩余命數(shù),則游戲結(jié)束。2.飛機(jī)碰撞英雄飛機(jī)與敵機(jī)發(fā)生碰撞后被撞毀的某個(gè)場(chǎng)景如圖所示。11.2游戲典型場(chǎng)景如果英雄飛機(jī)與敵機(jī)發(fā)生碰撞,那么它們各自都需要做一些處理,具體如下。(2)敵機(jī)撞毀英雄飛機(jī)的敵機(jī)需要播放被撞毀動(dòng)畫及被撞毀音效。被撞毀動(dòng)畫播放過程中,敵機(jī)顯示在游戲窗口的位置不會(huì)移動(dòng);被撞毀動(dòng)畫播放完成后,敵機(jī)會(huì)被設(shè)置為初始狀態(tài),從屏幕頂部任意位置沿著垂直方向向下飛行。3.游戲暫停玩家按下空格鍵可以暫停游戲,再次按下空格鍵可以恢復(fù)游戲。游戲暫停的某個(gè)場(chǎng)景如圖所示。11.2游戲典型場(chǎng)景當(dāng)游戲暫停時(shí),整個(gè)游戲畫面靜止,背景音樂停止播放,游戲狀態(tài)圖像會(huì)切換為運(yùn)行圖像,并在窗口中央偏上的位置顯示“GamePaused!”的文字,在“GamePaused!”文字下方顯示最高得分,在最高得分下方顯示“Pressspacebartocontinue.”,提示玩家按下空格鍵可以繼續(xù)游戲。當(dāng)玩家再次按下空格鍵以恢復(fù)游戲時(shí),整個(gè)游戲畫面恢復(fù)正常,并繼續(xù)播放背景音樂。游戲狀態(tài)圖像切換回暫停圖像,而窗口中央位置的提示文字全部被隱藏起來。4.游戲結(jié)束英雄飛機(jī)被敵機(jī)撞毀后若沒有剩余命數(shù)繼續(xù)戰(zhàn)斗,則游戲結(jié)束。在英雄飛機(jī)被撞毀的動(dòng)畫播放完成之后,整個(gè)游戲畫面靜止。游戲結(jié)束的某個(gè)場(chǎng)景如圖所示。11.2游戲典型場(chǎng)景游戲窗口中央由上至下依次顯示了游戲結(jié)束的提示文字“GameOver!”,最好成績(jī)的提示文字“Best:2185000”,以及再來一局的提示文字“Pressspacebartoplayagain.”。玩家按下空格鍵即可重新開始一局游戲。項(xiàng)目準(zhǔn)備11.2
先定一個(gè)小目標(biāo)!11.2.1類設(shè)計(jì)熟悉項(xiàng)目的準(zhǔn)備工作,能夠獨(dú)立設(shè)計(jì)游戲的類11.2.1類設(shè)計(jì)根據(jù)之前對(duì)游戲的介紹,我們可以看到飛機(jī)大戰(zhàn)游戲包含許多游戲元素,如英雄飛機(jī)、敵機(jī)、道具、子彈、游戲狀態(tài)文本、背景音樂和音效等。這些元素都可以通過類進(jìn)行構(gòu)建,但目前它們分散且缺乏統(tǒng)一的管理。為了方便統(tǒng)一管理這些游戲元素,我們根據(jù)它們的職責(zé)進(jìn)行了分類。游戲元素的分類及說明如表所示。分類類名說明游戲類Game負(fù)責(zé)整個(gè)游戲的運(yùn)行流程指示器面板類HUBPanel負(fù)責(zé)統(tǒng)一管理游戲狀態(tài)、游戲分?jǐn)?shù)、炸彈數(shù)量、生命數(shù)量,以及文本提示等與游戲數(shù)據(jù)或狀態(tài)相關(guān)的內(nèi)容音樂播放類MusicPlayer負(fù)責(zé)背景音樂和音效的播放游戲背景類Background負(fù)責(zé)顯示游戲的背景圖像狀態(tài)按鈕類StatusButton負(fù)責(zé)顯示游戲的狀態(tài)按鈕飛機(jī)類Plane表示游戲中的飛機(jī),包括英雄飛機(jī)和敵機(jī)子彈類Bullet表示英雄飛機(jī)發(fā)射的子彈道具類Supply負(fù)責(zé)管理炸彈補(bǔ)給和子彈增強(qiáng)道具文本標(biāo)簽類Label負(fù)責(zé)顯示游戲窗口上的文本11.2.1類設(shè)計(jì)游戲元素的分類及說明表中前三個(gè)分類負(fù)責(zé)管理游戲中獨(dú)立的功能,它們可以直接繼承基類object;剩余幾個(gè)分類中涉及的游戲元素都是顯示于窗口的圖像,這些元素可以繼承pygame.Sprite類,用于統(tǒng)一組織和管理游戲元素,具體說明如下:(1)游戲背景類、狀態(tài)按鈕類、飛機(jī)類、子彈類、道具類負(fù)責(zé)顯示的元素都會(huì)發(fā)生動(dòng)態(tài)的變化,它們的共同特征或行為可以抽取成一個(gè)游戲元素基類GameSprite,該基類繼承pygame.Sprite類。(2)飛機(jī)類表示游戲中的飛機(jī),包括英雄飛機(jī)和敵機(jī),這兩種類型的飛機(jī)各自具有獨(dú)特的特征和行為,因此可以將Plane類派生兩個(gè)子類:Hero和Enemy,分別表示游戲中的英雄飛機(jī)和敵機(jī)。11.2.1類設(shè)計(jì)10.2.1模塊的構(gòu)建與使用飛機(jī)大戰(zhàn)游戲項(xiàng)目中提煉出的類及類之間的繼承關(guān)系如圖所示。
先定一個(gè)小目標(biāo)!11.2.2模塊設(shè)計(jì)熟悉項(xiàng)目的準(zhǔn)備工作,能夠獨(dú)立設(shè)計(jì)游戲的模塊在設(shè)計(jì)程序時(shí),我們既要考慮程序的設(shè)計(jì)理念和設(shè)計(jì)思想,又要考慮程序的結(jié)構(gòu)。結(jié)構(gòu)設(shè)計(jì)的原則是代碼模塊化,以便于擴(kuò)展和維護(hù)。為此,我們將飛機(jī)大戰(zhàn)游戲項(xiàng)目劃分為四個(gè)模塊:game.py、game_items.py、game_hud.py和game_music.py,每個(gè)模塊的功能和說明如表所示。11.2.2模塊設(shè)計(jì)模塊說明game.py游戲主模塊,封裝Game類并負(fù)責(zé)啟動(dòng)游戲game_items.py游戲元素模塊,封裝英雄飛機(jī)、子彈、敵機(jī)、道具等游戲元素類,并定義全局變量game_hud.py游戲面板模塊,封裝指示器面板類game_music.py游戲音樂模塊,封裝音樂播放器類
先定一個(gè)小目標(biāo)!掌握游戲項(xiàng)目的創(chuàng)建,能夠在PyCharm工具中創(chuàng)建飛機(jī)大戰(zhàn)項(xiàng)目11.2.3創(chuàng)建項(xiàng)目打開PyCharm工具,在該工具中新建一個(gè)名稱為“飛機(jī)大戰(zhàn)”的項(xiàng)目。在飛機(jī)大戰(zhàn)項(xiàng)目中依次創(chuàng)建game.py、game_items.py、game_hud.py和game_music.py四個(gè)文件,之后將資源文件夾res復(fù)制到飛機(jī)大戰(zhàn)項(xiàng)目的目錄下。創(chuàng)建好的項(xiàng)目文件結(jié)構(gòu)如圖所示。11.2.3創(chuàng)建項(xiàng)目res目錄包含3個(gè)子目錄:font、images和sound,這3個(gè)子目錄分別放置了飛機(jī)大戰(zhàn)游戲使用的字體、圖片和聲音素材。游戲框架搭建11.3
先定一個(gè)小目標(biāo)!11.3.1游戲類的設(shè)計(jì)掌握游戲類的設(shè)計(jì),能夠根據(jù)案例需求設(shè)計(jì)游戲類游戲類負(fù)責(zé)控制整個(gè)游戲的運(yùn)行流程,它需要包含游戲中的主要元素。Game類的類圖如圖所示。11.3.1游戲類的設(shè)計(jì)1.Game類的屬性Game類的屬性可以分為游戲?qū)傩院途`組屬性。精靈表示顯示圖像的對(duì)象,游戲窗口中看到的每個(gè)單獨(dú)圖像或者一行文字都可以看作一個(gè)精靈,例如,英雄飛機(jī)、一顆子彈、分?jǐn)?shù)標(biāo)簽等。(1)游戲?qū)傩訥ame類中定義的游戲?qū)傩灾饕?個(gè),這些屬性的說明如表所示。11.3.1游戲類的設(shè)計(jì)屬性說明main_window游戲主窗口,初始大小為(480,700)is_game_over游戲結(jié)束標(biāo)記,初始值為False,表示游戲未結(jié)束is_pause游戲暫停標(biāo)記,初始值為False,表示游戲未暫停hero英雄精靈,最初顯示在游戲窗口中央靠下位置hud_panel指示器面板,負(fù)責(zé)顯示與游戲狀態(tài)以及數(shù)據(jù)相關(guān)的內(nèi)容,包括狀態(tài)圖像、游戲得分、炸彈數(shù)量、英雄飛機(jī)的命數(shù),以及游戲暫停或結(jié)束時(shí)顯示在游戲窗口中央位置的提示信息等player音樂播放器,負(fù)責(zé)播放背景音樂和游戲音效(2)精靈組屬性精靈組就是保存了多個(gè)精靈對(duì)象的組,支持將多個(gè)精靈對(duì)象進(jìn)行分組,并對(duì)組內(nèi)的精靈對(duì)象一起進(jìn)行操作和處理。Pygame的精靈組常用于以下重要的場(chǎng)景。一次性繪制或者更新多個(gè)精靈。碰撞檢測(cè)。碰撞檢測(cè)就是檢測(cè)多個(gè)精靈之間是否發(fā)生碰撞,例如,子彈是否擊中敵機(jī)、敵機(jī)是否撞到英雄飛機(jī)等。Game類中定義的精靈組屬性總共有3個(gè),這些屬性的說明如表所示。11.3.1游戲類的設(shè)計(jì)屬性說明all_group所有精靈組,存放所有要顯示的精靈,用于屏幕繪制和更新位置enemies_group敵機(jī)精靈組,存放所有敵機(jī)精靈對(duì)象,用于檢測(cè)子彈擊中敵機(jī)以及敵機(jī)撞到英雄飛機(jī)supplies_group道具精靈組,存放所有道具精靈對(duì)象,用于檢測(cè)英雄飛機(jī)拾取道具2.Game類的方法Game類封裝了多個(gè)方法,分別用于創(chuàng)建游戲元素、管理游戲的流程、監(jiān)聽系統(tǒng)事件等。Game類中定義的方法如表所示。11.3.1游戲類的設(shè)計(jì)方法說明reset_game()重置游戲。在開啟新一輪游戲前,將游戲?qū)傩曰謴?fù)到初始狀態(tài)create_enemies()創(chuàng)建敵機(jī)精靈。在新游戲開始或者關(guān)卡晉級(jí)后,根據(jù)當(dāng)前游戲級(jí)別創(chuàng)建敵機(jī)精靈create_supplies()創(chuàng)建道具。游戲開始后每隔30秒隨機(jī)投放炸彈補(bǔ)給或子彈增強(qiáng)道具start()開始游戲。創(chuàng)建時(shí)鐘對(duì)象并且開啟游戲循環(huán),在游戲循環(huán)中監(jiān)聽事件、更新精靈位置、繪制精靈、更新顯示、設(shè)置刷新幀率event_handler()事件監(jiān)聽。監(jiān)聽并處理每一次游戲循環(huán)執(zhí)行時(shí)發(fā)生的事件,避免游戲循環(huán)中的代碼過長(zhǎng)check_collide()碰撞檢測(cè)。監(jiān)聽并處理每一次游戲循環(huán)執(zhí)行時(shí)是否發(fā)生精靈與精靈之間的碰撞,例如,子彈擊中敵機(jī)、英雄飛機(jī)拾取道具、敵機(jī)撞擊英雄飛機(jī)等
先定一個(gè)小目標(biāo)!11.3.2游戲框架實(shí)現(xiàn)掌握游戲框架的搭建方式,能夠獨(dú)立搭建游戲的框架1.定義游戲窗口尺寸的全局變量在game_items模塊中,定義一個(gè)表示游戲窗口尺寸的全局變量SCREEN_RECT,全局變量的值是使用Rect類創(chuàng)建的矩形對(duì)象,矩形對(duì)象的寬度和高度分別為480和700像素,具體代碼如下:11.3.2游戲框架實(shí)現(xiàn)importpygame#游戲窗口區(qū)域SCREEN_RECT=pygame.Rect(0,0,480,700)2.實(shí)現(xiàn)Game類的基礎(chǔ)代碼在game模塊中定義Game類,并實(shí)現(xiàn)構(gòu)造方法和重設(shè)游戲方法,具體代碼如下:11.3.2游戲框架實(shí)現(xiàn)classGame(object):def__init__(self):#游戲主窗口
self.main_window=pygame.display.set_mode(SCREEN_RECT.size)pygame.display.set_caption("飛機(jī)大戰(zhàn)")self.is_game_over=False#游戲結(jié)束標(biāo)記
self.is_pause=False#游戲暫停標(biāo)記
defreset_game(self):"""重設(shè)游戲"""self.is_game_over=False#游戲結(jié)束標(biāo)記
self.is_pause=False#游戲暫停標(biāo)記2.實(shí)現(xiàn)Game類的基礎(chǔ)代碼在Game類中定義event_handler()方法,event_handler()方法用于監(jiān)聽游戲循環(huán)中發(fā)生的事件,若監(jiān)聽到退出事件,則返回True,否則返回False,具體代碼如下:11.3.2游戲框架實(shí)現(xiàn)defevent_handler(self):foreventinpygame.event.get():ifevent.type==pygame.QUIT:#退出程序
returnTrueelifevent.type==pygame.KEYDOWNand\event.key==pygame.K_ESCAPE:#按下Esc鍵
returnTruereturnFalse2.實(shí)現(xiàn)Game類的基礎(chǔ)代碼在Game類中定義start()方法。start()方法用于開始游戲,該方法中首先會(huì)創(chuàng)建游戲時(shí)鐘,再開啟游戲循環(huán),代碼如下:11.3.2游戲框架實(shí)現(xiàn)defstart(self):"""開始游戲"""clock=pygame.time.Clock()#游戲時(shí)鐘
whileTrue:ifself.event_handler():#事件監(jiān)聽
returnpygame.display.update()#更新顯示
clock.tick(60)#設(shè)置刷新幀率3.在主模塊中啟動(dòng)游戲在game模塊的末尾增加以下代碼,創(chuàng)建游戲?qū)ο蟛⑶覇?dòng)游戲,具體代碼如下:11.3.2游戲框架實(shí)現(xiàn)if__name__=='__main__':pygame.init()Game().start()pygame.quit()4.使用空格鍵切換游戲狀態(tài)調(diào)整event_handler()方法。在事件監(jiān)聽的循環(huán)體中,增加對(duì)空格鍵按鍵事件的監(jiān)聽,并在監(jiān)聽到空格鍵按下的事件時(shí)切換游戲狀態(tài),具體代碼如下:11.3.2游戲框架實(shí)現(xiàn)elifevent.type==pygame.KEYDOWNandevent.key==pygame.K_SPACE:ifself.is_game_over:#游戲已經(jīng)結(jié)束
self.reset_game()else:#切換暫停狀態(tài)
self.is_pause=notself.is_pause4.使用空格鍵切換游戲狀態(tài)在游戲循環(huán)語句中增加判斷游戲狀態(tài)的邏輯代碼:若游戲已經(jīng)結(jié)束,則輸出游戲結(jié)束狀態(tài)的提示文字;若游戲暫停,則輸出游戲暫停狀態(tài)的提示文字;若游戲正在進(jìn)行中,則輸出游戲狀態(tài)的提示文字。11.3.2游戲框架實(shí)現(xiàn)defstart(self):clock=pygame.time.Clock()#游戲時(shí)鐘
whileTrue:ifself.event_handler():#事件監(jiān)聽
Returnifself.is_game_over:#判斷游戲狀態(tài)print("游戲已經(jīng)結(jié)束,按空格鍵重新開始...")elifself.is_pause:print("游戲已經(jīng)暫停,按空格鍵繼續(xù)...")else:print("游戲進(jìn)行中...")pygame.display.update()#更新顯示
clock.tick(60)#設(shè)置刷新幀率如果想要測(cè)試游戲結(jié)束后使用空格鍵重新開始游戲的功能,可以通過將構(gòu)造方法中is_game_over屬性的值暫時(shí)設(shè)置為True,再進(jìn)行測(cè)試。注意,測(cè)試結(jié)束后應(yīng)將is_game_over屬性的值設(shè)置為False。11.3.2游戲框架實(shí)現(xiàn)游戲背景和英雄飛機(jī)11.4
先定一個(gè)小目標(biāo)!11.4.1介紹精靈和精靈組熟悉精靈和精靈組,能夠歸納精靈和精靈組的作用飛機(jī)大戰(zhàn)項(xiàng)目中需要管理多種游戲?qū)ο?,如敵機(jī)、英雄飛機(jī)和子彈。此外,還需要實(shí)現(xiàn)許多動(dòng)畫效果,如英雄飛機(jī)的飛行動(dòng)畫和飛機(jī)的碰撞動(dòng)畫等等。為了保證游戲?qū)ο蟮娘@示和動(dòng)畫效果,我們可以使用精靈和精靈組管理它們。11.4.1介紹精靈和精靈組Pygame專門提供了兩個(gè)類:Sprite和Group,分別表示精靈和精靈組,其中精靈是指游戲中顯示圖像的對(duì)象,比如英雄飛機(jī)、敵機(jī)、子彈等;精靈組是保存和管理一組精靈對(duì)象的容器。通過添加精靈對(duì)象到組中,可以實(shí)現(xiàn)一次性對(duì)組中所有精靈對(duì)象進(jìn)行操作,例如更新、繪制、碰撞檢測(cè)等。11.4.1介紹精靈和精靈組1.Sprite類Sprite用于創(chuàng)建游戲中精靈對(duì)象的基類,該類提供了一些屬性和方法操作或管理精靈對(duì)象。常用屬性和方法如表所示。11.4.1介紹精靈和精靈組類型名稱說明屬性imageimage屬性用于存儲(chǔ)精靈對(duì)象的圖像內(nèi)容。這個(gè)圖像可以是從磁盤上加載的圖片,也可以是通過字體渲染出的文本內(nèi)容。注意,Sprite的子類中必須手動(dòng)設(shè)置image屬性rect表示精靈對(duì)象在游戲窗口的矩形區(qū)域。注意,Sprite的子類中必須手動(dòng)設(shè)置rect屬性方法update(*args,**kwargs)用于更新精靈對(duì)象的狀態(tài)和屬性。默認(rèn)情況下,此方法不執(zhí)行任何操作。子類可以重寫update()方法實(shí)現(xiàn)自定義的更新邏輯,例如改變精靈的位置或顯示內(nèi)容add(*groups)將精靈添加到指定的精靈組中remove(*groups)將精靈從指定的精靈組中移除kill()將精靈從所有精靈組中移除并銷毀2.Group類Group是一個(gè)包含多個(gè)精靈的容器類,該類中提供了一些管理精靈的常用方法,關(guān)于這些常用方法的說明如表所示。游戲中精靈對(duì)象的基類,該類提供了一些屬性和方法操作或管理精靈對(duì)象。常用屬性和方法如表所示。11.4.1介紹精靈和精靈組名稱說明update(*args,**kwargs)更新組內(nèi)所有精靈的狀態(tài),如位置或顯示內(nèi)容等draw(surface)在指定表面上一次繪制組內(nèi)的所有精靈對(duì)象sprites()返回精靈組中所有精靈的列表add(*sprites)向精靈組中添加一個(gè)或多個(gè)精靈remove(*sprites)從精靈組中移除一個(gè)或多個(gè)精靈empty()清空精靈組中所有的精靈
先定一個(gè)小目標(biāo)!11.4.2派生游戲精靈子類熟悉派生游戲精靈子類,能夠歸納派生游戲精靈子類的使用根據(jù)Pygame官方文檔的建議,我們應(yīng)該在實(shí)際開發(fā)中使用派生自Sprite類的子類,而不是直接使用Sprite類。以下是關(guān)于派生自Sprite類的子類的注意事項(xiàng),具體內(nèi)容如下:子類可以重寫update()方法。子類必須為image和rect屬性賦值。子類的構(gòu)造方法可以接收任意數(shù)量的精靈組對(duì)象,以將創(chuàng)建完成的精靈對(duì)象添加到指定的精靈組中。子類的構(gòu)造方法中必須調(diào)用父類的構(gòu)造方法,這樣才能向精靈組中添加精靈。11.4.2派生游戲精靈子類在game_items模塊中定義派生自Sprite的子類GameSprite,GameSprite類的類圖如圖所示。11.4.2派生游戲精靈子類定義GameSprite類,具體代碼如下:11.4.2派生游戲精靈子類classGameSprite(pygame.sprite.Sprite):"""游戲精靈類"""res_path="./res/images/"#圖片資源路徑
def__init__(self,image_name,speed,*groups):super().__init__(*groups)#圖像
self.image=pygame.image.load(self.res_path+image_name)self.rect=self.image.get_rect()#矩形區(qū)域,默認(rèn)在左上角
self.speed=speed#移動(dòng)速度
defupdate(self,*args):self.rect.y+=self.speed
先定一個(gè)小目標(biāo)!11.4.3繪制游戲背景和英雄飛機(jī)掌握繪制游戲背景和英雄飛機(jī),能夠?qū)崿F(xiàn)繪制飛機(jī)大戰(zhàn)的游戲背景和英雄飛機(jī)按照Game類的類圖,在Game類的構(gòu)造方法中創(chuàng)建3個(gè)精靈組,并且創(chuàng)建背景精靈和英雄精靈,代碼如下。#精靈組屬性self.all_group=pygame.sprite.Group()#所有精靈組self.enemies_group=pygame.sprite.Group()#敵機(jī)精靈組self.supplies_group=pygame.sprite.Group()#道具精靈組#創(chuàng)建精靈#背景精靈,向下方移動(dòng)GameSprite("background.png",1,self.all_group)#英雄精靈,靜止不動(dòng)hero=GameSprite("me1.png",0,self.all_group)hero.rect.center=SCREEN_RECT.center#顯示在屏幕中央11.4.3繪制游戲背景和英雄飛機(jī)在判斷游戲狀態(tài)之后、更新顯示之前增加負(fù)責(zé)繪制和更新所有精靈的代碼,修改后的代碼如下:defstart(self):……#判斷游戲狀態(tài)
ifself.is_game_over:print("游戲已經(jīng)結(jié)束,按空格鍵重新開始...")elifself.is_pause:print("游戲已經(jīng)暫停,按空格鍵繼續(xù)...")else:self.all_group.update()#更新all_group中所有精靈內(nèi)容self.all_group.draw(self.main_window)#繪制all_group中的所有精靈pygame.display.update()#更新顯示
clock.tick(60)#設(shè)置刷新幀率11.4.3繪制游戲背景和英雄飛機(jī)運(yùn)行游戲,可以在游戲窗口中看到緩緩向下移動(dòng)的星空背景和英雄飛機(jī),如圖所示。11.4.3繪制游戲背景和英雄飛機(jī)
先定一個(gè)小目標(biāo)!11.4.4實(shí)現(xiàn)游戲背景連續(xù)滾動(dòng)掌握游戲背景連續(xù)滾動(dòng),能夠?qū)崿F(xiàn)在飛機(jī)大戰(zhàn)中實(shí)現(xiàn)游戲背景連續(xù)滾動(dòng)11.4.4實(shí)現(xiàn)游戲背景連續(xù)滾動(dòng)當(dāng)我們運(yùn)行上個(gè)小節(jié)實(shí)現(xiàn)的程序時(shí),注意到游戲剛啟動(dòng)時(shí),背景圖像填滿了整個(gè)游戲窗口。但是隨著背景圖像緩慢向下移動(dòng),游戲窗口上方會(huì)逐漸出現(xiàn)一個(gè)越來越大的灰色無圖區(qū)域。那么,如何實(shí)現(xiàn)背景圖像的連續(xù)滾動(dòng)效果呢?解決方法是使用兩個(gè)背景精靈:背景精靈1和背景精靈2。使用這兩個(gè)背景精靈實(shí)現(xiàn)背景圖像連續(xù)滾動(dòng)的原理圖,具體如圖所示。11.4.4實(shí)現(xiàn)游戲背景連續(xù)滾動(dòng)11.4.4實(shí)現(xiàn)游戲背景連續(xù)滾動(dòng)使用兩個(gè)背景精靈實(shí)現(xiàn)背景圖像連續(xù)滾動(dòng)的原理,連續(xù)滾動(dòng)的完整過程可以拆分成以下步驟:(1)背景精靈1與窗口重合;背景精靈2放在窗口的正上方,與背景精靈1連接。(2)兩個(gè)背景精靈同時(shí)向下移動(dòng)。(3)當(dāng)背景精靈1移出窗口底部時(shí),背景精靈2正好完全顯示在窗口上。(4)背景精靈1立即移動(dòng)到窗口的上方,與背景精靈2連接。(5)兩個(gè)背景精靈繼續(xù)同時(shí)向下移動(dòng),回到步驟(2)。11.4.4實(shí)現(xiàn)游戲背景連續(xù)滾動(dòng)在代碼實(shí)現(xiàn)時(shí),可以通過檢查背景精靈的y值是否大于等于窗口的h值來判斷背景精靈是否移出窗口的底部。如果背景精靈已經(jīng)移出窗口,則可以將背景精靈的y值設(shè)置為其高度的負(fù)值,將其從窗口下方移動(dòng)到窗口的上方。理解了背景圖像連續(xù)滾動(dòng)的實(shí)現(xiàn)原理之后,根據(jù)背景圖像的特征和行為設(shè)計(jì)背景精靈類Background。Background類的類圖如圖所示。11.4.4實(shí)現(xiàn)游戲背景連續(xù)滾動(dòng)11.4.4實(shí)現(xiàn)游戲背景連續(xù)滾動(dòng)由Background類的類圖可知,背景精靈類繼承自GameSprite,并且包含重寫的構(gòu)造方法__init__()和update()方法。__init__()方法中有一個(gè)參數(shù)is_alt,用于區(qū)別兩個(gè)背景精靈:若is_alt的值為False,表示第一個(gè)背景精靈的初始矩形區(qū)域應(yīng)該與游戲窗口重疊;若is_alt的值為True,表示另一個(gè)背景精靈的初始矩形區(qū)域應(yīng)該在游戲窗口的正上方。11.4.4實(shí)現(xiàn)游戲背景連續(xù)滾動(dòng)Background類中之所以要重寫update()方法,是因?yàn)樾枰袛鄨D像是否已經(jīng)移出游戲窗口。一旦檢測(cè)到圖像已經(jīng)移出游戲窗口,就需要將背景精靈重新定位到游戲窗口正上方,以實(shí)現(xiàn)連續(xù)滾動(dòng)的效果。在game_items文件中,添加BackGround類的定義,具體代碼如下:classBackground(GameSprite):"""背景精靈類"""def__init__(self,is_alt,*groups):#調(diào)用父類方法實(shí)現(xiàn)精靈的創(chuàng)建
super().__init__("background.png",1,*groups)ifis_alt:#判斷是否是另一個(gè)精靈,如果是則需要設(shè)置初始位置
self.rect.y=-self.rect.h#將圖像設(shè)置到窗口上方
defupdate(self,*args):#調(diào)用父類的方法實(shí)現(xiàn)向下移動(dòng)的效果
super().update(*args)#向下移動(dòng)
#判斷是否移出窗口,如果移出窗口,將圖像設(shè)置到窗口上方
ifself.rect.y>=self.rect.h:self.rect.y=-self.rect.h11.4.4實(shí)現(xiàn)游戲背景連續(xù)滾動(dòng)修改Game類中創(chuàng)建背景精靈的代碼,創(chuàng)建兩個(gè)背景精靈并將它們?nèi)刻砑拥骄`組中,具體代碼如下:def__init__(self):#游戲主窗口
self.main_window=pygame.display.set_mode(SCREEN_RECT.size)pygame.display.set_caption("飛機(jī)大戰(zhàn)")……#背景精靈,交替位置實(shí)現(xiàn)連續(xù)滾動(dòng)
self.all_group.add(Background(False),Background(True))11.4.4實(shí)現(xiàn)游戲背景連續(xù)滾動(dòng)運(yùn)行游戲,可以看到背景圖像持續(xù)向窗口下方移動(dòng),沒有出現(xiàn)無背景圖像的情況,如圖所示。11.4.4實(shí)現(xiàn)游戲背景連續(xù)滾動(dòng)指示器面板11.5
先定一個(gè)小目標(biāo)!11.5.1指示器面板類的設(shè)計(jì)熟悉精靈和精靈組,能夠歸納精靈和精靈組的作用11.5.1指示器面板類的設(shè)計(jì)指示器面板又稱HUD(平視顯示器,全稱為HeadUpDisplay),是航空器上的飛行輔助儀器。在游戲開發(fā)中,我們借鑒了指示器面板概念,以類似的方式將游戲相關(guān)信息顯示在游戲畫面上,使玩家能夠隨時(shí)了解最重要、最直接的游戲信息。在飛機(jī)大戰(zhàn)游戲中,指示器面板負(fù)責(zé)顯示與游戲狀態(tài)和數(shù)據(jù)相關(guān)的內(nèi)容,包括狀態(tài)圖像、游戲得分、炸彈圖像、炸彈數(shù)量、英雄命數(shù)等,同時(shí)還會(huì)在游戲暫停或結(jié)束時(shí)在游戲窗口中央顯示相應(yīng)的提示信息。指示器面板類HudPanel的類圖如圖所示。11.5.1指示器面板類的設(shè)計(jì)1.HudPanel的屬性HudPanel類的屬性可以分為游戲數(shù)據(jù)屬性和精靈屬性,其中游戲數(shù)據(jù)屬性是一些指示器面板中變化的數(shù)據(jù);精靈屬性是一些指示器面板中顯示圖像的精靈,關(guān)于它們的介紹如下。(1)游戲數(shù)據(jù)屬性HudPanel類中封裝了4個(gè)與游戲數(shù)據(jù)相關(guān)的屬性,關(guān)于這些屬性的說明如表所示。11.5.1指示器面板類的設(shè)計(jì)屬性說明score游戲得分,初始值為0lives_count生命計(jì)數(shù),即英雄飛機(jī)的命數(shù),初始值為3level游戲級(jí)別,初始值為1best_score最好成績(jī),保存在record.txt文件中HudPanel類中封裝了3個(gè)圖像精靈和6個(gè)標(biāo)簽精靈屬性,關(guān)于這些精靈屬性的說明如表所示。11.5.1指示器面板類的設(shè)計(jì)屬性說明status_sprite狀態(tài)精靈,顯示在游戲窗口左上角bomb_sprite炸彈精靈,顯示在游戲窗口左下角lives_sprite生命計(jì)數(shù)精靈,顯示在游戲窗口右下角score_label得分標(biāo)簽,顯示在狀態(tài)精靈的右側(cè)bomb_label炸彈計(jì)數(shù)標(biāo)簽,顯示在炸彈精靈的右側(cè)lives_label生命計(jì)數(shù)標(biāo)簽,顯示在生命計(jì)數(shù)精靈的右側(cè)best_label最好成績(jī)標(biāo)簽,顯示在游戲窗口中央status_label狀態(tài)標(biāo)簽,顯示在最好成績(jī)標(biāo)簽上方,標(biāo)簽的文字內(nèi)容為GameOver!或者GamePaused!tip_label提示標(biāo)簽,顯示在最好成績(jī)標(biāo)簽下方,游戲暫?;蛘呓Y(jié)束時(shí)的文字內(nèi)容分別為“Pressspacebartocontinue.”或“Pressspacebartoplayagain.”需要注意的是,HudPanel類的職責(zé)僅限于游戲數(shù)據(jù)的維護(hù)和指示器面板相關(guān)精靈的創(chuàng)建,而精靈的繪制和更新操作則主要在游戲循環(huán)中進(jìn)行。為此,可以考慮在HudPanel類的構(gòu)造方法中添加一個(gè)display_group參數(shù),通過該參數(shù)傳遞負(fù)責(zé)更新和繪制的精靈組對(duì)象。這樣,在創(chuàng)建HudPanel類的對(duì)象時(shí),可以將創(chuàng)建好的精靈添加到精靈組中,并在游戲循環(huán)中進(jìn)行統(tǒng)一的繪制和更新操作。11.5.1指示器面板類的設(shè)計(jì)2.HudPanel類的方法HudPanel類中封裝了眾多負(fù)責(zé)顯示和更新數(shù)據(jù)、游戲狀態(tài)的方法,關(guān)于這些方法的說明如表所示。11.5.1指示器面板類的設(shè)計(jì)方法說明reset_panel()重置面板數(shù)據(jù)。開啟新一輪游戲之前,將游戲數(shù)據(jù)屬性恢復(fù)為初始值show_bomb()顯示炸彈數(shù)量。根據(jù)傳入的炸彈數(shù)量,更改炸彈計(jì)數(shù)標(biāo)簽顯示show_lives()顯示生命計(jì)數(shù)。使用英雄命數(shù)更新生命計(jì)數(shù)標(biāo)簽顯示increase_score()增加分?jǐn)?shù)。根據(jù)消滅的敵機(jī)分值增加游戲得分、計(jì)算是否獎(jiǎng)勵(lì)生命、調(diào)整最好成績(jī)以及計(jì)算游戲級(jí)別,并且更改分?jǐn)?shù)標(biāo)簽顯示load_best_score()加載最好成績(jī)。從record.txt文件中加載最好成績(jī)save_best_socre()保存最好成績(jī)。將最好成績(jī)保存到record.txt文件中panel_paused()面板暫停。當(dāng)游戲暫?;蚪Y(jié)束時(shí),在游戲窗口中央位置顯示游戲暫?;蚪Y(jié)束的提示信息panel_resume()面板恢復(fù)。當(dāng)游戲運(yùn)行時(shí),隱藏游戲窗口中央位置的提示信息
先定一個(gè)小目標(biāo)!11.5.2指示器面板類的準(zhǔn)備掌握指示器面板類的準(zhǔn)備,能夠定義指示器面板類、設(shè)計(jì)狀態(tài)按鈕類以及創(chuàng)建圖像精靈11.5.2指示器面板類的準(zhǔn)備指示器面板類的準(zhǔn)備工作,包括定義指示器面板類、設(shè)計(jì)狀態(tài)按鈕類以及創(chuàng)建圖像精靈,具體內(nèi)容如下。1.定義指示器面板類在game_hud模塊中定義HudPanel類,并在該類的構(gòu)造方法中添加游戲?qū)傩裕唧w代碼如下:importpygamefromgame_itemsimport*classHUDPanel:"""指示器面板類"""def__init__(self,display_group):#游戲?qū)傩?/p>
self.score=0游戲得分
self.lives_count=3#生命計(jì)數(shù)
self.level=1#游戲級(jí)別
self.best_score=0#最好成績(jī)HUDPanel類本身并不是一個(gè)精靈,它只是一個(gè)負(fù)責(zé)管理游戲數(shù)據(jù)以及多個(gè)精靈的面板。11.5.2指示器面板類的準(zhǔn)備2.設(shè)計(jì)狀態(tài)按鈕類根據(jù)游戲介紹,當(dāng)玩家按下空格鍵暫停或繼續(xù)游戲時(shí),游戲窗口左上角的狀態(tài)精靈會(huì)根據(jù)操作發(fā)生相應(yīng)的變化。為了方便后續(xù)的代碼編寫,可以從GameSprite類派生一個(gè)子類StatusButton類,通過StatusButton類來處理狀態(tài)圖像的切換操作。StatusButton類的類圖如圖所示。11.5.2指示器面板類的準(zhǔn)備在game_items模塊中定義一個(gè)繼承GameSprite類的子類StatusButton類,具體代碼如下:classStatusButton(GameSprite):"""狀態(tài)按鈕類"""def__init__(self,image_names,*groups):super().__init__(image_names[0],0,*groups)#加載圖像
self.images=[pygame.image.load(self.res_path+name)fornameinimage_names]defswitch_status(self,is_pause):self.image=self.images[1ifis_pauseelse0]11.5.2指示器面板類的準(zhǔn)備3.創(chuàng)建圖像精靈在HUDPanel類的構(gòu)造方法中創(chuàng)建指示器面板中的圖像精靈,包括左上角的狀態(tài)精靈(暫?;蚶^續(xù)圖像)、左下角的炸彈精靈(炸彈圖像),以及右下角的生命計(jì)數(shù)精靈(小飛機(jī)圖像),具體步驟如下。首先,在HUDPanel類中構(gòu)造方法上方定義一些類屬性,方便后續(xù)可以設(shè)置精靈的矩形區(qū)域和標(biāo)簽精靈的字體顏色,具體代碼如下:classHUDPanel(object):"""指示器面板類"""margin=10#精靈之間的間距
white=(255,255,255) #白色
gray=(64,64,64) #灰色
def__init__(self,display_group):……11.5.2指示器面板類的準(zhǔn)備3.創(chuàng)建圖像精靈然后,在構(gòu)造方法的末尾創(chuàng)建精靈并設(shè)置精靈的顯示位置,具體代碼如下:#創(chuàng)建圖像精靈#狀態(tài)精靈self.status_sprite=StatusButton(("pause.png","resume.png"),display_group)self.status_sprite.rect.topleft=(self.margin,self.margin)self.bomb_sprite=GameSprite("bomb.png",0,display_group)#炸彈精靈self.bomb_sprite.rect.x=self.marginself.bomb_sprite.rect.bottom=SCREEN_RECT.bottom-self.margin#生命計(jì)數(shù)精靈self.lives_sprite=GameSprite("life.png",0,display_group)self.lives_sprite.rect.right=SCREEN_RECT.right-self.marginself.lives_sprite.rect.bottom=SCREEN_RECT.bottom-self.margin11.5.2指示器面板類的準(zhǔn)備3.創(chuàng)建圖像精靈最后,在Game類的構(gòu)造方法末尾創(chuàng)建指示器面板對(duì)象,具體代碼如下:#指示器面板self.hud_panel=HUDPanel(self.all_group)
先定一個(gè)小目標(biāo)!11.5.3使用精靈實(shí)現(xiàn)文本標(biāo)簽掌握文本標(biāo)簽的使用,能夠使用精靈實(shí)現(xiàn)文本標(biāo)簽由于系統(tǒng)字體不太符合游戲的視覺風(fēng)格,所以需要使用自定義字體定義文本標(biāo)簽精靈,之后再創(chuàng)建指示器面板的文本標(biāo)簽精靈,具體內(nèi)容如下。1.使用自定義字體定義文本標(biāo)簽精靈Pygame的font模塊提供了SysFont類,使用SysFont類可以創(chuàng)建系統(tǒng)字體對(duì)象,實(shí)現(xiàn)在游戲窗口中繪制文字內(nèi)容。但系統(tǒng)字體存在以下幾點(diǎn)限制:不夠美觀。一般操作系統(tǒng)默認(rèn)提供的字體大多比較規(guī)整,直接應(yīng)用到游戲中,呈現(xiàn)的效果比較呆板。不支持跨平臺(tái)。不同操作系統(tǒng)使用的系統(tǒng)字體的名稱不同,當(dāng)一個(gè)程序被移植到其他類型的操作系統(tǒng)運(yùn)行時(shí),可能會(huì)導(dǎo)致文字內(nèi)容無法被正確顯示。11.5.3使用精靈實(shí)現(xiàn)文本標(biāo)簽1.使用自定義字體定義文本標(biāo)簽精靈在游戲開發(fā)中,若希望擁有美觀的字體,又需要確保游戲能夠跨平臺(tái)運(yùn)行。為了實(shí)現(xiàn)這一目標(biāo),使用自定義字體將是一個(gè)不錯(cuò)的選擇。使用自定義字體的方法是將字體文件與程序文件保存在同一個(gè)目錄下。在程序執(zhí)行時(shí),可以直接加載并使用該目錄下的字體文件;而在程序移植時(shí),只需將字體文件復(fù)制到相應(yīng)的目錄即可。pygame的font模塊還提供了另外一個(gè)Font類,使用Font類可以創(chuàng)建自定義字體對(duì)象。在game_items模塊中派生一個(gè)pygame.sprite.Sprite類的子類Label。Label類的類圖如圖所示。11.5.3使用精靈實(shí)現(xiàn)文本標(biāo)簽11.5.3使用精靈實(shí)現(xiàn)文本標(biāo)簽因?yàn)槲谋緲?biāo)簽的內(nèi)容并不需要在每一次游戲循環(huán)執(zhí)行時(shí)發(fā)生變化,所以Label類無須重寫update()方法。在游戲執(zhí)行過程中,如果希望更改文本標(biāo)簽的顯示內(nèi)容,可以通過set_text()方法重新渲染文本圖像,并且更新矩形區(qū)域。根據(jù)Label類的類圖,在game_items模塊中定義一個(gè)繼承pygame.sprite.Sprite的Label類,具體代碼如下:11.5.3使用精靈實(shí)現(xiàn)文本標(biāo)簽classLabel(pygame.sprite.Sprite):"""文本標(biāo)簽精靈"""font_path="./res/font/MarkerFelt.ttc"#字體文件路徑
def__init__(self,text,size,color,*groups):super().__init__(*groups)self.font=pygame.font.Font(self.font_path,size)self.color=colorself.image=self.font.render(text,True,self.color)self.rect=self.image.get_rect()defset_text(self,text):self.image=self.font.render(text,True,self.color)self.rect=self.image.get_rect()2.創(chuàng)建指示器面板的文本標(biāo)簽精靈在HUDPanel類的構(gòu)造方法末尾創(chuàng)建指示器面板的文本標(biāo)簽精靈,代碼如下:11.5.3使用精靈實(shí)現(xiàn)文本標(biāo)簽#創(chuàng)建文本標(biāo)簽精靈#分?jǐn)?shù)標(biāo)簽self.score_label=Label("%d"%self.score,32,self.gray,display_group)self.score_label.rect.midleft=(self.status_sprite.rect.right+self.margin,self.status_sprite.rect.centery)#炸彈標(biāo)簽self.bomb_label=Label("X3",32,self.gray,display_group)self.bomb_label.rect.midleft=(self.bomb_sprite.rect.right+self.margin,self.bomb_sprite.rect.centery)......#提示標(biāo)簽self.tip_label=Label("Pressspacebartoplayagain.",22,self.white,display_group)self.tip_label.rect.midtop=(self.best_label.rect.centerx,self.best_label.rect.bottom+8*self.margin)在設(shè)定文本標(biāo)簽精靈的位置時(shí),既可以參照之前的游戲示意圖,依次根據(jù)選好的每一個(gè)標(biāo)簽精靈的參照物設(shè)定,也可以每設(shè)置一次標(biāo)簽精靈的位置后進(jìn)行運(yùn)行測(cè)試,以確保每個(gè)標(biāo)簽精靈能顯示到正確的位置。運(yùn)行游戲,可以在游戲窗口的左上、左下以及右下方位置看到圖像對(duì)應(yīng)的文本標(biāo)簽,如圖所示。11.5.3使用精靈實(shí)現(xiàn)文本標(biāo)簽需要注意的是,此時(shí)的指示器面板存在以下一些問題:游戲得分、炸彈計(jì)數(shù)、生命計(jì)數(shù)的數(shù)據(jù)不會(huì)變化;最好成績(jī)始終為0;提示信息不會(huì)隨著游戲狀態(tài)的變化而變化,而是始終顯示在游戲窗口中央位置。
先定一個(gè)小目標(biāo)!11.5.4顯示和修改游戲數(shù)據(jù)掌握顯示和修改游戲數(shù)據(jù),能夠?qū)崿F(xiàn)顯示和修改游戲數(shù)據(jù)11.5.4顯示和修改游戲數(shù)據(jù)HUDPanel類封裝了3個(gè)方法:show_bomb()、show_lives()、increase_score(),分別實(shí)現(xiàn)顯示炸彈數(shù)量、顯示生命計(jì)數(shù)、增加游戲得分的功能,下面依次實(shí)現(xiàn)這幾個(gè)功能。1.顯示炸彈數(shù)量根據(jù)游戲介紹,英雄飛機(jī)出場(chǎng)后默認(rèn)會(huì)攜帶3顆炸彈,且會(huì)在玩家按下b鍵時(shí)引爆炸彈。引爆炸彈后,游戲窗口左下角的炸彈數(shù)量會(huì)減少。為了測(cè)試游戲是否能夠正常監(jiān)聽b鍵的事件,這里先以隨機(jī)數(shù)為例實(shí)現(xiàn)顯示炸彈數(shù)量的功能,即玩家按下b鍵后顯示隨機(jī)的炸彈數(shù)量。首先,在HUDPanel類中實(shí)現(xiàn)show_bomb()方法,通過show_bomb()方法的參數(shù)更新炸彈計(jì)數(shù)標(biāo)簽的顯示,具體代碼如下:defshow_bomb(self,count):#設(shè)置炸彈標(biāo)簽文字
self.bomb_label.set_text("X%d"%count)#設(shè)置炸彈標(biāo)簽位置
self.bomb_label.rect.midleft=(self.bomb_sprite.rect.right+self.margin,self.bomb_sprite.rect.centery)11.5.4顯示和修改游戲數(shù)據(jù)然后,在game模塊的頂部導(dǎo)入random模塊,代碼如下:importrandom11.5.4顯示和修改游戲數(shù)據(jù)最后,在Game類的event_handler()方法中添加代碼,監(jiān)聽玩家按下b鍵的事件,并使用隨機(jī)數(shù)測(cè)試顯示的炸彈數(shù)量,具體如加粗代碼所示:defevent_handler(self):……elifevent.type==pygame.KEYDOWNandevent.key==pygame.K_SPACE:ifself.is_game_over:#游戲已經(jīng)結(jié)束
self.reset_game()else:#切換暫停狀態(tài)
self.is_pause=notself.is_pauseifnotself.is_game_overandnotself.is_pause:#判斷是否正在游戲
#監(jiān)聽玩家按下字母b,引爆炸彈
ifevent.type==pygame.KEYDOWNandevent.key==pygame.K_b:self.hud_panel.show_bomb(random.randint(0,100))returnFalse11.5.4顯示和修改游戲數(shù)據(jù)運(yùn)行游戲,游戲窗口左側(cè)顯示的炸彈數(shù)量為3,按下b鍵,炸彈數(shù)量變?yōu)?0,再次按下b鍵,炸彈數(shù)量變?yōu)?1。游戲窗口左下角炸彈數(shù)量的變化情況如圖所示。游戲窗口左下角炸彈數(shù)量的變化情況11.5.4顯示和修改游戲數(shù)據(jù)2.顯示生命計(jì)數(shù)按照游戲介紹,英雄飛機(jī)被敵機(jī)撞毀后,游戲窗口右下角的生命計(jì)數(shù)應(yīng)該相應(yīng)減少;英雄飛機(jī)每得到10萬分會(huì)被獎(jiǎng)勵(lì)1條命,游戲窗口右下角的生命計(jì)數(shù)應(yīng)該相應(yīng)增加。為了測(cè)試游戲是否能夠正常顯示生命計(jì)數(shù),這里先以隨機(jī)數(shù)為例實(shí)現(xiàn)顯示生命計(jì)數(shù)的功能,即玩家按下b鍵后顯示隨機(jī)的生命計(jì)數(shù),具體步驟如下。在HUDPanel類中定義show_lives()方法,使用生命計(jì)數(shù)屬性值更新生命計(jì)數(shù)標(biāo)簽的顯示,代碼如下:defshow_lives(self):"""顯示生命計(jì)數(shù)"""self.lives_label.set_text("X%d"%self.lives_count)#設(shè)置生命計(jì)數(shù)標(biāo)簽文字
#設(shè)置生命計(jì)數(shù)標(biāo)簽位置
self.lives_label.rect.midright=(SCREEN_RECT.right-self.margin,self.bomb_label.rect.centery)#調(diào)整生命計(jì)數(shù)精靈位置
self.lives_sprite.rect.right=self.lives_label.rect.left-self.margin11.5.4顯示和修改游戲數(shù)據(jù)2.顯示生命計(jì)數(shù)修改Game類的event_handler()方法,在監(jiān)聽到玩家按下b鍵的事件處理中,使用隨機(jī)數(shù)測(cè)試生命計(jì)數(shù)的顯示,代碼如下:#判斷是否正在游戲ifnotself.is_game_overandnotself.is_pause:#監(jiān)聽玩家按下字母b,引爆炸彈
ifevent.type==pygame.KEYDOWNandevent.key==pygame.K_b:#TODO測(cè)試炸彈數(shù)量變化
self.hud_panel.show_bomb(random.randint(0,100))#TODO測(cè)試生命計(jì)數(shù)數(shù)量變化
self.hud_panel.lives_count=random.randint(0,10)self.hud_panel.show_lives()運(yùn)行游戲,按下b鍵,可以在游戲窗口的右下角位置看到生命計(jì)數(shù)的變化。11.5.4顯示和修改游戲數(shù)據(jù)3.增加游戲得分根據(jù)游戲介紹,每當(dāng)英雄飛機(jī)摧毀一架敵機(jī)之后,游戲得分應(yīng)該相應(yīng)增加,且根據(jù)摧毀的敵機(jī)類型增加相應(yīng)的分值。需要注意的是,隨著游戲分?jǐn)?shù)的增加,其他游戲?qū)傩钥赡軙?huì)受到影響,包括生命計(jì)數(shù)、最好成績(jī)和游戲級(jí)別,具體如下。(1)生命計(jì)數(shù)。英雄飛機(jī)每得到10萬分會(huì)被獎(jiǎng)勵(lì)1條命。(2)最好成績(jī)。若當(dāng)前游戲得分超過了歷史最好成績(jī),將當(dāng)前的游戲得分設(shè)置為最好成績(jī)。(3)游戲級(jí)別。當(dāng)前游戲得分超過了級(jí)別預(yù)設(shè)的分?jǐn)?shù)后,會(huì)自動(dòng)進(jìn)入下一級(jí)別。級(jí)別不同,游戲中敵機(jī)的類型、數(shù)量和速度不同。11.5.4顯示和修改游戲數(shù)據(jù)在增加游戲得分時(shí),除了要完成根據(jù)摧毀敵機(jī)的分值增加游戲得分的功能之外,還需處理與之相關(guān)的生命計(jì)數(shù)、最好成績(jī)以及游戲級(jí)別。下面分步驟實(shí)現(xiàn)這些功能。首先,在HUDPanel類的構(gòu)造方法上方定義幾個(gè)類屬性,方便后續(xù)計(jì)算獎(jiǎng)勵(lì)生命和游戲級(jí)別,具體代碼如下:reward_score=100000#獎(jiǎng)勵(lì)分值level2_score=10000#級(jí)別2分值level3_score=50000#級(jí)別3分值11.5.4顯示和修改游戲數(shù)據(jù)然后,在HUDPanel類中實(shí)現(xiàn)increase_score()方法,用于增加游戲得分,并處理與分?jǐn)?shù)有關(guān)的生命計(jì)數(shù)、最好成績(jī)以及游戲級(jí)別,具體代碼如下:defincrease_score(self,enemy_score):score=self.score+enemy_score#游戲得分ifscore//self.reward_score!=self.score//self.reward_score:self.lives_count+=1self.show_lives()self.score=scoreself.best_score=scoreifscore>self.best_scoreelseself.best_score......self.score_label.rect.midleft=(self.status_sprite.rect.right+self.margin,self.status_sprite.rect.centery)returnis_upgrade11.5.4顯示和修改游戲數(shù)據(jù)最后,在Game類的游戲循環(huán)中增加測(cè)試increase_score()方法的代碼,具體如下:else:#TODO測(cè)試修改游戲得分
ifself.hud_panel.increase_score(100):print("升級(jí)到%d"%self.hud_panel.level)#更新all_group中所有精靈內(nèi)容
self.all_group.update()11.5.4顯示和修改游戲數(shù)據(jù)運(yùn)行游戲,可以看到游戲窗口左上角的分?jǐn)?shù)標(biāo)簽快速地發(fā)生變化,達(dá)到獎(jiǎng)勵(lì)分?jǐn)?shù)后,游戲窗口右下角的生命計(jì)數(shù)數(shù)值增加,如圖所示。
先定一個(gè)小目標(biāo)!11.5.5保存和顯示最好成績(jī)掌握保存和顯示最好成績(jī),能夠?qū)崿F(xiàn)保存和顯示最好成績(jī)最好成績(jī)是一個(gè)永久記錄,不會(huì)因?yàn)橛螒虻耐顺龆鴣G失,因此需要進(jìn)行持久化存儲(chǔ)??紤]到最好成績(jī)占據(jù)的數(shù)據(jù)量比較小,可以直接采用文件存儲(chǔ)方式。在HUDPanel類的類圖中,設(shè)計(jì)了save_best_score()和load_best_score()方法,分別用于保存和加載最好成績(jī)。下面分別實(shí)現(xiàn)save_best_score()方法和load_best_score()方法,并在適當(dāng)?shù)奈恢谜{(diào)用這兩個(gè)方法,以保存和顯示最好成績(jī)。11.5.5保存和顯示最好成績(jī)1.保存最好成績(jī)首先,在HUDPanel類的構(gòu)造方法上方定義一個(gè)類屬性,使用該屬性指定保存最好成績(jī)的文件名,代碼如下:record_filename="record.txt"#最好成績(jī)文件名11.5.5保存和顯示最好成績(jī)?nèi)缓?,在HUDPanel類中實(shí)現(xiàn)save_best_score()方法,代碼如下:defsave_best_score(self):"""將最好成績(jī)寫入record.txt"""file=open(self.record_filename,"w")file.write("%d"%self.best_score)file.close()最后,修改Game類的游戲循環(huán),在游戲退出之前,調(diào)用指示器面板的save_best_score()方法,修改后的代碼如加粗部分所示:defstart(self):"""開始游戲"""……ifself.event_handler(): #事件監(jiān)聽
self.hud_panel.save_best_score()return……11.5.5保存和顯示最好成績(jī)運(yùn)行游戲,等到游戲分?jǐn)?shù)增長(zhǎng)到一定數(shù)值后,按下ESC鍵退出游戲,此時(shí)可以看到飛機(jī)大戰(zhàn)項(xiàng)目目錄下新建了record.txt文件,record.txt文件中保存了游戲退出時(shí)記錄的分?jǐn)?shù),如圖所示。11.5.5保存和顯示最好成績(jī)2.加載最好成績(jī)游戲結(jié)束后會(huì)在窗口中央顯示最好成績(jī),因此我們需要從record.txt文件中加載最好成績(jī)。在HUDPanel類中實(shí)現(xiàn)load_best_score()方法,代碼如下:11.5.5保存和顯示最好成績(jī)defload_best_score(self):"""從record.txt加載最好成績(jī)"""try:file=open(self.record_filename)txt=file.readline()file.close()self.best_score=int(txt)except(FileNotFoundError,ValueError):print("文件不存在或者類型轉(zhuǎn)換錯(cuò)誤")修改HUDPanel類的構(gòu)造方法,在定義完游戲?qū)傩灾?,調(diào)用load_best_score()方法加載最好成績(jī),修改后的代碼如下所示:11.5.5保存和顯示最好成績(jī)def__init__(self,display_group):"""構(gòu)造方法
:paramdisplay_group:面板中的精靈要被添加到的顯示精靈組
"""#游戲?qū)傩?/p>
self.score=0 #游戲得分
self.lives_count=3 #生命計(jì)數(shù)
self.level=1 #游戲級(jí)別
self.best_score=0 #最好成績(jī)
self.load_best_score() #加載最好成績(jī)
……運(yùn)行游戲,可以看到游戲窗口中央位置顯示了之前保存的最好成績(jī),如圖所示。11.5.5保存和顯示
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。
最新文檔
- 第4課-2023-2024學(xué)年初中信息技術(shù)七年級(jí)上冊(cè)(人教版)-教學(xué)設(shè)計(jì)-總結(jié)與評(píng)價(jià)
- 10 綠(教學(xué)設(shè)計(jì))-2023-2024學(xué)年統(tǒng)編版語文四年級(jí)下冊(cè)
- 15 可親可敬的家鄉(xiāng)人1(教學(xué)設(shè)計(jì))2024-2025學(xué)年統(tǒng)編版道德與法治二年級(jí)上冊(cè)
- 中國(guó)自緊式外圓切斷刀行業(yè)市場(chǎng)發(fā)展前景及發(fā)展趨勢(shì)與投資戰(zhàn)略研究報(bào)告
- 第7課 基督教的興起和法蘭克王國(guó) 教學(xué)設(shè)計(jì)-2023-2024學(xué)年浙江省部編版歷史與社會(huì)九年級(jí)上冊(cè)
- 熱電廠施工方案與進(jìn)度安排
- 第23課 和平發(fā)展合作共贏的歷史潮流 教學(xué)設(shè)計(jì)-2023-2024學(xué)年高中歷史統(tǒng)編版(2019)必修中外歷史綱要下冊(cè)
- 農(nóng)藥運(yùn)輸合同范本
- 科技創(chuàng)新中心的定義與功能
- 門面土地租賃合同范本(一)與門面店租賃合同8篇
- GB/T 42595-2023承壓設(shè)備修理基本要求
- 塑料成型模具設(shè)計(jì)(第2版)江昌勇課件1-塑料概述
- 科幻小說賞讀智慧樹知到答案章節(jié)測(cè)試2023年杭州師范大學(xué)
- 《足球:腳背內(nèi)側(cè)傳球》說課課件
- 高中生物 人教版 選修二《生態(tài)系統(tǒng)及其穩(wěn)定性》 《生態(tài)系統(tǒng)及其穩(wěn)定性》單元教學(xué)設(shè)計(jì)
- 公司設(shè)備日點(diǎn)檢表模板
- (新版)金屬冶煉(鉛、鋅冶煉)主要負(fù)責(zé)人考試題庫(含答案)
- 創(chuàng)新創(chuàng)業(yè)基礎(chǔ)(楊衛(wèi)軍)第九章 新創(chuàng)企業(yè)管理
- GA/T 1920-2021法庭科學(xué)疑似毒品中211種麻醉藥品和精神藥品檢驗(yàn)氣相色譜-質(zhì)譜法
- GB/T 21260-2007汽車用前照燈清洗器
- 兒科重癥監(jiān)護(hù)病房管理演示文稿
評(píng)論
0/150
提交評(píng)論