python项目:飞机大战(爆炸效果,血条,音效,buff加成,boss,菜单,完整详细注释的源码)
文章目錄
- 一. 總體概覽
- 基本功能
- 細(xì)節(jié)部分(全部可以自定義)
- 可增添需求
- 二,技術(shù)框架
- 核心技術(shù)概述
- 1.游戲的初始化和退出
- 2 理解游戲中的坐標(biāo)系
- 3 創(chuàng)建游戲主窗口
- 4. 理解 **圖像** 并實(shí)現(xiàn)圖像繪制
- 5. 游戲中的動畫實(shí)現(xiàn)原理
- 游戲循環(huán)的作用
- 游戲時鐘
- 6. 在游戲循環(huán)中 監(jiān)聽 事件
- 事件 `event`
- 監(jiān)聽
- 代碼實(shí)現(xiàn)
- 7. 理解 **精靈** 和 **精靈組**
- 精靈 和 精靈
- 精靈
- 精靈組
- 整體框架
- 三,實(shí)踐中遇到的問題和解決辦法
- 1.敵機(jī)死后,子彈連帶的消失
- 2.子彈和敵機(jī)多次撞擊
- 3.進(jìn)行了update卻不顯示
- 4. 想方設(shè)法把一個Sprite或者rect或者image進(jìn)行清除操作
- 5. 為什么英雄死掉了,還是會發(fā)生碰撞檢測
- 6, 如何按鍵不放,移動不止
- 7,不知道全局變量如何使用
- 8.明明畫在屏幕上也更新了可就是看不到
- 三,源代碼
- 注釋超級詳細(xì)
- 方法比較簡單,很容易看懂
- 易修改,易擴(kuò)展,可定制化參數(shù)
- 四, 總結(jié)和下載
一. 總體概覽
話不多說,先看效果圖,動作是有聲音的,但是放不出來
看圖片應(yīng)該大體有個了解,然后我再具體介紹下,游戲有哪些功能和細(xì)節(jié)
基本功能
4.1子彈buff最多吃5個,每吃一個子彈數(shù)目或者威力提高,吃到第五個召喚"最強(qiáng)形態(tài)"
4.2炸彈buff可以無限吃,當(dāng)然出現(xiàn)幾率比較小,吃到的炸彈在屏幕左下角顯示,空格鍵引爆一顆炸彈,毀掉當(dāng)前所有敵軍飛機(jī),boss損血
4.3補(bǔ)血buff,一次補(bǔ)滿英雄血條
細(xì)節(jié)部分(全部可以自定義)
可增添需求
(簡單重復(fù)性工作可讓細(xì)節(jié)更加到位,代碼看明白后可以自行添加,這是個無底洞,提供個思路)
二,技術(shù)框架
主要就是python類和pygame模塊的運(yùn)用,有項(xiàng)目文件后直接安裝pygame庫就可以運(yùn)行了
核心技術(shù)概述
1.游戲的初始化和退出
- 要使用 pygame 提供的所有功能之前,需要調(diào)用 init 方法
- 在游戲結(jié)束前需要調(diào)用一下 quit 方法
| pygame.init() | 導(dǎo)入并初始化所有 pygame 模塊,使用其他模塊之前,必須先調(diào)用 init 方法 |
| pygame.quit() | 卸載所有 pygame 模塊,在游戲結(jié)束之前調(diào)用! |
| import pygame |
pygame.init()這個模塊初始化一定不能省略
游戲代碼…
pygame.quit()
2 理解游戲中的坐標(biāo)系
-
坐標(biāo)系
- 原點(diǎn) 在 左上角 (0, 0)
- x 軸 水平方向向 右,逐漸增加
- y 軸 垂直方向向 下,逐漸增加
-
在游戲中,所有可見的元素 都是以 矩形區(qū)域 來描述位置的
-
要描述一個矩形區(qū)域有四個要素:(x, y) (width, height)
-
pygame 專門提供了一個類 pygame.Rect 用于描述 矩形區(qū)域
3 創(chuàng)建游戲主窗口
- pygame 專門提供了一個 模塊 pygame.display 用于創(chuàng)建、管理 游戲窗口
| pygame.display.set_mode() | 初始化游戲顯示窗口 |
| pygame.display.update() | 刷新屏幕內(nèi)容顯示,稍后使用 |
set_mode 方法
set_mode(resolution=(0,0), flags=0, depth=0) -> Surface4. 理解 圖像 并實(shí)現(xiàn)圖像繪制
- 在游戲中,能夠看到的 游戲元素 大多都是 圖像
- 圖像文件 初始是保存在磁盤上的,如果需要使用,第一步 就需要 被加載到內(nèi)存
- 要在屏幕上 看到某一個圖像的內(nèi)容,需要按照三個步驟:
- 使用 pygame.image.load() 加載圖像的數(shù)據(jù)
- 使用 游戲屏幕 對象,調(diào)用 blit 方法 將圖像繪制到指定位置
- 調(diào)用 pygame.display.update() 方法更新整個屏幕的顯示
- 透明圖像
- png 格式的圖像是支持 透明 的
- 在繪制圖像時,透明區(qū)域 不會顯示任何內(nèi)容
- 但是如果下方已經(jīng)有內(nèi)容,會 透過 透明區(qū)域 顯示出來
5. 游戲中的動畫實(shí)現(xiàn)原理
- 跟 電影 的原理類似,游戲中的動畫效果,本質(zhì)上是 快速 的在屏幕上繪制 圖像
- 電影是將多張 靜止的電影膠片 連續(xù)、快速的播放,產(chǎn)生連貫的視覺效果!
- 一般在電腦上 每秒繪制 60 次,就能夠達(dá)到非常 連續(xù) 高品質(zhì) 的動畫效果
- 每次繪制的結(jié)果被稱為 幀 Frame
游戲循環(huán)的開始 就意味著 游戲的正式開始
游戲循環(huán)的作用
- 每隔 1 / 60 秒 移動一下所有圖像的位置
- 調(diào)用 pygame.display.update() 更新屏幕顯示
游戲時鐘
- pygame 專門提供了一個類 pygame.time.Clock 可以非常方便的設(shè)置屏幕繪制速度 —— 刷新幀率
- 要使用 時鐘對象 需要兩步:
- 1)在 游戲初始化 創(chuàng)建一個 時鐘對象
- 2)在 游戲循環(huán) 中讓時鐘對象調(diào)用 tick(幀率) 方法
- tick 方法會根據(jù) 上次被調(diào)用的時間,自動設(shè)置 游戲循環(huán) 中的延時
6. 在游戲循環(huán)中 監(jiān)聽 事件
事件 event
- 就是游戲啟動后,用戶針對游戲所做的操作
- 例如:點(diǎn)擊關(guān)閉按鈕,點(diǎn)擊鼠標(biāo),按下鍵盤…
監(jiān)聽
- 在 游戲循環(huán) 中,判斷用戶 具體的操作
只有 捕獲 到用戶具體的操作,才能有針對性的做出響應(yīng)
代碼實(shí)現(xiàn)
- pygame 中通過 pygame.event.get() 可以獲得 用戶當(dāng)前所做動作 的 事件列表
- 用戶可以同一時間做很多事情
- 提示:這段代碼非常的固定,幾乎所有的 pygame 游戲都 大同小異!
7. 理解 精靈 和 精靈組
精靈 和 精靈
- 為了簡化開發(fā)步驟,pygame 提供了兩個類
- pygame.sprite.Sprite —— 存儲 圖像數(shù)據(jù) image 和 位置 rect 的 對象
- pygame.sprite.Group
精靈
-
在游戲開發(fā)中,通常把 顯示圖像的對象 叫做精靈 Sprite
-
精靈 需要 有 兩個重要的屬性
- image 要顯示的圖像
- rect 圖像要顯示在屏幕的位置
-
默認(rèn)的 update() 方法什么事情也沒做
- 子類可以重寫此方法,在每次刷新屏幕時,更新精靈位置
-
注意:pygame.sprite.Sprite 并沒有提供 image 和 rect 兩個屬性
- 需要程序員從 pygame.sprite.Sprite 派生子類
- 并在 子類 的 初始化方法 中,設(shè)置 image 和 rect 屬性
精靈組
- 一個 精靈組 可以包含多個 精靈 對象
- 調(diào)用 精靈組 對象的 update() 方法
- 可以 自動 調(diào)用 組內(nèi)每一個精靈 的 update() 方法
- 調(diào)用 精靈組 對象的 draw(屏幕對象) 方法
- 可以將 組內(nèi)每一個精靈 的 image 繪制在 rect 位置
整體框架
三,實(shí)踐中遇到的問題和解決辦法
1.敵機(jī)死后,子彈連帶的消失
因?yàn)樽訌椊M是敵軍對象的成員,子彈不是
就是在主函數(shù)需要敵軍的子彈再加到一個組,而且所有敵軍的子彈加到一起更更新更加方便,這樣不用擔(dān)心敵機(jī)毀掉了,他們的子彈對象也訪問不了了.
2.子彈和敵機(jī)多次撞擊
由于播放爆炸動畫采用的方法是被撞毀時,先不移除精靈組,然后更改該對象圖片,知道圖片輪完了才kill(),這就導(dǎo)致進(jìn)行下一次循環(huán),對象還沒kill(),kill()了就不能進(jìn)行輪播.
思考一:
撞毀的時候新建循環(huán)把爆炸圖片畫在屏幕上,
行不通,第循環(huán)一次只能更新一幀圖片,如果你要更新多幀那么其他精靈就會靜止.
思考二:
撞毀時候,先移除精靈組,然后用變量儲存,進(jìn)行最初更新的方法.實(shí)驗(yàn)證明可行.
3.進(jìn)行了update卻不顯示
混淆draw和display.update
首先一個精靈的update方法讓圖像有改變
精靈組的draw方法調(diào)用screen的blit方法畫到屏幕上
這時候屏幕畫面殘留在上一幀
只有display更新了才能看到
4. 想方設(shè)法把一個Sprite或者rect或者image進(jìn)行清除操作
其實(shí)pygam你們只有貼上去,沒有"撕下來"
想要看不見他,兩種方法如果是精靈,skill()從所有精靈組里面刪除,如果只是單純的image和rect,直接從他們的list里面remove,這樣就不會被blit,實(shí)際上屏幕在更新,如果你想要看到,就要畫在在更新的每一幀上面,之后如果不再用到它,python自己會進(jìn)行回收.
同樣的道理,如果希望一個壞人消失,最好的辦法不是你去殺死他,而是從你所在的集體里面孤立排除他,這樣你就再也見不到他了
5. 為什么英雄死掉了,還是會發(fā)生碰撞檢測
這是因?yàn)?雖然我們把英雄加入英雄隊伍,但是隊伍中英雄很少,為了方便我們碰撞的時候不是從隊伍中取直接就用該英雄對象進(jìn)行檢測,這時候,英雄skill()了,但是rect并沒有丟失,
記住skill(),只是把他從需要顯示或者操作群體中把他刪除了,但是這個對象并沒有被立即回收,它的rect還是在,還能用于碰撞檢測
6, 如何按鍵不放,移動不止
方向鍵監(jiān)聽有兩種方式
按一下
按下
返回所有按鍵的元組,如果某個鍵被按下,對應(yīng)的值會是1
7,不知道全局變量如何使用
python里面的全局常量和其他語言一樣是沒有歧義的,但是全局變量就不一樣了,因?yàn)閜ython定義變量不用定義類型,只有在賦值的時候才知道,所以在函數(shù)里面使用全局變量,無法保證兩個變量是一樣的,所以在函數(shù)里面需要用global聲明一下這個變量是我開始設(shè)的這個全局變量,不是又重新定義了一個局部變量,
同樣的道理,全局變量也不能跨模塊調(diào)用,即使import了也只能用他的初始值,所以可以建立一個全局變量操作類,用來獲取和修改全局變量.
8.明明畫在屏幕上也更新了可就是看不到
注意更新的順序影響圖像的上下層關(guān)系
三,源代碼
注釋超級詳細(xì)
方法比較簡單,很容易看懂
易修改,易擴(kuò)展,可定制化參數(shù)
import random import pygame pygame.init() # ************************************************************** # FileName: plane_sprites.py*************************************** # Author: Junieson ********************************************* # Version: 2019.8.12 ****************************************** # **************************************************************** # 分?jǐn)?shù) 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)建敵機(jī)的定時器常量,自定義用戶事件,其實(shí)就是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 + 5class GameScore(object):global SCOREdef __init__(self):self.score = 0passdef getvalue(self):self.score = SCOREreturn self.scoreclass GameSprite(pygame.sprite.Sprite):"""飛機(jī)大戰(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 = speedyself.speedx = speedxself.injury = 1self.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.speedyself.rect.x += self.speedxself.bar.x = self.rect.xself.bar.y = self.rect.y - 10class Background(GameSprite):"""游戲背景精靈"""def __init__(self, is_alt=False):# 1. 調(diào)用父類方法實(shí)現(xiàn)精靈的創(chuàng)建(image/rect/speed)super().__init__("./images/background.png")# 2. 判斷是否是交替圖像,如果是,需要設(shè)置初始位置if is_alt:self.rect.y = -self.rect.heightdef update(self):# 1. 調(diào)用父類的方法實(shí)現(xiàn)super().update()# 2. 判斷是否移出屏幕,如果移出屏幕,將圖像設(shè)置到屏幕的上方if self.rect.y >= SCREEN_RECT.height:self.rect.y = -self.rect.heightclass 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 = 240self.y = 200self.isboom = Falseself.number = 3self.index1 = 1 # 控制動畫速度self.index2 = 0self.index3 = 0self.index4 = 0self.injury = 1self.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. 設(shè)置精靈的位置bullet.rect.centerx = self.rect.centerxbullet.rect.y = self.rect.bottomif j == 2:bullet.speedx = 0else:bullet.speedx = (-1) ** j * ((j - 1) // 2) * 1self.bullets.add(bullet)def update(self):# 左右移global SCOREif self.index4 % 2 == 0: # 降低幀速率,注意這兩個指針不能一樣# 內(nèi)部為左右移動大概50像素if self.index3 % 50 == 0 and (self.index3 // 50) % 2 == 1:self.speedx = -self.speedxself.rect.x += self.speedxself.index3 += 1self.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.weightif self.bar.length <= 0: # 此時滿足爆炸的條件了self.music_fly.stop()if self.index2 == 0:self.music_boom.play()if self.index2 < 29: # 4*7+1self.image = pygame.image.load("./images/enemy3_down" + str(self.index2 // 7) + ".png")# 這個地方之所以要整除4是為了減慢爆炸的速度,如果按照update的頻率60hz就太快了self.index2 += 1else:self.kill()SCORE += self.bar.valueelse:self.isboom = False # 否則還不能死class Enemy(GameSprite):"""敵機(jī)精靈"""def __init__(self, num=1):self.number = num# 1. 調(diào)用父類方法,創(chuàng)建敵機(jī)精靈,同時指定敵機(jī)圖片super().__init__("./images/enemy" + str(num) + ".png")# musicif num == 1:self.music_boom = pygame.mixer.Sound("./music/enemy1_down.wav")else:self.music_boom = pygame.mixer.Sound("./music/enemy2_down.wav")# 2. 指定敵機(jī)的初始隨機(jī)速度 1 ~ 3self.speedy = random.randint(1, 3)# 3. 指定敵機(jī)的初始隨機(jī)位置self.rect.bottom = 0max_x = SCREEN_RECT.width - self.rect.widthself.rect.x = random.randint(0, max_x)# 4.爆炸效果self.isboom = Falseself.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. 設(shè)置精靈的位置bullet.rect.bottom = self.rect.bottom + i * 20bullet.rect.centerx = self.rect.centerx# 3. 將精靈添加到精靈組self.bullets.add(bullet)def update(self):global SCORE# 1. 調(diào)用父類方法,保持垂直方向的飛行super().update()# 2. 判斷是否飛出屏幕,如果是,需要從精靈組刪除敵機(jī)if self.rect.y > SCREEN_RECT.height:# print("飛出屏幕,需要從精靈組刪除...")# kill方法可以將精靈從所有精靈組中移出,精靈就會被自動銷毀self.kill()self.bar.length = 0if self.isboom:self.bar.length -= self.bar.weight * self.injuryif self.bar.length <= 0:if self.index == 0: # 保證只響一次self.music_boom.play()if self.index < 17: # 4*4+1self.image = pygame.image.load("./images/enemy" + str(self.number) + "_down" + str(self.index // 4) + ".png")# 這個地方之所以要整除4是為了減慢爆炸的速度,如果按照update的頻率60hz就太快了self.index += 1else:self.kill()SCORE += self.bar.valueelse:self.isboom = Falseclass Hero(GameSprite):"""英雄精靈"""def __init__(self):# 1. 調(diào)用父類方法,設(shè)置image&speedsuper().__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. 設(shè)置英雄的初始位置self.rect.centerx = SCREEN_RECT.centerxself.rect.bottom = SCREEN_RECT.bottom - 120# 3. 創(chuàng)建子彈的精靈組self.bullets = pygame.sprite.Group()# 4.爆炸self.isboom = Falseself.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 = 0def update(self):# 英雄在水平方向移動和血條不同步,特殊self.rect.y += self.speedyself.rect.x += self.speedx# 控制英雄不能離開屏幕if self.rect.x < 0:self.rect.x = 0elif self.rect.right > SCREEN_RECT.right:self.rect.right = SCREEN_RECT.rightelif self.rect.y < 0:self.rect.y = 0elif 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.weightif self.bar.length <= 0: # 此時滿足爆炸的條件了if self.index2 == 0:self.music_down.play()if self.index2 < 17: # 4*4+1self.image = pygame.image.load("./images/me_destroy_" + str(self.index2 // 4) + ".png")# 這個地方之所以要整除4是為了減慢爆炸的速度,如果按照update的頻率60hz就太快了self.index2 += 1else:self.kill()else:self.isboom = False # 否則還不能死# 發(fā)射子彈def fire(self):if self.buff1_num == 0:for i in range(0, 1):# 1. 創(chuàng)建子彈精靈bullet = Bullet()# 2. 設(shè)置精靈的位置bullet.rect.bottom = self.rect.y - i * 20bullet.rect.centerx = self.rect.centerx# 3. 將精靈添加到精靈組self.bullets.add(bullet)elif self.buff1_num <= 3:for i in (0, 1):# 1. 創(chuàng)建子彈精靈for j in range(2, self.buff1_num + 3):bullet = Bullet(2, -3)# 2. 設(shè)置精靈的位置bullet.rect.bottom = self.rect.y - i * 20if (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.centerxelse:bullet.rect.centerx = self.rect.centerx + (-1) ** j * 15 * ((j - 1) // 2)# 3. 將精靈添加到精靈組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. 設(shè)置精靈的位置bullet.rect.bottom = self.rect.yif j == 2:bullet.rect.centerx = self.rect.centerxelse: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 = numdef update(self):if self.rect.right > SCREEN_RECT.right:self.rect.right = SCREEN_RECT.rightif self.rect.x < 0:self.rect.x = 0if self.rect.y < 0:self.rect.y = 0elif self.rect.bottom > SCREEN_RECT.bottom:self.rect.bottom = SCREEN_RECT.bottomdef fire(self):for i in range(0, 1, 2):# 1. 創(chuàng)建子彈精靈bullet = Bullet()# 2. 設(shè)置精靈的位置bullet.rect.bottom = self.rect.y - i * 20bullet.rect.centerx = self.rect.centerx# 3. 將精靈添加到精靈組self.bullets.add(bullet)class Bullet(GameSprite):"""子彈精靈"""def __init__(self, color=1, speedy=-2, speedx=0):# 調(diào)用父類方法,設(shè)置子彈圖片,設(shè)置初始速度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 = 0max_x = SCREEN_RECT.width - self.rect.widthself.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.widthself.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 += 1class Buff3(Buff2):def __init__(self):super().__init__()self.image = pygame.image.load("./images/buff3.png")self.speedy=3class bloodline(object):def __init__(self, color, x, y, length, width=2, value=2):self.color = colorself.x = xself.y = yself.length = lengthself.width = width # 線寬self.value = value * 1.0 # 血量用浮點(diǎn)數(shù)self.weight = length / value # 每一滴血表示的距離self.color_init = colordef update(self, canvas):if self.length <= self.value * self.weight / 2:self.color = color_redelse:self.color = self.color_initself.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.centerxself.rect_again.bottom = SCREEN_RECT.centeryself.rect_over.y = self.rect_again.bottom + 20self.screen = screendef 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 1elif self.rect_over.left < pos[0] < self.rect_over.right and \self.rect_over.top < pos[1] < self.rect_over.bottom:return 0def 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 - 20self.screen.blit(image, rect) import sys import pygamepygame.init() from plane_sprites import * # ************************************************************** # FileName: plane_main.py*************************************** # Author: Junieson ********************************************* # Version: 2019.8.12 ****************************************** # **************************************************************** class PlaneGame(object):"""飛機(jī)大戰(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()# 分?jǐn)?shù)對象self.score = GameScore()# 程序控制指針self.index = 0# 音樂bgmself.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. 設(shè)置定時器事件 - 創(chuàng)建敵機(jī) 1spygame.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)建敵機(jī)的精靈組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()# bomb列表self.bombs = []def start_game(self):print("游戲開始...")while True:# 1. 設(shè)置刷新幀率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 += 1for event in pygame.event.get():# 判斷是否退出游戲if event.type == pygame.QUIT:pygame.quit()sys.exit()if event.type == CREATE_ENEMY_EVENT:# 創(chuàng)建敵機(jī)精靈將敵機(jī)精靈添加到敵機(jī)精靈組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()# 判斷元組中對應(yīng)的按鍵索引值 1if 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 = xself.hero.speedy = ydef 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 -= 1self.bombs.pop()for enemy in self.enemy_group:if enemy.number < 3:enemy.bar.length = 0enemy.isboom = Trueelse:enemy.injury = 20enemy.isboom = Truedef __check_collide(self):# 1. 子彈摧毀敵機(jī)for enemy in self.enemy_group:for hero in self.hero_group:for bullet in hero.bullets:if pygame.sprite.collide_mask(bullet, enemy): # 這種碰撞檢測可以精確到像素去掉alpha遮罩的那種哦bullet.kill()enemy.injury = bullet.hityenemy.isboom = Trueif enemy.bar.length <= 0:self.enemy_group.remove(enemy)self.enemy_boom.add(enemy)# 2. 敵機(jī)撞毀英雄for enemy in self.enemy_group:if pygame.sprite.collide_mask(self.hero, enemy):if enemy.number < 3:enemy.bar.length = 0 # 敵機(jī)直接死self.hero.injury = self.hero.bar.value / 4 # 英雄掉四分之一的血if self.hero.buff1_num > 0:self.hero.buff1_num -= 1self.hero.music_degrade.play()self.enemy_group.remove(enemy)self.enemy_boom.add(enemy)enemy.isboom = Trueelse:self.hero.bar.length = 0self.hero.isboom = True# 子彈摧毀英雄for bullet in self.enemy_bullet_group:if pygame.sprite.collide_mask(self.hero, bullet):bullet.kill()self.hero.injury = 1if 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 -= 1self.hero.isboom = Trueif not self.hero.alive():self.hero.rect.right = -10 # 把英雄移除屏幕if self.hero.buff1_num == 5:self.mate1.rect.right = -10self.mate2.rect.right = -10self.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 += 1self.hero.music_upgrade.play()if self.hero.buff1_num == 5:self.team_show()elif buff.speedy==2:self.hero.bomb += 1image = 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.valuebuff.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.bottomhero.rect.left = self.hero.rect.rightif hero.number == -1:hero.rect.bottom = self.hero.rect.bottomhero.rect.right = self.hero.rect.lefthero.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 = 1for bomb in self.bombs:self.screen.blit(bomb, (0, 700 - (bomb.get_rect().height) * i))i += 1def 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, 480self.screen.blit(image, rect)@staticmethoddef __start__():# 創(chuàng)建游戲?qū)ο?/span>game = PlaneGame()# 啟動游戲game.start_game()if __name__ == '__main__':PlaneGame.__start__()四, 總結(jié)和下載
這次的項(xiàng)目實(shí)踐,讓我對python面相對象程序設(shè)計有了更深的體會,也讓我感受到了python語言簡潔優(yōu)雅的美感,如果你覺得還行的話,可以拿去小練一下手,如果有什么問題可以在評論區(qū)留言,我會在第一時間回復(fù),
敲打不易,順手點(diǎn)個贊吧,
(づ ̄3 ̄)づ╭?~.鏈接:https://github.com/Junieson/PlaneGame
總結(jié)
以上是生活随笔為你收集整理的python项目:飞机大战(爆炸效果,血条,音效,buff加成,boss,菜单,完整详细注释的源码)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Web服务器配置
- 下一篇: 运营好一个自媒体公众号,你还需要一个错别