飛機大戰(zhàn)游戲設計
摘 要:根據(jù)課程要求,以及面向?qū)ο蟪绦蛟O計的編程思想,在Windows操作系統(tǒng)環(huán)境下,運用PyCharm編譯程序,以Python語言為開發(fā)語言,最終實現(xiàn)飛機大戰(zhàn)游戲相應的游戲操作功能。Python是一種跨平臺的、開源的、免費的、解釋型的高級編程語言。它具有豐富的、強大的庫, 能夠把其他語言制作的各種模塊很輕松地聯(lián)結(jié)在一起, 所以Python常被稱為“膠水”語言。Python語言近幾年發(fā)展勢頭迅猛, 應用領域也非常廣泛, 在Web編程、圖形處理、黑客編程、大數(shù)據(jù)處理、網(wǎng)絡爬蟲、科學計算和游戲編程等領域都能找到Python的應用。其中Pygame是Python的一個第三方庫, 搭載了基于OpenGL的圖形庫和優(yōu)質(zhì)的音頻庫, 可以快速上手制作2D游戲的原型。Pygame的API比較偏底層, 開發(fā)人員在編程時具有很大的自由度, 同時具有了很強的可定制性。Python語言的研究和發(fā)明主要是為了便于學習和應用, 因此Python語言是開源的, 并且語法非常簡單、容易編寫和理解。本文通過對飛機大戰(zhàn)游戲的設計與分析, 掌握Python語言在游戲開發(fā)領域的優(yōu)勢。
關鍵詞:面向?qū)ο蟪绦蛟O計;Pygame模塊;Python語言;PyCharm編譯程序
1、課程概述
飛機大戰(zhàn)游戲設計開發(fā)課題是《面向?qū)ο蟪绦蛟O計(Python)》中面向?qū)ο蟪绦蛟O計的一次運用,主要設計原則如下:
(1)簡單性,在實現(xiàn)軟件的功能的同時, 盡量讓軟件操作簡單易懂;
(2)針對性,基于Python軟件, 實現(xiàn)飛機大戰(zhàn)游戲的各種要求;
(3)一致性,類型、變量和其他元素的命名規(guī)則保持一致;
完成同樣的功能應該盡量使用同樣的元素;界面元素的外觀風格、擺放位置在同一個界面和不同界面之間是一致的??梢允蛊浠绢悗霵ygame的基本函數(shù)和功能模塊的調(diào)用操作實現(xiàn)python語言在課程設計中的運用。
通過對飛機大戰(zhàn)游戲設計的實現(xiàn),要求我們進一步理解和掌握課堂上所學各種基本類型的變量、數(shù)據(jù)類型、類、用戶輸入和文件操作實現(xiàn)面向?qū)ο蟮挠螒蜷_發(fā),以及它們在程序中的使用方法;掌握Python軟件設計的基本內(nèi)容和設計方法,并培養(yǎng)學生進行規(guī)范化軟件設計的能力;掌握使用各種計算機資料和有關參考資料,提高我們進行程序設計的基本能力,逐步熟悉程序設計的方法,并養(yǎng)成良好的編程習慣。
本次設計為了使飛機大戰(zhàn)游戲具有更加豐富的功能,基于面向?qū)ο蠛兔嫦蜻^程的方法,使用Python編程語言提供資源結(jié)構(gòu),以Pygame模塊對游戲進行研發(fā),提出了飛機大戰(zhàn)游戲開發(fā)方案。通過各種優(yōu)化調(diào)整,實現(xiàn)了飛機的飛行移動、擊落,計分等功能,實現(xiàn)了飛機大戰(zhàn)的開發(fā),增加游戲體驗。
2、需求分析
2.1問題描述
本次課程設計題目是 “飛機大戰(zhàn)游戲設計”,實現(xiàn)基于面向?qū)ο蟪绦蛟O計的方法,使用Python編程語言,以Pygame模塊實時對游戲進行研發(fā),提出飛機大戰(zhàn)小游戲開發(fā)方案。通過各種優(yōu)化調(diào)整,實現(xiàn)飛機的飛行移動、擊落,計分等功能,實現(xiàn)飛機大戰(zhàn)的開發(fā),增加游戲體驗。
2.2設計目的
這次課程旨在使讀者學會分析研究面向?qū)ο缶幊痰奶匦?,學會Python編程方法,以便選擇合適的數(shù)據(jù)結(jié)構(gòu)和邏輯結(jié)構(gòu),以及相應的運算,把現(xiàn)實世界中的問題轉(zhuǎn)化為計算機內(nèi)部的表示和處理。
《面向?qū)ο蟪绦蛟O計(Python)》課程的主要目的是使學生一步理解和掌握課堂上所學各種基本類型的變量、數(shù)據(jù)類型、類、用戶輸入、文件操作等,以及它
們在程序中的使用方法;掌握軟件設計的基本內(nèi)容和設計方法,并培養(yǎng)學生進行規(guī)范化軟件設計的能力;掌握使用各種計算機資料和有關參考資料,提高學生進行程序設計的基本能力。
2.3 系統(tǒng)設計思想
本次設計基于面向?qū)ο蟮某绦蛟O計方法,使用Python編程語言提供資源結(jié)構(gòu),以Pygame模塊實時對游戲進行研發(fā),提出了飛機大戰(zhàn)小游戲二次開發(fā)方案。通過各種優(yōu)化調(diào)整,實現(xiàn)了飛機的飛行移動、擊落,計分等功能,而且拓展了游戲的等級提升功能、界面打印功能、游戲獎勵機制等等,實現(xiàn)了飛機大戰(zhàn)的二次開發(fā),豐富了游戲體驗。
Pygame是Python的一個第三方庫, 搭載了基于OpenGL的圖形庫和優(yōu)質(zhì)的音頻庫, 可以快速上手制作2D游戲的原型。Pygame的API比較偏底層, 開發(fā)人員在編程時具有很大的自由度, 同時具有了很強的可定制性。
按照游戲工業(yè)市場的飛機游戲開發(fā)需求,分析游戲的基本功能,在此基礎上增加游戲的各類功能模塊完善游戲。本設計所用到的編程語言是Python,版本是Python3.9,開發(fā)工具為Pycharm,調(diào)用Pygame模塊,對游戲進行開發(fā)、運行及測試。游戲程序編輯、編譯、調(diào)試、發(fā)布所有過程都是基于PC機平臺運行。
2.4 開發(fā)平臺及工具介紹
開發(fā)軟件:Python 3.9
使用系統(tǒng):Windows 10
3、設計要求
3.1 設計目的
(1)實現(xiàn)飛機的移動、子彈發(fā)射,對本次游戲有一個初步的編寫及認識。
(2)飛機的持續(xù)按鍵移動和飛機自爆優(yōu)化。
(3)進行基類的抽取,使代碼更具有層次性和簡化重復代碼。
(4)對判斷以及刪除越界子彈、敵機發(fā)射子彈進行擴展優(yōu)化。
3.2 總體設計
3.2.1系統(tǒng)功能總體設計框圖
圖3-1 系統(tǒng)功能總體設計框圖
3.2.2主要流程圖
(1)程序主函數(shù)
程序主函數(shù)主要進行定義和繼承的相關操作,實現(xiàn)成員函數(shù)的定義和成員屬性的定義,繼承相關函數(shù)并添加相關的游戲特性。如圖3-2所示。
圖3-2 程序主函數(shù)流程圖
(2)子彈模塊
子彈實例化中,分成了兩種射擊模式,一個是普通子彈,另一個是超級子彈,包括了外形、速度、與敵機碰撞的撞擊等基本因素,其基本屬性方法如圖3-3所示。
圖3-3 子彈模塊
(3)敵機模塊
敵軍飛機的飛行模式設定為單一向垂直移動飛行模式,設計飛行的速度,調(diào)用隨機函數(shù),設定敵軍飛機的隨機高度和隨機寬度
圖3- 4 敵軍飛機功能模塊
(4)本機模塊
自身飛機的功能屬性如圖3-5所示,需要自身飛機的圖片加載、飛行速度設置、飛行上下移動等功能。
圖3- 5 自身飛機模塊
(5)獎勵模塊
游戲的獎勵模塊是本設計實現(xiàn)游戲創(chuàng)新的重要組成部分,本文中設計了生命、超級子彈、炸彈3個功能屬性的獎勵。
圖3- 6 獎勵模塊
5 調(diào)試分析
5.1 調(diào)試
經(jīng)過反復測試,飛機大戰(zhàn)游戲最終可以流暢運行,而且容錯能力較好,穩(wěn)定性很強。下面做一些簡單的說明:
(1)print() 方法
第一種方法簡單直接粗暴有效,就是用print()把可能有問題的變量打印出來看看,執(zhí)行后在輸出中查找打印的變量值。
(2)斷言 assert
凡是用print()來輔助查看的地方,都可以用斷言(assert)來替代,assert的意思是,表達式n != 0應該是True,否則,根據(jù)程序運行的邏輯,后面的代碼肯定會出錯。如果斷言失敗,assert語句本身就會拋出AssertionError。程序中如果到處充斥著assert,和print()相比也好不到哪去。不過,啟動Python解釋器時可以用-O參數(shù)來關閉assert。
(3)logging
把print()替換為logging是第3種方式,和assert比,logging不會拋出錯誤,而且可以輸出到文件,logging.info()就可以輸出一段文本。運行,發(fā)現(xiàn)除了ZeroDivisionError,沒有任何信息。別急,在import logging之后添加一行配置再試試。
5.2 調(diào)試中遇到的問題
1.敵機死后,子彈連帶的消失
因為子彈組是敵軍對象的成員,是在主函數(shù)需要敵軍的子彈再加到一個組,而且所有敵軍的子彈加到一起更更新更加方便,這樣不用擔心敵機毀掉了,他們的子彈對象也訪問不了。
2.子彈和敵機多次撞擊
由于播放爆炸動畫采用的方法是被撞毀時,先不移除精靈組,然后更改該對象圖片,知道圖片輪完了才kill(),這就導致進行下一次循環(huán),對象還沒kill(),kill()了就不能進行輪播。撞毀的時候新建循環(huán)把爆炸圖片畫在屏幕上,行不通,第循環(huán)一次只能更新一幀圖片,如果你要更新多幀那么其他精靈就會靜止;撞毀時候,先移除精靈組,然后用變量儲存,進行最初更新的方法。實驗證明可行。
3.進行了update卻不顯示
混淆draw和display.update。首先一個精靈的update方法讓圖像有改變,draw方法調(diào)用screen的blit方法畫到屏幕上,這時候屏幕畫面殘留在上一幀,只有display更新了才能看到
4. 想方設法把一個Sprite或者rect或者image進行清除操作
想要看不見他,兩種方法如果是精靈,skill()從所有精靈組里面刪除,如果只是單純的image和rect,直接從他們的list里面remove,這樣就不會被blit,實際上屏幕在更新,如果你想要看到,就要畫在在更新的每一幀上面,之后如果不再用到它,python自己會進行回收.
5. 為什么英雄死掉了,還是會發(fā)生碰撞檢測
這是因為,雖然我們把英雄加入英雄隊伍,但是隊伍中英雄很少,為了方便我們碰撞的時候不是從隊伍中取直接就用該英雄對象進行檢測,這時候,英雄skill()了,但是rect并沒有丟失。skill()只是把他從需要顯示或者操作群體中把他刪除了,但是這個對象并沒有被立即回收,它的rect還是在,還能用于碰撞檢測
6.不知道全局變量如何使用
python里面的全局常量和其他語言一樣是沒有歧義的,但是全局變量就不一樣了,因為python定義變量不用定義類型,只有在賦值的時候才知道,所以在函數(shù)里面使用全局變量,無法保證兩個變量是一樣的,所以在函數(shù)里面需要用global聲明一下這個變量是我開始設的這個全局變量,不是又重新定義了一個局部變量。
6 總結(jié)
6.1功能
1.基本功能
(1)鍵盤方向鍵控制英雄移動
(2)英雄自動發(fā)射子彈
(3)敵軍飛機自動生成,向下運動,發(fā)射不同速度炮彈
(4)自動生成補給,有子彈buff,炸彈buff,補血buff子彈。buff最多吃5個,每吃一個子彈數(shù)目或者威力提高,吃到第五個召喚"最強形態(tài)"。炸彈buff可以無限吃,當然出現(xiàn)幾率比較小,吃到的炸彈在屏幕左下角顯示,空格鍵引爆一顆炸彈,毀掉當前所有敵軍飛機,boss損血。補血buff,一次補滿英雄血條
(5)每種敵軍對應不同分數(shù),擊爆后,屏幕又下角的總分增加相應的分數(shù)。
(6)子彈擊中和撞擊都會時敵機和英雄損血,且英雄還會debuff,就是buff效果會減弱。
(7)當英雄掛掉,游戲結(jié)束,屏幕顯示分數(shù),并且可以選擇重來或者結(jié)束游戲
2.附加功能
(1)英雄吃buff初期子彈威力+1,且子彈排數(shù)有序增加,均勻分步。
(2)血條低于某個值會變紅,當吃補給增加后又會恢復原色。
(3)敵機出現(xiàn)位置隨機,速度隨機,發(fā)射子彈速度隨機,數(shù)量排數(shù)自定義,低級敵機出場較多,中型后來逐漸增多。
(4)英雄,boss有飛行和爆炸動畫,敵機有爆炸動畫。
(5)撞擊對不同對象效果不同,英雄撞boss,英雄死boss損血,敵機撞英雄,敵機爆,英雄損血,且損血和被子彈擊中血量不同。
(6)背景和bgm循環(huán)移動,營造飛行感覺。
(7)每個動作都有專屬音效,如英雄爆,敵機爆,補習,補子彈,補炸彈,扔炸彈,射擊。
(8)boss移動速度慢,慢于最低速度,即1像素每幀,游戲定義為60幀/秒,即速度低于60像素/秒。
6.2 收獲與體會
通過此次課程設計,使我更加扎實的掌握了Pycharm、Python、Pygame方面的知識,在設計過程中雖然遇到了一些問題,但經(jīng)過一次又一次的思考,一遍又一遍的檢查終于找出了原因所在,也暴露出了前期我在這方面的知識欠缺和經(jīng)驗不足。實踐出真知,通過親自動手制作,使我們掌握的知識不再是紙上談兵。
在課程設計過程中,持續(xù)發(fā)現(xiàn)錯誤,持續(xù)改正,持續(xù)領悟,持續(xù)獲取。最終的檢測調(diào)試環(huán)節(jié),本身就是在踐行“過而能改,善莫大焉”的知行觀。這次課程設計終于順利完成了,在設計中遇到了很多問題,最后在老師的指導下,終于游逆而解。在今后社會的發(fā)展和學習實踐過程中,一定要不懈努力,不能遇到問題就想到要退縮,一定要不厭其煩的發(fā)現(xiàn)問題所在,然后一一實行解決,只有這樣,才能成功的做成想做的事,才能在今后的道路上劈荊斬棘,而不是知難而退,那樣永遠不可能收獲成功,收獲喜悅,也永遠不可能得到他人對你的認可!此次課程設計,感慨頗多,從理論到實踐,在這一個周里,能夠說得是苦多于甜,但是能夠?qū)W到很多很多的東西,同時不但能夠鞏固了以前所學過的知識,而且學到了很多在書本上所沒有學到過的知識。通過這次課程設計使我懂得了理論與實際相結(jié)合是很重要的,只有理論知識是遠遠不夠的,只有把所學的理論知識與實踐相結(jié)合起來,從理論中得出結(jié)論,才能真正為社會服務,從而提升自己的實際動手水平和獨立思考的水平。在設計的過程中遇到問題,能夠說得是困難重重,但可喜的是最終都得到了解決。
Python是一種簡單易學,功能強大的編程語言,它有高效率的高層數(shù)據(jù)結(jié)構(gòu),能簡單而有效地實現(xiàn)面向?qū)ο缶幊獭ython簡潔的語法和對動態(tài)輸入的支持,再加上解釋性語言的本質(zhì),使得它在大多數(shù)平臺上的很多領域都是一個理想的腳本語言,特別適用于快速的應用程序開發(fā)。其次,這種解釋語言的機制,更能讓我們這些初學者體驗到學習成果,不需要了解很多東西,也能編出個小程序來,這個過程比其他語言要快和簡單很多。此外,還有一點就是Python的學習很有彈性,我稍微學一點就能做點東西,而想要深入研究仍然有無窮的方向可以選擇,因為Python的應用范圍也是很廣闊。
參考文獻
[1]宋雅娟,尚鮮連.面向Python翻轉(zhuǎn)課堂的圖形動畫案例庫的設計[J].計算機時代,2021(12):106-108.DOI:10.16644/j.cnki.cn33-1094/tp.2021.12.026.
[2]吳紹兵,王昌梅,賈學明,曹好順,扶斌.基于對分課堂的Python語言程序設計教學探索[J].計算機教育,2019(02):53-56.DOI:10.16512/j.cnki.jsjjy.2019.02.014.
[3]嵩天,黃天羽,禮欣.Python語言:程序設計課程教學改革的理想選擇[J].中國大學教學,2016(02):42-47.
[4]杜蘭,陳琳琳,黃祎靜.基于Pygame的壁球游戲的設計與開發(fā)[J].電子技術與軟件工程,2018(22):54+202.
[5]劉班.基于Pygame快速開發(fā)游戲軟件[J].數(shù)字技術與應用,2013(08):130.DOI:10.19695.
[6] Creating Physics Aware Games using PyGame and PyODE[J]. Python Papers,2010,5(3).
[7]Youtian Guo,Qi Gao,Feng Pan. Trained Model Reuse of Autonomous-Driving in Pygame with Deep Reinforcement Learning[C].
[8]Sahni Nishant,Srinivasan Kailash,Savla Harsh. A Review on Developing an Arcade Game Machine and an Arcade Game using Raspberry Pi and Pygame[J]. International Journal of Computer Applications,2015,120(17):
附錄
程序代碼:
import random
import pygame
pygame.init()
SCORE = 0
#屏幕大小的常量
SCREEN_RECT = pygame.Rect(0, 0, 480, 700)
color
color_blue = (30, 144, 255)
color_green = (0, 255, 0)
color_red = (255, 0, 0)
color_purple = (148, 0, 211)
color_gray = (251, 255, 242)
#刷新的幀率
FRAME_PER_SEC = 60 # 刷新率是60hz,即每秒update60次
創(chuàng)建敵機的定時器常量,自定義用戶事件,其實就是int數(shù),不同數(shù)表示不同事件
CREATE_ENEMY_EVENT = pygame.USEREVENT
#英雄發(fā)射子彈事件
HERO_FIRE_EVENT = pygame.USEREVENT + 1
#buff1 出現(xiàn)的事件
BUFF1_SHOW_UP = pygame.USEREVENT + 2
#buff2
BUFF2_SHOW_UP = pygame.USEREVENT + 3
#敵軍發(fā)射子彈
ENEMY_FIRE_EVENT = pygame.USEREVENT + 4
#發(fā)射炸彈
BOMB_THROW = pygame.USEREVENT + 5
class GameScore(object):
global SCORE
def __init__(self):
self.score = 0
pass
def getvalue(self):
self.score = SCORE
return self.score
class GameSprite(pygame.sprite.Sprite):
“”“飛機大戰(zhàn)游戲”""
def init(self, image_name, speedy=1, speedx=0):
# 調(diào)用父類的初始化方法
super().init()
# 定義對象的屬性
self.image = pygame.image.load(image_name)
self.rect = self.image.get_rect()
self.speedy = speedy
self.speedx = speedx
self.injury = 1
self.index = 0 # 記幀數(shù)變量
self.bar = bloodline(color_blue, self.rect.x, self.rect.y - 10, self.rect.width)
def update(self):
# 在屏幕的垂直方向上移動
self.rect.y += self.speedy
self.rect.x += self.speedx
self.bar.x = self.rect.x
self.bar.y = self.rect.y - 10
class Background(GameSprite):
“”“游戲背景精靈”""
def init(self, is_alt=False):
# 1. 調(diào)用父類方法實現(xiàn)精靈的創(chuàng)建(image/rect/speed)
super().init("./images/background.png")
# 2. 判斷是否是交替圖像,如果是,需要設置初始位置
if is_alt:
self.rect.y = -self.rect.height
def update(self):
# 1. 調(diào)用父類的方法實現(xiàn)
super().update()
# 2. 判斷是否移出屏幕,如果移出屏幕,將圖像設置到屏幕的上方
if self.rect.y >= SCREEN_RECT.height:
self.rect.y = -self.rect.height
class Boss(GameSprite):
def __init__(self):
super().__init__("./images/enemy3_n1.png", 0, 1)
self.music_boom = pygame.mixer.Sound("./music/enemy3_down.wav")
self.music_fly = pygame.mixer.Sound("./music/enemy3_flying.wav")
self.music_fly.play(-1)
self.rect.centerx = 240
self.y = 200
self.isboom = False
self.number = 3
self.index1 = 1 # 控制動畫速度
self.index2 = 0
self.index3 = 0
self.index4 = 0
self.injury = 1
self.bar = bloodline(color_purple, 0, 0, 480, 8, 200)
self.bullets = pygame.sprite.Group()
def fire(self):
for j in range(2, 7): # 每層5個
bullet = Bullet(0, 1)
bullet.injury = 1
# 2. 設置精靈的位置
bullet.rect.centerx = self.rect.centerx
bullet.rect.y = self.rect.bottom
if j == 2:
bullet.speedx = 0
else:
bullet.speedx = (-1) ** j * ((j - 1) // 2) * 1
self.bullets.add(bullet)
def update(self):
# 左右移
global SCORE
if self.index4 % 2 == 0: # 降低幀速率,注意這兩個指針不能一樣
# 內(nèi)部為左右移動大概50像素
if self.index3 % 50 == 0 and (self.index3 // 50) % 2 == 1:
self.speedx = -self.speedx
self.rect.x += self.speedx
self.index3 += 1
self.index4 += 1
# 發(fā)電動畫
self.image = pygame.image.load("./images/enemy3_n" + str((self.index1 // 6) % 2 + 1) + ".png")
self.index1 += 1
# 爆炸動畫
if self.isboom:
self.bar.length -= self.injury * self.bar.weight
if self.bar.length <= 0: # 此時滿足爆炸的條件了
self.music_fly.stop()
if self.index2 == 0:
self.music_boom.play()
if self.index2 < 29: # 4*7+1
self.image = pygame.image.load("./images/enemy3_down" + str(self.index2 // 7) + ".png")
# 這個地方之所以要整除4是為了減慢爆炸的速度,如果按照update的頻率60hz就太快了
self.index2 += 1
else:
self.kill()
SCORE += self.bar.value
else:
self.isboom = False # 否則還不能死
class Enemy(GameSprite):
“”“敵機精靈”""
def init(self, num=1):
self.number = num
# 1. 調(diào)用父類方法,創(chuàng)建敵機精靈,同時指定敵機圖片
super().init("./images/enemy" + str(num) + “.png”)
# music
if num == 1:
self.music_boom = pygame.mixer.Sound("./music/enemy1_down.wav")
else:
self.music_boom = pygame.mixer.Sound("./music/enemy2_down.wav")
# 2. 指定敵機的初始隨機速度 1 ~ 3
self.speedy = random.randint(1, 3)
# 3. 指定敵機的初始隨機位置
self.rect.bottom = 0
max_x = SCREEN_RECT.width - self.rect.width
self.rect.x = random.randint(0, max_x)
# 4.爆炸效果
self.isboom = False
self.index = 0
# 5.血條
if self.number == 1:
self.bar = bloodline(color_blue, self.rect.x, self.rect.y, self.rect.width)
else:
self.bar = bloodline(color_blue, self.rect.x, self.rect.y, self.rect.width, 3, 4)
# 6,子彈
self.bullets = pygame.sprite.Group()
def fire(self):
for i in range(0, 2):
# 1. 創(chuàng)建子彈精靈
bullet = Bullet(0, random.randint(self.speedy + 1, self.speedy + 3))
# 2. 設置精靈的位置
bullet.rect.bottom = self.rect.bottom + i * 20
bullet.rect.centerx = self.rect.centerx
# 3. 將精靈添加到精靈組
self.bullets.add(bullet)
def update(self):
global SCORE
# 1. 調(diào)用父類方法,保持垂直方向的飛行
super().update()
# 2. 判斷是否飛出屏幕,如果是,需要從精靈組刪除敵機
if self.rect.y > SCREEN_RECT.height:
# print(“飛出屏幕,需要從精靈組刪除…”)
# kill方法可以將精靈從所有精靈組中移出,精靈就會被自動銷毀
self.kill()
self.bar.length = 0
if self.isboom:
self.bar.length -= self.bar.weight * self.injury
if self.bar.length <= 0:
if self.index == 0: # 保證只響一次
self.music_boom.play()
if self.index < 17: # 4*4+1
self.image = pygame.image.load(
“./images/enemy” + str(self.number) + “_down” + str(self.index // 4) + “.png”)
# 這個地方之所以要整除4是為了減慢爆炸的速度,如果按照update的頻率60hz就太快了
self.index += 1
else:
self.kill()
SCORE += self.bar.value
else:
self.isboom = False
class Hero(GameSprite):
“”“英雄精靈”""
def __init__(self):
# 1. 調(diào)用父類方法,設置image&speed
super().__init__("./images/me1.png")
self.music_down = pygame.mixer.Sound("./music/me_down.wav")
self.music_upgrade = pygame.mixer.Sound("./music/upgrade.wav")
self.music_degrade = pygame.mixer.Sound("./music/supply.wav")
self.number = 0
# 2. 設置英雄的初始位置
self.rect.centerx = SCREEN_RECT.centerx
self.rect.bottom = SCREEN_RECT.bottom - 120
# 3. 創(chuàng)建子彈的精靈組
self.bullets = pygame.sprite.Group()
# 4.爆炸
self.isboom = False
self.index1 = 1 # 控制動畫速度
self.index2 = 0
# 5.buff1加成
self.buff1_num = 0
# 6,英雄血條
self.bar = bloodline(color_green, 0, 700, 480, 8, 10)
# 7,炸彈數(shù)目
self.bomb = 0
def update(self):
# 英雄在水平方向移動和血條不同步,特殊
self.rect.y += self.speedy
self.rect.x += self.speedx
# 控制英雄不能離開屏幕
if self.rect.x < 0:
self.rect.x = 0
elif self.rect.right > SCREEN_RECT.right:
self.rect.right = SCREEN_RECT.right
elif self.rect.y < 0:
self.rect.y = 0
elif self.rect.bottom > SCREEN_RECT.bottom:
self.rect.bottom = SCREEN_RECT.bottom
# 英雄噴氣動畫
self.image = pygame.image.load("./images/me" + str((self.index1 // 6) % 2 + 1) + ".png")
self.index1 += 1
# 英雄爆炸動畫
if self.isboom:
self.bar.length -= self.injury * self.bar.weight
if self.bar.length <= 0: # 此時滿足爆炸的條件了
if self.index2 == 0:
self.music_down.play()
if self.index2 < 17: # 4*4+1
self.image = pygame.image.load("./images/me_destroy_" + str(self.index2 // 4) + ".png")
# 這個地方之所以要整除4是為了減慢爆炸的速度,如果按照update的頻率60hz就太快了
self.index2 += 1
else:
self.kill()
else:
self.isboom = False # 否則還不能死
# 發(fā)射子彈
def fire(self):
if self.buff1_num == 0:
for i in range(0, 1):
bullet = Bullet()
bullet.rect.bottom = self.rect.y - i * 20
bullet.rect.centerx = self.rect.centerx
self.bullets.add(bullet)
elif self.buff1_num <= 3:
for i in (0, 1):
for j in range(2, self.buff1_num + 3):
bullet = Bullet(2, -3)
bullet.rect.bottom = self.rect.y - i * 20
if (self.buff1_num % 2 == 1):
bullet.rect.centerx = self.rect.centerx + (-1) ** j * 15 * (j // 2)
if (self.buff1_num % 2 == 0):
if j == 2:
bullet.rect.centerx = self.rect.centerx
else:
bullet.rect.centerx = self.rect.centerx + (-1) ** j * 15 * ((j - 1) // 2)
self.bullets.add(bullet)
elif self.buff1_num >= 4:
for i in range(0, 1):
# 1. 表示有幾層
for j in range(2, 5): # 每層三個
bullet = Bullet(3, -3)
bullet.injury = 2
# 2. 設置精靈的位置
bullet.rect.bottom = self.rect.y
if j == 2:
bullet.rect.centerx = self.rect.centerx
else:
bullet.rect.centerx = self.rect.centerx + (-1) ** j * (30 + 5 * i)
bullet.speedx = (-1) ** j * (i + 1)
self.bullets.add(bullet)
class Heromate(Hero):
def init(self, num):
super().init()
self.image = pygame.image.load("./images/life.png")
self.number = num
def update(self):
if self.rect.right > SCREEN_RECT.right:
self.rect.right = SCREEN_RECT.right
if self.rect.x < 0:
self.rect.x = 0
if self.rect.y < 0:
self.rect.y = 0
elif self.rect.bottom > SCREEN_RECT.bottom:
self.rect.bottom = SCREEN_RECT.bottom
def fire(self):
for i in range(0, 1, 2):
bullet = Bullet()
bullet.rect.bottom = self.rect.y - i * 20
bullet.rect.centerx = self.rect.centerx
self.bullets.add(bullet)
class Bullet(GameSprite):
“”“子彈”""
def __init__(self, color=1, speedy=-2, speedx=0):
# 調(diào)用父類方法,設置子彈圖片,設置初始速度
self.hity = color # 子彈傷害值
self.music_shoot = pygame.mixer.Sound("./music/bullet.wav")
self.music_shoot.set_volume(0.4)
if color > 0: # 只讓英雄發(fā)子彈響
self.music_shoot.play()
super().__init__("./images/bullet" + str(color) + ".png", speedy, speedx)
def update(self):
# 調(diào)用父類方法,讓子彈沿垂直方向飛行
super().update()
# 判斷子彈是否飛出屏幕
if self.rect.bottom < 0 or self.rect.y > 700:
self.kill()
class Buff1(GameSprite):
def init(self):
super().init("./images/bullet_supply.png", 1)
self.music_get = pygame.mixer.Sound("./music/get_bullet.wav")
self.rect.bottom = 0
max_x = SCREEN_RECT.width - self.rect.width
self.rect.x = random.randint(0, max_x)
def update(self):
super().update()
if self.rect.bottom < 0:
self.kill()
class Buff2(GameSprite):
def init(self):
super().init("./images/bomb_supply.png", 2)
self.music_get = pygame.mixer.Sound("./music/get_bomb.wav")
self.rect.bottom = random.randint(0, 700)
max_x = SCREEN_RECT.width - self.rect.width
self.rect.x = random.randint(0, max_x)
self.ran = random.randint(60, 180) # 在持續(xù)1~3s后消失
def update(self):
super().update()
if self.rect.bottom < 0 or self.index == self.ran:
self.kill()
self.index += 1
class Buff3(Buff2):
def init(self):
super().init()
self.image = pygame.image.load("./images/buff3.png")
self.speedy=3
class bloodline(object):
def init(self, color, x, y, length, width=2, value=2):
self.color = color
self.x = x
self.y = y
self.length = length
self.width = width # 線寬
self.value = value * 1.0 # 血量用浮點數(shù)
self.weight = length / value # 每一滴血表示的距離
self.color_init = color
def update(self, canvas):
if self.length <= self.value * self.weight / 2:
self.color = color_red
else:
self.color = self.color_init
self.bar_rect = pygame.draw.line(canvas, self.color, (self.x, self.y), (self.x + self.length, self.y),
self.width)
class CanvasOver():
def init(self, screen):
self.img_again = pygame.image.load("./images/again.png")
self.img_over = pygame.image.load("./images/gameover.png")
self.rect_again = self.img_again.get_rect()
self.rect_over = self.img_over.get_rect()
self.rect_again.centerx = self.rect_over.centerx = SCREEN_RECT.centerx
self.rect_again.bottom = SCREEN_RECT.centery
self.rect_over.y = self.rect_again.bottom + 20
self.screen = screen
def event_handler(self, event):
if event.type == pygame.MOUSEBUTTONDOWN:
pos = pygame.mouse.get_pos()
if self.rect_again.left < pos[0] < self.rect_again.right and
self.rect_again.top < pos[1] < self.rect_again.bottom:
return 1
elif self.rect_over.left < pos[0] < self.rect_over.right and
self.rect_over.top < pos[1] < self.rect_over.bottom:
return 0
def update(self):
self.screen.blit(self.img_again, self.rect_again)
self.screen.blit(self.img_over, self.rect_over)
score_font = pygame.font.Font("./STCAIYUN.ttf", 50)
image = score_font.render(“SCORE:” + str(int(SCORE)), True, color_gray)
rect = image.get_rect()
rect.centerx, rect.bottom = SCREEN_RECT.centerx, self.rect_again.top - 20
self.screen.blit(image, rect)
import sys
import pygame
pygame.init()
from plane_sprites import *
class PlaneGame(object):
“”“飛機大戰(zhàn)主游戲”""
def init(self):
print(“游戲初始化”)
# 1. 創(chuàng)建游戲的窗口
self.screen = pygame.display.set_mode(SCREEN_RECT.size)
# 創(chuàng)建結(jié)束界面
self.canvas_over = CanvasOver(self.screen)
# 2. 創(chuàng)建游戲的時鐘
self.clock = pygame.time.Clock()
# 3. 調(diào)用私有方法,精靈和精靈組的創(chuàng)建
self.__create_sprites()
# 分數(shù)對象
self.score = GameScore()
# 程序控制指針
self.index = 0
# 音樂bgm
self.bg_music = pygame.mixer.Sound("./music/game_music.ogg")
self.bg_music.set_volume(0.3)
self.bg_music.play(-1)
# 游戲結(jié)束了嗎
self.game_over = False
# 4. 設置定時器事件 - 創(chuàng)建敵機 1s
pygame.time.set_timer(CREATE_ENEMY_EVENT, random.randint(1000, 2000))
pygame.time.set_timer(HERO_FIRE_EVENT, 400)
pygame.time.set_timer(BUFF1_SHOW_UP, random.randint(10000, 20000))
pygame.time.set_timer(BUFF2_SHOW_UP, random.randint(20000, 40000))
pygame.time.set_timer(ENEMY_FIRE_EVENT, 2000)
def __create_sprites(self):
# 創(chuàng)建背景精靈和精靈組
bg1 = Background()
bg2 = Background(True)
self.back_group = pygame.sprite.Group(bg1, bg2)
# 創(chuàng)建敵機的精靈組
self.enemy_group = pygame.sprite.Group()
# 創(chuàng)建英雄的精靈和精靈組
self.hero = Hero()
self.hero_group = pygame.sprite.Group(self.hero)
# 創(chuàng)建敵軍子彈組
self.enemy_bullet_group = pygame.sprite.Group(
# 血條列表
self.bars = []
self.bars.append(self.hero.bar)
# 創(chuàng)建buff組
self.buff1_group = pygame.sprite.Group()
# 創(chuàng)建假象boom組
self.enemy_boom = pygame.sprite.Group()文章來源:http://www.zghlxwxcb.cn/news/detail-470734.html
# bomb列表
self.bombs = []
def start_game(self):
print("游戲開始...")
while True:
# 1. 設置刷新幀率
self.clock.tick(FRAME_PER_SEC)
# 2. 事件監(jiān)聽
self.__event_handler()
# 3. 碰撞檢測
self.__check_collide()
# 4. 更新/繪制精靈組
self.__update_sprites()
# 是否要結(jié)束游戲
if self.game_over:
self.canvas_over.update()
# 5. 更新顯示
pygame.display.update()
def __event_handler(self): # 事件檢測
if self.score.getvalue() > 200+500*self.index:
self.boss = Boss()
self.enemy_group.add(self.boss)
self.bars.append(self.boss.bar)
self.index += 1
for event in pygame.event.get():
# 判斷是否退出游戲
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == CREATE_ENEMY_EVENT:
# 創(chuàng)建敵機精靈將敵機精靈添加到敵機精靈組
if self.score.getvalue() < 20:
enemy = Enemy()
else:
if random.randint(0, 100) % 4:
enemy = Enemy()
else:
enemy = Enemy(2)
self.enemy_group.add(enemy)
self.bars.append(enemy.bar)
elif event.type == HERO_FIRE_EVENT:
for hero in self.hero_group:
hero.fire()
elif event.type == BUFF1_SHOW_UP:
buff1 = Buff1()
self.buff1_group.add(buff1)
elif event.type == BUFF2_SHOW_UP:
if self.hero.bar.color == color_red:#按需分配
buff = Buff3()
else:
buff= Buff2()
self.buff1_group.add(buff)
elif event.type == ENEMY_FIRE_EVENT:
for enemy in self.enemy_group:
if enemy.number >= 2:
enemy.fire()
for bullet in enemy.bullets:
self.enemy_bullet_group.add(bullet)
elif event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
self.bomb_throw()
else:
if self.game_over == True:
flag = self.canvas_over.event_handler(event)
if flag == 1:
self.__start__()
elif flag == 0:
pygame.quit()
sys.exit()
keys_pressed = pygame.key.get_pressed()
# 判斷元組中對應的按鍵索引值 1
if keys_pressed[pygame.K_RIGHT]:
self.heros_move(5)
elif keys_pressed[pygame.K_LEFT]:
self.heros_move(-5)
elif keys_pressed[pygame.K_UP]:
self.heros_move(0, -5)
elif keys_pressed[pygame.K_DOWN]:
self.heros_move(0, 5)
else:
self.heros_move(0, 0)
def heros_move(self, x=0, y=0):
self.hero.speedx = x
self.hero.speedy = y
def bomb_throw(self):
music_use_bomb = pygame.mixer.Sound("./music/use_bomb.wav")
if self.hero.bomb > 0:
music_use_bomb.play()
self.hero.bomb -= 1
self.bombs.pop()
for enemy in self.enemy_group:
if enemy.number < 3:
enemy.bar.length = 0
enemy.isboom = True
else:
enemy.injury = 20
enemy.isboom = True
def __check_collide(self):
# 1. 子彈摧毀敵機
for enemy in self.enemy_group:
for hero in self.hero_group:
for bullet in hero.bullets:
if pygame.sprite.collide_mask(bullet, enemy):
bullet.kill()
enemy.injury = bullet.hity
enemy.isboom = True
if enemy.bar.length <= 0:
self.enemy_group.remove(enemy)
self.enemy_boom.add(enemy)
# 2. 敵機撞毀英雄
for enemy in self.enemy_group:
if pygame.sprite.collide_mask(self.hero, enemy):
if enemy.number < 3:
enemy.bar.length = 0 # 敵機直接死
self.hero.injury = self.hero.bar.value / 4 # 英雄掉四分之一的血
if self.hero.buff1_num > 0:
self.hero.buff1_num -= 1
self.hero.music_degrade.play()
self.enemy_group.remove(enemy)
self.enemy_boom.add(enemy)
enemy.isboom = True
else:
self.hero.bar.length = 0
self.hero.isboom = True
# 子彈摧毀英雄
for bullet in self.enemy_bullet_group:
if pygame.sprite.collide_mask(self.hero, bullet):
bullet.kill()
self.hero.injury = 1
if self.hero.buff1_num > 0:
self.hero.music_degrade.play()
if self.hero.buff1_num == 5:
self.mate1.kill()
self.mate2.kill()
self.hero.buff1_num -= 1
self.hero.isboom = True
if not self.hero.alive():
self.hero.rect.right = -10 # 把英雄移除屏幕
if self.hero.buff1_num == 5:
self.mate1.rect.right = -10
self.mate2.rect.right = -10
self.game_over = True
# 3.buff吸收
for buff in self.buff1_group:
if pygame.sprite.collide_mask(self.hero, buff):
buff.music_get.play()
if buff.speedy == 1: # 用速度來區(qū)分
if self.hero.buff1_num < 6:
self.hero.buff1_num += 1
self.hero.music_upgrade.play()
if self.hero.buff1_num == 5:
self.team_show()
elif buff.speedy==2:
self.hero.bomb += 1
image = pygame.image.load("./images/bomb.png")
self.bombs.append(image)
elif buff.speedy==3:
if self.hero.bar.length < self.hero.bar.weight*self.hero.bar.value:
self.hero.bar.length += self.hero.bar.weight*self.hero.bar.value
buff.kill()
def team_show(self):
self.mate1 = Heromate(-1)
self.mate2 = Heromate(1)
self.mate1.image = pygame.image.load("./images/life.png")
self.mate1.rect = self.mate1.image.get_rect()
self.mate2.image = pygame.image.load("./images/life.png")
self.mate2.rect = self.mate2.image.get_rect()
self.hero_group.add(self.mate1)
self.hero_group.add(self.mate2)
def __update_sprites(self):
self.back_group.update()
self.back_group.draw(self.screen)
self.enemy_group.update()
self.enemy_group.draw(self.screen)
self.enemy_boom.update()
self.enemy_boom.draw(self.screen)
self.heros_update()
self.hero_group.draw(self.screen)
for hero in self.hero_group:
hero.bullets.update()
hero.bullets.draw(self.screen)
self.buff1_group.update()
self.buff1_group.draw(self.screen)
self.bars_update()
self.bombs_update()
self.enemy_bullet_group.update()
self.enemy_bullet_group.draw(self.screen)
self.score_show()
def heros_update(self):
for hero in self.hero_group:
if hero.number == 1:
hero.rect.bottom = self.hero.rect.bottom
hero.rect.left = self.hero.rect.right
if hero.number == -1:
hero.rect.bottom = self.hero.rect.bottom
hero.rect.right = self.hero.rect.left
hero.update()
def bars_update(self):
for bar in self.bars:
if bar.length > 0:
bar.update(self.screen)
else:
self.bars.remove(bar)
def bullet_enemy_update(self):
for enemy in self.enemy_group:
enemy.bullets.update()
enemy.bullets.draw(self.screen)
def bombs_update(self):
i = 1
for bomb in self.bombs:
self.screen.blit(bomb, (0, 700 - (bomb.get_rect().height) * i))
i += 1
def score_show(self):
score_font = pygame.font.Font("./STCAIYUN.ttf", 33)
image = score_font.render("SCORE:" + str(int(self.score.getvalue())), True, color_gray)
rect = image.get_rect()
rect.bottom, rect.right = 700, 480
self.screen.blit(image, rect)
@staticmethod
def __start__():
# 創(chuàng)建游戲?qū)ο? game = PlaneGame()
# 啟動游戲
game.start_game()
if name == ‘main’:
PlaneGame.start()文章來源地址http://www.zghlxwxcb.cn/news/detail-470734.html
到了這里,關于Python實驗,用pygame做飛機大戰(zhàn)游戲設計的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!