pygame面向?qū)ο蟮娘w行小鳥實現(xiàn)(Flappy bird)
一些想法
自學(xué)python已經(jīng)有快三個月了 最近這段時間沒有怎么寫過python 很多東西反而又遺忘了 準(zhǔn)備翻以前的筆記復(fù)習(xí)一下在博客上記錄下來 自己也沒能夠做出什么厲害的東西 小鳥游戲算是目前自己寫的最好的一個代碼了
基本游戲界面就是這樣
分析需要的功能
我的構(gòu)思是將游戲分成三個部分
- 初始游戲菜單界面
- 游戲進(jìn)行界面
- 游戲結(jié)束界面
游戲里的角色和道具則使用類
- 小鳥類
- 管道類
因為是使用pygame模塊 我對這個模塊也很不熟悉 很多功能都是論壇參考其他大神的 比如
pygame.transform 里面的各種變化功能 pygame.sprite 精靈模塊里面的方法
構(gòu)建整體框架
1.導(dǎo)入pygame和random
pygame擁有豐富的制作游戲的功能
random是隨機(jī)模塊 游戲里各種隨機(jī)事件就是通過這個模塊功能實現(xiàn)
import pygame import random
2.我們寫一個小的項目之前 需要將每個功能分成不同的代碼塊
定義的變量都寫到最上面
MAP_WIDTH = 288 # 地圖大小 MAP_HEIGHT = 512 FPS = 30 # 刷新率 PIPE_GAPS = [110, 120, 130, 140, 150, 160] # 缺口的距離 有這6個隨機(jī)距離 # 寫的途中的全局變量都可以寫在最上面
全局變量
我一般喜歡使用大寫來區(qū)分
3.游戲窗口的設(shè)置
pygame.init() # 進(jìn)行初始化 SCREEN = pygame.display.set_mode((MAP_WIDTH, MAP_HEIGHT)) # 屏幕大小 pygame.display.set_caption('飛行小鳥') # 標(biāo)題 CLOCK = pygame.time.Clock()
4.加載素材
加載游戲圖片和音樂
SPRITE_FILE = './images' IMAGES = {} IMAGES['guide'] = pygame.image.load(SPRITE_FILE + 'guide.png') IMAGES['gameover'] = pygame.image.load(SPRITE_FILE + 'gameover.png') IMAGES['floor'] = pygame.image.load(SPRITE_FILE + 'floor.png') SPRITE_SOUND = './audio/' SOUNDS = {} SOUNDS['start'] = pygame.mixer.Sound(SPRITE_SOUND + 'start.wav') SOUNDS['die'] = pygame.mixer.Sound(SPRITE_SOUND + 'die.wav') SOUNDS['hit'] = pygame.mixer.Sound(SPRITE_SOUND + 'hit.wav') SOUNDS['score'] = pygame.mixer.Sound(SPRITE_SOUND + 'score.wav')
5.執(zhí)行函數(shù)
就是執(zhí)行程序的函數(shù)
def main(): menu_window() result = game_window() end_window(result)
6.程序入口
if __name__ == '__main__': main()
7.我將游戲分成了三個界面
- 初始游戲菜單界面
- 游戲進(jìn)行界面
- 游戲結(jié)束界面
def menu_window(): pass def game_window(): pass def end_window(result): pass # 這里就是寫運行三種游戲界面的代碼
8.因為要顯示游戲得分
所以專門寫一個方法在游戲主界面代碼里面直接調(diào)用這個方法 讓代碼不會顯得冗余
9.最后就是我們游戲角色和道具的類方法
- 小鳥類
- 管道類
class Bird(pygame.sprite.Sprite): def __init__(self, x, y): # super(Bird, self).__init__(x, y) pygame.sprite.Sprite.__init__(self) pass def update(self, flap=False): pass def go_die(self): pass class Pipe(pygame.sprite.Sprite): def __init__(self, x, y, upwards=True): pygame.sprite.Sprite.__init__(self) pass def update(self): pass
我們把整體框架搭建好之后 就可以著手完善代碼
著手完整代碼
""" Project: pygame Creator: stan Z Create time: 2021-03-08 19:37 IDE: PyCharm Introduction: """ import pygame import random ######################################## 定義變量 MAP_WIDTH = 288 # 地圖大小 MAP_HEIGHT = 512 FPS = 30 # 刷新率 PIPE_GAPS = [90, 100, 110, 120, 130, 140] # 缺口的距離 有這6個隨機(jī)距離 # PIPE_GAPS1 = [] PIPE_HEIGHT_RANGE = [int(MAP_HEIGHT * 0.3), int(MAP_HEIGHT * 0.7)] # 管道長度范圍 PIPE_DISTANCE = 120 # 管道之間距離 ######################################## 游戲基本設(shè)置 pygame.init() # 進(jìn)行初始化 SCREEN = pygame.display.set_mode((MAP_WIDTH, MAP_HEIGHT)) # 調(diào)用窗口設(shè)置屏幕大小 pygame.display.set_caption('飛行小鳥byStanZ') # 標(biāo)題 CLOCK = pygame.time.Clock() # 建立時鐘 ######################################## 加載素材 SPRITE_FILE = './images' # 列表推導(dǎo)式 獲得三種不同的鳥和三種狀態(tài) BIRDS = [[f'{SPRITE_FILE}{bird}-{move}.png' for move in ['up', 'mid', 'down']] for bird in ['red', 'blue', 'yellow']] BGPICS = [SPRITE_FILE + 'day.png', SPRITE_FILE + 'night.png'] PIPES = [SPRITE_FILE + 'green-pipe.png', SPRITE_FILE + 'red-pipe.png'] NUMBERS = [f'{SPRITE_FILE}{n}.png' for n in range(10)] # 將圖片設(shè)置成一個大字典 里面通過key-value存不同的場景圖 IMAGES = {} IMAGES['numbers'] = [pygame.image.load(number) for number in NUMBERS] # 數(shù)字素材有10張 因此遍歷 IMAGES['guide'] = pygame.image.load(SPRITE_FILE + 'guide.png') IMAGES['gameover'] = pygame.image.load(SPRITE_FILE + 'gameover.png') IMAGES['floor'] = pygame.image.load(SPRITE_FILE + 'floor.png') # 地板的高是一個很常用的變量 因此我們專門拿出來 FLOOR_H = MAP_HEIGHT - IMAGES['floor'].get_height() # 屏幕高減去floor圖片的高 就是他在屏幕里的位置 SPRITE_SOUND = './sound' SOUNDS = {} # 同理聲音素材也這樣做 SOUNDS['start'] = pygame.mixer.Sound(SPRITE_SOUND + 'start.wav') SOUNDS['die'] = pygame.mixer.Sound(SPRITE_SOUND + 'die.wav') SOUNDS['hit'] = pygame.mixer.Sound(SPRITE_SOUND + 'hit.wav') SOUNDS['score'] = pygame.mixer.Sound(SPRITE_SOUND + 'score.wav') SOUNDS['flap'] = pygame.mixer.Sound(SPRITE_SOUND + 'flap.wav') SOUNDS['death'] = pygame.mixer.Sound(SPRITE_SOUND + 'death.wav') SOUNDS['main'] = pygame.mixer.Sound(SPRITE_SOUND + 'main_theme.ogg') SOUNDS['world_clear'] = pygame.mixer.Sound(SPRITE_SOUND + 'world_clear.wav') # 執(zhí)行函數(shù) def main(): while True: IMAGES['bgpic'] = pygame.image.load(random.choice(BGPICS)) # random的choice方法可以隨機(jī)從列表里返回一個元素 白天或者黑夜 IMAGES['bird'] = [pygame.image.load(frame) for frame in random.choice(BIRDS)] # 列表推導(dǎo)式 鳥也是隨機(jī) pipe = pygame.image.load(random.choice(PIPES)) IMAGES['pipe'] = [pipe, pygame.transform.flip(pipe, False, True)] # flip是翻轉(zhuǎn) 將管道放下面和上面 Flase水平不動,True上下翻轉(zhuǎn) SOUNDS['start'].play() # SOUNDS['main'].play() menu_window() result = game_window() end_window(result) def menu_window(): SOUNDS['world_clear'].play() floor_gap = IMAGES['floor'].get_width() - MAP_WIDTH # 地板間隙 336 - 288 = 48 floor_x = 0 # 標(biāo)題位置 guide_x = (MAP_WIDTH - IMAGES['guide'].get_width()) / 2 guide_y = MAP_HEIGHT * 0.12 # 小鳥位置 bird_x = MAP_WIDTH * 0.2 bird_y = MAP_HEIGHT * 0.5 - IMAGES['bird'][0].get_height() / 2 bird_y_vel = 1 # 小鳥飛行的速率 按y坐標(biāo)向下 max_y_shift = 50 # 小鳥飛行的最大幅度 y_shift = 0 # 小鳥起始幅度為0 idx = 0 # 小鳥翅膀煽動頻率 frame_seq = [0] * 5 + [1] * 5 + [2] * 5 + [1] * 5 # 控制小鳥翅膀運動上中下 while True: for event in pygame.event.get(): # 監(jiān)控行為 if event.type == pygame.QUIT: quit() elif event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE: return if floor_x <= -floor_gap: # 當(dāng)?shù)匕迮艿阶畲箝g隔的時候 floor_x = floor_x + floor_gap # 刷新地板的x軸 else: floor_x -= 4 # 地板 x軸的移動速度 if abs(y_shift) == max_y_shift: # 如果y_shift的絕對值 = 最大幅度 bird_y_vel *= -1 # 調(diào)轉(zhuǎn)方向飛 同時飛行速度為1 else: bird_y += bird_y_vel y_shift += bird_y_vel # 小鳥y軸正負(fù)交替 上下飛 # 小鳥翅膀 idx += 1 # 翅膀煽動頻率 idx %= len(frame_seq) # 通過取余得到 0 1 2 frame_index = frame_seq[idx] # 小鳥圖片的下標(biāo) 就是翅膀的狀態(tài) SCREEN.blit(IMAGES['bgpic'], (0, 0)) SCREEN.blit(IMAGES['floor'], (floor_x, FLOOR_H)) SCREEN.blit(IMAGES['guide'], (guide_x, guide_y)) SCREEN.blit(IMAGES['bird'][frame_index], (bird_x, bird_y)) pygame.display.update() CLOCK.tick(FPS) # 以每秒30幀刷新屏幕 def game_window(): SOUNDS['world_clear'].stop() SOUNDS['main'].play() score = 0 floor_gap = IMAGES['floor'].get_width() - MAP_WIDTH # 地板間隙 336 - 288 = 48 floor_x = 0 # 小鳥位置 bird_x = MAP_WIDTH * 0.2 bird_y = MAP_HEIGHT * 0.5 - IMAGES['bird'][0].get_height() / 2 bird = Bird(bird_x, bird_y) n_pair = round(MAP_WIDTH / PIPE_DISTANCE) # 四舍五入取整數(shù) 屏幕寬度/兩個管道之間的距離 這個距離時候刷新第二個管道 2.4 pipe_group = pygame.sprite.Group() # 是一個集合 # 生成前面的管道 pipe_x = MAP_WIDTH pipe_y = random.randint(PIPE_HEIGHT_RANGE[0], PIPE_HEIGHT_RANGE[1]) # 管道長度隨機(jī)從153.6 到 358.4 pipe1 = Pipe(pipe_x, pipe_y, upwards=True) # 創(chuàng)建一個管道對象 pipe_group.add(pipe1) # 將對象添加到這個精靈集合里面 pipe2 = Pipe(pipe_x, pipe_y - random.choice(PIPE_GAPS), upwards=False) # 翻轉(zhuǎn)的管道 pipe_group.add(pipe2) SOUNDS['flap'].play() while True: flap = False for event in pygame.event.get(): if event.type == pygame.QUIT: quit() elif event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE: # 空格拍翅膀 SOUNDS['flap'].play() flap = True bird.update(flap) if floor_x <= -floor_gap: # 當(dāng)?shù)匕迮艿阶畲箝g隔的時候 floor_x = floor_x + floor_gap # 刷新地板的x軸 else: floor_x -= 4 # 地板 x軸的移動速度 # 生成最后一個管道 if len(pipe_group) / 2 < n_pair: # 當(dāng)管道組長度<2.4 時 意思就是兩個半管道的時候 # sprites()將管道組返回成列表 last_pipe = pipe_group.sprites()[-1] pipe_x = last_pipe.rect.right + PIPE_DISTANCE pipe_y = random.randint(PIPE_HEIGHT_RANGE[0], PIPE_HEIGHT_RANGE[1]) pipe1 = Pipe(pipe_x, pipe_y, upwards=True) pipe_group.add(pipe1) pipe2 = Pipe(pipe_x, pipe_y - random.choice(PIPE_GAPS), upwards=False) pipe_group.add(pipe2) pipe_group.update() # 鳥的矩形y坐標(biāo)如果大于地板的高度 就死亡 # pygame.sprite.spritecollideany 碰撞函數(shù) 如果bird和pipe_group碰撞了 就死亡 if bird.rect.y > FLOOR_H or bird.rect.y < 0 or pygame.sprite.spritecollideany(bird, pipe_group): SOUNDS['score'].stop() SOUNDS['main'].stop() SOUNDS['hit'].play() SOUNDS['die'].play() SOUNDS['death'].play() # 保存死亡時的鳥兒 分?jǐn)?shù) 管道 繼續(xù)顯示在結(jié)束窗口 result = {'bird': bird, 'score': score, 'pipe_group': pipe_group} return result # 當(dāng)小鳥左邊大于 管道右邊就得分 if pipe_group.sprites()[0].rect.left == 0: SOUNDS['score'].play() score += 1 SCREEN.blit(IMAGES['bgpic'], (0, 0)) pipe_group.draw(SCREEN) SCREEN.blit(IMAGES['floor'], (floor_x, FLOOR_H)) SCREEN.blit(bird.image, bird.rect) show_score(score) pygame.display.update() CLOCK.tick(FPS) def end_window(result): # 顯示gameover的圖片 gameover_x = MAP_WIDTH * 0.5 - IMAGES['gameover'].get_width() / 2 gameover_y = MAP_HEIGHT * 0.4 bird = result['bird'] pipe_group = result['pipe_group'] while True: for event in pygame.event.get(): if event.type == pygame.QUIT: quit() elif event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE and bird.rect.y > FLOOR_H: SOUNDS['death'].stop() return # 使用類go_die方法 鳥兒撞墻后 旋轉(zhuǎn)往下 bird.go_die() SCREEN.blit(IMAGES['bgpic'], (0, 0)) pipe_group.draw(SCREEN) SCREEN.blit(IMAGES['floor'], (0, FLOOR_H)) SCREEN.blit(IMAGES['gameover'], (gameover_x, gameover_y)) show_score(result['score']) SCREEN.blit(bird.image, bird.rect) pygame.display.update() CLOCK.tick(FPS) # 顯示得分 def show_score(score): score_str = str(score) w = IMAGES['numbers'][0].get_width() x = MAP_WIDTH / 2 - 2 * w / 2 y = MAP_HEIGHT * 0.1 for number in score_str: # IMAGES['numbers'] = [pygame.image.load(number) for number in NUMBERS] SCREEN.blit(IMAGES['numbers'][int(number)], (x, y)) x += w class Bird(pygame.sprite.Sprite): def __init__(self, x, y): # super(Bird, self).__init__(x, y) pygame.sprite.Sprite.__init__(self) self.frames = IMAGES['bird'] # 鳥兒框架 self.frame_list = [0] * 5 + [1] * 5 + [2] * 5 + [1] * 5 # 控制小鳥翅膀運動上中下 self.frame_index = 0 self.image = self.frames[self.frame_list[self.frame_index]] # 和菜單界面小鳥扇翅膀一個原理 self.rect = self.image.get_rect() # 鳥兒的矩形 self.rect.x = x self.rect.y = y self.gravity = 1 # 重力 self.flap_acc = -10 # 翅膀拍打往上飛 y坐標(biāo)-10 self.y_vel = -10 # y坐標(biāo)的速度 self.max_y_vel = 15 # y軸下落最大速度 self.rotate = 0 # 腦袋朝向 self.rotate_vel = -3 # 轉(zhuǎn)向速度 self.max_rotate = -30 # 最大轉(zhuǎn)向速度 self.flap_rotate = 45 # 按了空格只會腦袋朝向上30度 def update(self, flap=False): if flap: self.y_vel = self.flap_acc # 拍打翅膀 則y速度-10向上 self.rotate = self.flap_rotate else: self.rotate = self.rotate + self.rotate_vel self.y_vel = min(self.y_vel + self.gravity, self.max_y_vel) self.rect.y += self.y_vel # 小鳥向上移動的距離 self.rorate = max(self.rotate + self.rotate_vel, self.max_rotate) self.frame_index += 1 # 扇翅膀的速率 self.frame_index %= len(self.frame_list) # 0~20 self.image = self.frames[self.frame_list[self.frame_index]] self.image = pygame.transform.rotate(self.image, self.rotate) # transform變形方法 旋轉(zhuǎn) def go_die(self): if self.rect.y < FLOOR_H: self.y_vel = self.max_y_vel self.rect.y += self.y_vel self.rotate = -90 self.image = self.frames[self.frame_list[self.frame_index]] self.image = pygame.transform.rotate(self.image, self.rotate) # 管道類 class Pipe(pygame.sprite.Sprite): def __init__(self, x, y, upwards=True): pygame.sprite.Sprite.__init__(self) self.x_vel = -4 # 管道移動速度 # 默認(rèn)屬性為真 則是正向管道 if upwards: self.image = IMAGES['pipe'][0] self.rect = self.image.get_rect() self.rect.x = x self.rect.top = y # 利用flip方法 旋轉(zhuǎn)管道成為反向管道 else: self.image = IMAGES['pipe'][1] self.rect = self.image.get_rect() self.rect.x = x self.rect.bottom = y def update(self): self.rect.x += self.x_vel # 管道x軸加移動速度 if self.rect.right < 0: self.kill() if __name__ == '__main__': main()
到此這篇關(guān)于pygame面向?qū)ο蟮娘w行小鳥實現(xiàn)(Flappy bird)的文章就介紹到這了,更多相關(guān)pygame 飛行小鳥內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python 循環(huán)終止語句的三種方法小結(jié)
今天小編就為大家分享一篇Python 循環(huán)終止語句的三種方法小結(jié),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-06-06python 使用pdfminer3k 讀取PDF文檔的例子
今天小編就為大家分享一篇python 使用pdfminer3k 讀取PDF文檔的例子,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-08-08Django def clean()函數(shù)對表單中的數(shù)據(jù)進(jìn)行驗證操作
這篇文章主要介紹了Django def clean()函數(shù)對表單中的數(shù)據(jù)進(jìn)行驗證操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-07-07nginx黑名單和django限速,最簡單的防惡意請求方法分享
今天小編就為大家分享一篇nginx黑名單和django限速,最簡單的防惡意請求方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2019-08-08