早就知道pygame模塊,就是沒怎麼深刻研究過,恰逢這周未沒約到妹子,只能本身在家玩本身啦,一時興起,花了幾個小時寫了個打飛機程序。python
頗有意思,跟你們分享下。git
先看一下項目結構github
""" PlayPlane/ |-- bin/ | |-- main.py 程序運行主體程序 |-- config/ | |-- settings.py 程序配置(例如: 遊戲背景音樂的加載等) |-- material 程序素材放置(打飛機遊戲素材放置) |-- ... |-- src/ 程序主體模塊存放 | |-- __init__.py | |-- bullet.py 我方飛機發射子彈實現代碼存放 | |-- enemy.py 敵方飛機實現代碼存放 | |-- plane.py 我方飛機實現代碼存放 |-- manage.py 程序啓動文件 |-- README.md """
再曬下項目成果圖微信
實現步驟app
#! /usr/bin/env python # -*- coding: utf-8 -*- import pygame pygame.init() # 遊戲初始化 pygame.mixer.init() # 混音器初始化 # 遊戲背景音樂 pygame.mixer.music.load("material/sound/game_music.wav") pygame.mixer.music.set_volume(0.2) # 子彈發射音樂 bullet_sound = pygame.mixer.Sound("material/sound/bullet.wav") bullet_sound.set_volume(0.2) # 我方飛機掛了的音樂 me_down_sound = pygame.mixer.Sound("material/sound/game_over.wav") me_down_sound.set_volume(0.2) # 敵方飛機掛了的音樂 enemy1_down_sound = pygame.mixer.Sound("material/sound/enemy1_down.wav") enemy1_down_sound.set_volume(0.2) config/settings.py
注:遊戲素材滑動到文章底部點擊連接便可下載 dom
飛機和子彈都是可移動的,那麼怎麼實現讓它們動起來呢(我方飛機能夠玩家進行操控,敵機就是隨機性的出現,子彈暫由我方飛機發射)。ide
在Pygame中,全部移動對象均可看作是一個精靈(sprite),精靈之間可以進行相互的交互通訊,例如如何讓碰撞檢測更加精準等等。函數
那麼先讓咱們先在屏幕上製做一個遊戲板,根據 settings.py 配置,並讓它有聲音播放,首先咱們在 bin/main.py 中這麼寫:oop
咱們能夠直接運行它,那麼咱們會看到如下畫面,而且還會有激情的聲音吆!!!可是咱們要將文件配置爲絕對路徑才能夠運行,由於剛剛在settings中的加載的音樂文件爲相對路徑。ui
#! /usr/bin/env python # -*- coding: utf-8 -*- import sys from config.settings import * bg_size = 480, 852 # 初始化遊戲背景大小(寬, 高) screen = pygame.display.set_mode(bg_size) # 設置背景對話框 pygame.display.set_caption("飛機大戰") # 設置標題 background = pygame.image.load(os.path.join(BASE_DIR, "material/image/background.png")) # 加載背景圖片,並設置爲不透明 def main(): pygame.mixer.music.play(loops=-1) # loops 對應的值爲 -1 則音樂會無限循環播放 while True: # 繪製背景圖 screen.blit(background, (0, 0)) # 響應用戶的操做(必定要有響應的用戶操做) for event in pygame.event.get(): if event.type == 12: # 若是用戶按下屏幕上的關閉按鈕,觸發QUIT事件,程序退出 pygame.quit() sys.exit() # 再而咱們將背景圖像並輸出到屏幕上面 pygame.display.flip() if __name__ == '__main__': main()
接下來呢,咱們將要製做我方飛機,敵方飛機和子彈如何讓它們展現在遊戲畫板上,繼而讓它們變得可移動起來,請看代碼實現方案...
從遊戲畫板上添加飛機,首先咱們應怎樣在屏幕上輸出飛機???
上述講過,pygame中的 sprite(精靈)可以使一張圖片或者一個靜態物體動起來,那麼製做飛機須要考慮並作些什麼呢?
那麼如何實現以上的功能呢?接下來結合上述的示例代碼咱們先將我方飛機繪製到畫板上方,而且咱們經過按鍵 J 斷定我方飛機的存活狀態爲死亡,繪製飛機的死亡畫面並重置飛機
""" 建立飛機 在pygame中, 全部可移動的對象均叫可看做一個精靈(sprite) 該類並實現了碰撞方法 spritecollide 我方飛機和敵方飛機指定掩膜屬性以及生存狀態標誌位 添加 self.mask 屬性(能夠實現更精準的碰撞效果) """ # 倒入精靈模塊, 使飛機能夠動起來 import pygame class OurPlane(pygame.sprite.Sprite): def __init__(self, bg_size): super(OurPlane, self).__init__() # 肯定我方飛機背景圖(有倆張,可讓它們不停的切換,造成動態效果) self.image_one = pygame.image.load("material/image/hero1.png") self.image_two = pygame.image.load("material/image/hero2.png") # 獲取我方飛機的位置 self.rect = self.image_one.get_rect() # 本地化背景圖片的尺寸 self.width, self.height = bg_size[0], bg_size[1] # 獲取飛機圖像的掩膜用以更加精確的碰撞檢測 self.mask = pygame.mask.from_surface(self.image_one) # 定義飛機初始化位置,底部預留60像素 self.rect.left, self.rect.top = (self.width - self.rect.width) // 2, (self.height - self.rect.height - 60) # 設置飛機移動速度 self.speed = 10 # 設置飛機存活狀態(True爲存活, False爲死亡) self.active = True # 加載飛機損毀圖片 self.destroy_images = [] self.destroy_images.extend( [ pygame.image.load("material/image/hero_blowup_n1.png"), pygame.image.load("material/image/hero_blowup_n2.png"), pygame.image.load("material/image/hero_blowup_n3.png"), pygame.image.load("material/image/hero_blowup_n4.png") ] ) def move_up(self): """ 飛機向上移動的操做函數,其他移動函數方法相似 """ if self.rect.top > 0: # 若是飛機還沒有移動出背景區域 self.rect.top -= self.speed else: # 若即將移動出背景區域,則及時糾正爲背景邊緣位置 self.rect.top = 0 def move_down(self): """ 飛機向下移動 """ if self.rect.bottom < self.height - 60: self.rect.top += self.speed else: self.rect.bottom = self.height - 60 def move_left(self): """ 飛機向左移動 """ if self.rect.left > 0: self.rect.left -= self.speed else: self.rect.left = 0 def move_right(self): """ 飛機向右移動 """ if self.rect.right < self.width: self.rect.right += self.speed else: self.rect.right = self.width def reset(self): # 初始化飛機(飛機掛了, 初始化到初始位置) self.rect.left, self.rect.top = (self.width - self.rect.width) // 2, (self.height - self.rect.height - 60) # 重置飛機的存活狀態 self.active = True
上面的代碼寫了一個 咱們的飛機 (OurPlane) 類,它初始化了一些屬性以及 上下左右 移動的方法和重置方法,接下來將要運用它展現到遊戲畫板上面
因爲飛機是一直存在的,接下咱們主程序 main 下面的死循環中這樣寫
def main(): pygame.mixer.music.play(loops=-1) # loops 對應的值爲 -1 則音樂會無限循環播放 our_plane = OurPlane(bg_size) # 初始化 switch_image = False # 定義飛機的切圖效果標識 while True: # 繪製背景圖 screen.blit(background, (0, 0)) # 飛機狀態是存活 if our_plane.active: if switch_image: screen.blit(our_plane.image_one, our_plane.rect) else: screen.blit(our_plane.image_two, our_plane.rect) switch_image = not switch_image # 讓切圖狀態不停的變換 else: pass # 響應用戶的操做(必定要有響應的用戶操做) for event in pygame.event.get(): if event.type == 12: # 若是用戶按下屏幕上的關閉按鈕,觸發QUIT事件,程序退出 pygame.quit() sys.exit() # 再而咱們將背景圖像並輸出到屏幕上面 pygame.display.flip() if __name__ == '__main__': main()
def main(): pygame.mixer.music.play(loops=-1) # loops 對應的值爲 -1 則音樂會無限循環播放 our_plane = OurPlane(bg_size) # 初始化 switch_image = False # 定義飛機的切圖效果標識 while True: # 繪製背景圖 screen.blit(background, (0, 0)) # 飛機狀態是存活 if our_plane.active: if switch_image: screen.blit(our_plane.image_one, our_plane.rect) else: screen.blit(our_plane.image_two, our_plane.rect) switch_image = not switch_image # 讓切圖狀態不停的變換 else: pass # 得到用戶全部的鍵盤輸入序列(若是用戶經過鍵盤發出「向上」的指令,其餘相似) key_pressed = pygame.key.get_pressed() if key_pressed[K_w] or key_pressed[K_UP]: our_plane.move_up() if key_pressed[K_s] or key_pressed[K_DOWN]: our_plane.move_down() if key_pressed[K_a] or key_pressed[K_LEFT]: our_plane.move_left() if key_pressed[K_d] or key_pressed[K_RIGHT]: our_plane.move_right() # 響應用戶的操做(必定要有響應的用戶操做) for event in pygame.event.get(): if event.type == 12: # 若是用戶按下屏幕上的關閉按鈕,觸發QUIT事件,程序退出 pygame.quit() sys.exit() # 再而咱們將背景圖像並輸出到屏幕上面 pygame.display.flip() if __name__ == '__main__': main()
def main(): pygame.mixer.music.play(loops=-1) # loops 對應的值爲 -1 則音樂會無限循環播放 our_plane = OurPlane(bg_size) # 初始化 switch_image = False # 定義飛機的切圖效果標識 our_plane_destroy_index = 0 while True: # 繪製背景圖 screen.blit(background, (0, 0)) # 飛機狀態是存活(若是按鍵 爲 J, 讓飛機死亡並繪製爆炸效果) if our_plane.active: if switch_image: screen.blit(our_plane.image_one, our_plane.rect) else: screen.blit(our_plane.image_two, our_plane.rect) switch_image = not switch_image # 讓切圖狀態不停的變換 else: """ 飛機死亡也是進行按順序的圖片切換, 那麼在死循環以外定義索引 """ me_destroy_index = (our_plane_destroy_index + 1) % 4 if me_destroy_index == 1: me_down_sound.play() # 爆炸聲音效果 our_plane.reset() # 初始化飛機 if our_plane_destroy_index >= len(our_plane.destroy_images): our_plane_destroy_index = 0 else: screen.blit(our_plane.destroy_images[our_plane_destroy_index], our_plane.rect) our_plane_destroy_index += 1 # 得到用戶全部的鍵盤輸入序列(若是用戶經過鍵盤發出「向上」的指令,其餘相似) key_pressed = pygame.key.get_pressed() if key_pressed[K_w] or key_pressed[K_UP]: our_plane.move_up() if key_pressed[K_s] or key_pressed[K_DOWN]: our_plane.move_down() if key_pressed[K_a] or key_pressed[K_LEFT]: our_plane.move_left() if key_pressed[K_d] or key_pressed[K_RIGHT]: our_plane.move_right() # 按鍵爲 j 飛機更改存活標識 if key_pressed[K_j]: our_plane.active = False # 響應用戶的操做(必定要有響應的用戶操做) for event in pygame.event.get(): if event.type == 12: # 若是用戶按下屏幕上的關閉按鈕,觸發QUIT事件,程序退出 pygame.quit() sys.exit() # 再而咱們將背景圖像並輸出到屏幕上面 pygame.display.flip()
那麼上述的功能都已經實現了,接下來就開始真正的"打飛機"
#! /usr/bin/env python # -*- coding: utf-8 -*- """ 建立飛機 在pygame中, 全部可移動的對象均叫可看做一個精靈(sprite) 該類並實現了碰撞方法 spritecollide 我方飛機和敵方飛機指定掩膜屬性以及生存狀態標誌位 添加 self.mask 屬性(能夠實現更精準的碰撞效果) """ # 倒入精靈模塊, 使飛機能夠動起來 import pygame class OurPlane(pygame.sprite.Sprite): def __init__(self, bg_size): super(OurPlane, self).__init__() # 肯定我方飛機背景圖 self.image_one = pygame.image.load("material/image/hero1.png") self.image_two = pygame.image.load("material/image/hero2.png") # 獲取我方飛機的位置 self.rect = self.image_one.get_rect() # 本地化背景圖片的尺寸 self.width, self.height = bg_size[0], bg_size[1] # 獲取飛機圖像的掩膜用以更加精確的碰撞檢測 self.mask = pygame.mask.from_surface(self.image_one) # 定義飛機初始化位置,底部預留60像素 self.rect.left, self.rect.top = (self.width - self.rect.width) // 2, (self.height - self.rect.height - 60) # 設置飛機移動速度 self.speed = 10 # 設置飛機存活狀態(True爲存活, False爲死亡) self.active = True # 加載飛機損毀圖片 self.destroy_images = [] self.destroy_images.extend( [ pygame.image.load("material/image/hero_blowup_n1.png"), pygame.image.load("material/image/hero_blowup_n2.png"), pygame.image.load("material/image/hero_blowup_n3.png"), pygame.image.load("material/image/hero_blowup_n4.png") ] ) def move_up(self): """ 飛機向上移動的操做函數,其他移動函數方法相似 """ if self.rect.top > 0: # 若是飛機還沒有移動出背景區域 self.rect.top -= self.speed else: # 若即將移動出背景區域,則及時糾正爲背景邊緣位置 self.rect.top = 0 def move_down(self): if self.rect.bottom < self.height - 60: self.rect.top += self.speed else: self.rect.bottom = self.height - 60 def move_left(self): if self.rect.left > 0: self.rect.left -= self.speed else: self.rect.left = 0 def move_right(self): if self.rect.right < self.width: self.rect.right += self.speed else: self.rect.right = self.width def reset(self): # 初始化飛機(飛機掛了, 初始化到初始位置) self.rect.left, self.rect.top = (self.width - self.rect.width) // 2, (self.height - self.rect.height - 60) self.active = True src/plane.py
#! /usr/bin/env python # -*- coding: utf-8 -*- """ 定義敵機 """ from random import randint import pygame class SmallEnemy(pygame.sprite.Sprite): """ 定義小飛機敵人 """ def __init__(self, bg_size): super(SmallEnemy, self).__init__() self.image = pygame.image.load("material/image/enemy1.png") self.rect = self.image.get_rect() self.width, self.height = bg_size[0], bg_size[1] self.mask = pygame.mask.from_surface(self.image) # 獲取飛機圖像的掩膜用以更加精確的碰撞檢測 self.speed = 2 # 定義敵機出現的位置, 保證敵機不會在程序已開始就當即出現 self.rect.left, self.rect.top = ( randint(0, self.width - self.rect.width), randint(-5 * self.rect.height, -5), ) self.active = True # 加載飛機損毀圖片 self.destroy_images = [] self.destroy_images.extend( [ pygame.image.load("material/image/enemy1_down1.png"), pygame.image.load("material/image/enemy1_down2.png"), pygame.image.load("material/image/enemy1_down3.png"), pygame.image.load("material/image/enemy1_down4.png") ] ) def move(self): """ 定義敵機的移動函數 :return: """ if self.rect.top < self.height: self.rect.top += self.speed else: self.reset() def reset(self): """ 當敵機向下移動出屏幕時, 以及敵機死亡 :return: """ self.rect.left, self.rect.top = (randint(0, self.width - self.rect.width), randint(-5 * self.rect.height, 0)) self.active = True
#! /usr/bin/env python # -*- coding: utf-8 -*- """ 子彈的實現 """ import pygame class Bullet(pygame.sprite.Sprite): def __init__(self, position): super(Bullet, self).__init__() self.image = pygame.image.load("material/image/bullet1.png") self.rect = self.image.get_rect() self.rect.left, self.rect.top = position self.speed = 30 self.active = True self.mask = pygame.mask.from_surface(self.image) def move(self): """ 子彈移動, 超出屏幕範圍, 則設置死亡 :return: """ if self.rect.top < 0: self.active = False else: self.rect.top -= self.speed def reset(self, position): """ 復位函數 :param position: :return: """ self.rect.left, self.rect.top = position self.active = True src/bullet.py
在上面的內容中,使用面向對象的形式製做了遊戲中可移動的對象並繼承 pygame.sprite.Sprite
import sys from pygame.locals import * from config.settings import * from src.plane import OurPlane from src.enemy import SmallEnemy from src.bullet import Bullet bg_size = 480, 852 # 初始化遊戲背景大小(寬, 高) screen = pygame.display.set_mode(bg_size) # 設置背景對話框 pygame.display.set_caption("飛機大戰") # 設置標題 background = pygame.image.load("material/image/background.png") # 加載背景圖片,並設置爲不透明 # 獲取我方飛機 our_plane = OurPlane(bg_size) def add_small_enemies(group1, group2, num): """ 添加小型敵機 指定個敵機對象添加到精靈組(sprite.group) 參數group一、group2是兩個精靈組類型的形參,用以存儲多個精靈對象(敵機)。 須要注意的一點是group既然是特定的精靈組結構體,在向其內部添加精靈對象時須要調用其對應的成員函數add() :return: """ for i in range(num): small_enemy = SmallEnemy(bg_size) group1.add(small_enemy) group2.add(small_enemy) def main(): # 響應音樂 pygame.mixer.music.play(-1) # loops 接收該參數, -1 表示無限循環(默認循環播放一次) running = True switch_image = False # 切換飛機的標識位(使飛機具備噴氣式效果) delay = 60 # 對一些效果進行延遲, 效果更好一些 enemies = pygame.sprite.Group() # 生成敵方飛機組(一種精靈組用以存儲全部敵機精靈) small_enemies = pygame.sprite.Group() # 敵方小型飛機組(不一樣型號敵機建立不一樣的精靈組來存儲) add_small_enemies(small_enemies, enemies, 4) # 生成若干敵方小型飛機 # 定義子彈, 各類敵機和我方敵機的毀壞圖像索引 bullet_index = 0 e1_destroy_index = 0 me_destroy_index = 0 # 定義子彈實例化個數 bullet1 = [] bullet_num = 6 for i in range(bullet_num): bullet1.append(Bullet(our_plane.rect.midtop)) while running: # 繪製背景圖 screen.blit(background, (0, 0)) # 微信的飛機貌似是噴氣式的, 那麼這個就涉及到一個幀數的問題 clock = pygame.time.Clock() clock.tick(60) # 繪製我方飛機的兩種不一樣的形式 if not delay % 3: switch_image = not switch_image for each in small_enemies: if each.active: # 隨機循環輸出小飛機敵機 for e in small_enemies: e.move() screen.blit(e.image, e.rect) else: if e1_destroy_index == 0: enemy1_down_sound.play() screen.blit(each.destroy_images[e1_destroy_index], each.rect) e1_destroy_index = (e1_destroy_index + 1) % 4 if e1_destroy_index == 0: each.reset() # 當我方飛機存活狀態, 正常展現 if our_plane.active: if switch_image: screen.blit(our_plane.image_one, our_plane.rect) else: screen.blit(our_plane.image_two, our_plane.rect) # 飛機存活的狀態下才能夠發射子彈 if not (delay % 10): # 每十幀發射一顆移動的子彈 bullet_sound.play() bullets = bullet1 bullets[bullet_index].reset(our_plane.rect.midtop) bullet_index = (bullet_index + 1) % bullet_num for b in bullets: if b.active: # 只有激活的子彈纔可能擊中敵機 b.move() screen.blit(b.image, b.rect) enemies_hit = pygame.sprite.spritecollide(b, enemies, False, pygame.sprite.collide_mask) if enemies_hit: # 若是子彈擊中飛機 b.active = False # 子彈損毀 for e in enemies_hit: e.active = False # 小型敵機損毀 # 毀壞狀態繪製爆炸的場面 else: if not (delay % 3): screen.blit(our_plane.destroy_images[me_destroy_index], our_plane.rect) me_destroy_index = (me_destroy_index + 1) % 4 if me_destroy_index == 0: me_down_sound.play() our_plane.reset() # 調用 pygame 實現的碰撞方法 spritecollide (我方飛機若是和敵機碰撞, 更改飛機的存活屬性) enemies_down = pygame.sprite.spritecollide(our_plane, enemies, False, pygame.sprite.collide_mask) if enemies_down: our_plane.active = False for row in enemies: row.active = False # 響應用戶的操做 for event in pygame.event.get(): if event.type == 12: # 若是用戶按下屏幕上的關閉按鈕,觸發QUIT事件,程序退出 pygame.quit() sys.exit() if delay == 0: delay = 60 delay -= 1 # 得到用戶全部的鍵盤輸入序列(若是用戶經過鍵盤發出「向上」的指令,其餘相似) key_pressed = pygame.key.get_pressed() if key_pressed[K_w] or key_pressed[K_UP]: our_plane.move_up() if key_pressed[K_s] or key_pressed[K_DOWN]: our_plane.move_down() if key_pressed[K_a] or key_pressed[K_LEFT]: our_plane.move_left() if key_pressed[K_d] or key_pressed[K_RIGHT]: our_plane.move_right() # 繪製圖像並輸出到屏幕上面 pygame.display.flip()
from bin.main import main if __name__ == '__main__': """ 環境: python3 + pygame running 起來就能夠打飛機了O(∩_∩)O~. """ main()
最終效果!
完整項目代碼 : https://github.com/triaquae/jerkoff
另外,本項目所用到的基礎知識視頻 已上傳至 路飛學城 ,須要者自取! http://luffy.oldboyedu.com/course/detail/python/5