Python_從零開始學習_(52) 飛機大戰_發射子彈
阿新 • • 發佈:2018-12-21
1. 設計 英雄 和 子彈 類
英雄需求
- 遊戲啟動後, 英雄 出現在螢幕的 水平中間 位置, 距離 螢幕底部 120 畫素
- 英雄 每隔 0.5 秒發射一次子彈, 每次 連發三枚子彈
- 英雄 預設不會移動, 需要通過 左/右 方向鍵, 控制 英雄 在水平方向移動
子彈需求
- 子彈 從 英雄 的正上方 沿直線 向 上方 飛行
- 飛出屏幕後, 需要從 從精靈組 中刪除
Hero ---- 英雄
- 初始化方法 指定 英雄圖片 初始速度 = 0 ---- 英雄預設靜止不定 定義 bullets 子彈精靈組 儲存子彈精靈
- 重寫 update() 方法
英雄需要 水平移動
並且需要保證不能 移除螢幕
- 增加 bullets 屬性, 記錄所有 子彈精靈
- 增加 fire 方法, 用於發射子彈
Bullet -- 子彈
- 初始化方法指定 子彈圖片 初始速度 = -2 ---- 子彈需要向上飛行
- 重寫 update() 方法 判斷 是否飛出螢幕, 如果是, 從 精靈組 刪除
2. 建立英雄
2.1 準備英雄類
- 在 plane_sprites 新建 Hero 類
- 重寫 初始化方法, 直接指定 圖片名稱, 並且將初始化速度設定為 0
- 設定 英雄的初始位置
class Hero(GameSprite): """英雄精靈""" def __init__(self): # 1. 呼叫父類方法, 設定image&speed super().__init__("./images/me1.png", 0) # 2. 設定英雄的初始位置 self.rect.centerx = SCREEN_RECT.centerx self.rect.bottom = SCREEN_RECT.bottom - 120
2.2 繪製英雄
- 在 __create_sprites, 新增 英雄精靈 和 英雄精靈組 後續要針對 英雄 做 碰撞檢測 以及 發射子彈 所以 英雄 需要 單獨定義成屬性
- 在 __upadte_sprites, 讓 英雄精靈組 呼叫 update 和 draw 方法
程式碼實現
- 修改 __create_sprites 方法如下 :
# 建立英雄的精靈和精靈組
self.hero = Hero()
self.hero_group = pygame.sprite.Group(self.hero)
- 修改 __update_sprites 方法如下 :
self.hero_group.update()
self.hero_group.draw(self.screen)
3. 移動英雄位置
在 pygame 中針對 鍵盤按鍵的捕獲, 有 兩種 方式
- 第一種方式 判斷 event.type == pygame.KEYDOWN
- 第二種方式 1. 首先使用 pygame.key.get_pressed() 返回 所有按鍵元組 2. 通過 鍵盤常量, 判斷元組中 某一個鍵是否被按下 ---- 如果被按下, 對應數值為 1
這兩種方式之間有什麼區別呢?
- 第一種方式
elif event.type == pygame.KEYDOWN and event.key == pygame.K_RIGHT:
print("向右移動...")
- 第二種方式
# 使用鍵盤提供的方法獲取鍵盤按鍵
keys_pressed = pygame.key.get_pressed()
# 判斷元組中對應的按鍵索引值 1
if keys_pressed[pygame.K_RIGHT]:
print("向右移動...")
結論
- 第一種方式 event.type 使用者 必須要擡起按鍵 才算一次 按鍵事件, 操作靈活性會大打折扣
- 第二種方式 使用者可以按住方向鍵不放, 就能夠實現持續向某一個方向移動了, 操作靈活性更好
3.1 移動英雄位置
演練步驟
- 在 Hero 類中重寫 update 方法 用 速度 speed 和 英雄 rect.x 進行疊加不需要呼叫父類方法 ---- 父類方法只是實現了單純的垂直活動
- 在 __event_hander 增加判斷條件
# 使用鍵盤提供的方法獲取鍵盤按鍵
keys_pressed = pygame.key.get_pressed()
# 判斷元組中對應的按鍵索引值 1
if keys_pressed[pygame.K_RIGHT]:
self.hero.speed = 3
elif keys_pressed[pygame.K_LEFT]:
self.hero.speed = -3
else:
self.hero.speed = 0
3.2 控制英雄運動邊界
- 在 Hero 類的 update() 方法判斷 英雄 是否超出 螢幕邊界
- right = x + width 利用 right 屬性可以非常容易的針對右側設定精靈位置
# 控制英雄的位置
if self.rect.x < 0:
self.rect.x = 0
elif self.rect.right > SCREEN_RECT.right:
self.rect.right = SCREEN_RECT.right
4. 發射子彈
4.1 添加發射子彈事件
pagame 的 定時器:
- 定義 定時器常量 ---- eventid
- 在 初始化方法 中, 呼叫 set_timer 方法 設定定時器事件
- 在 遊戲迴圈 中, 監聽定時器事件
程式碼實現
- 在 Hero 中定義 fire 方法
def fire(self):
print("發射子彈...")
- 定義定時器常量
# 英雄發射子彈事件定時器常量
HERO_FIRE_EVENT = pygame.USEREVENT + 1
- 在 __event_handler 方法中讓英雄發射子彈
elif event.type == HERO_FIRE_EVENT:
self.hero.fire()
4.2 定義子彈類
Bullet ---- 子彈
- 初始化方法 指定 子彈圖片 初始速度 = -2 ---- 子彈需要向上方飛行
- 重寫 update()方法 判斷 是否飛出螢幕, 如果是, 從 精靈組 刪除
定義子彈類
- 在 plane_sprites 新建 Bullet 繼承自 GameSprites
- 重寫 初始化方法, 直接指定 圖片名稱, 並且設定 初始速度
- 重寫 update() 方法, 判斷子彈 飛出螢幕從精靈組刪除
class Bullet(GameSprite):
"""子彈精靈"""
def __init__(self):
# 呼叫父類方法, 設定子彈圖片, 設定初始速度
super().__init__("./images/bullet1.png", -2)
def update(self):
# 呼叫父類方法, 讓子彈沿垂直方向飛行
super().update()
# 判斷子彈是否飛出螢幕
if self.rect.bottom < 0:
self.kill()
def __del__(self):
print("子彈被銷燬了...")
4.3 發射子彈
演練步驟
- 在 Hero 的 初始化方法 中建立 子彈精靈組 屬性
- 呼叫 update 和 draw 方法
- 實現 fire() 方法 建立子彈精靈 設定初始位置 ---- 在 英雄的正上方 將 子彈 新增到精靈組
程式碼實現
- 初始化方法
# 3. 建立子彈的精靈組
self.bullets = pygame.sprite.Group()
- 修改 fire() 方法
def fire(self):
print("發射子彈...")
# 1. 建立子彈精靈
bullet = Bullet()
# 2. 設定精靈的位置
bullet.rect.bottom = self.rect.y - 20
bullet.rect.centerx = self.rect.centerx
# 3. 將精靈新增到精靈組
self.bullets.add(bullet)
一次發射三枚子彈
- 修改 file() 方法
def fire(self):
print("發射子彈...")
for i in (0, 1, 2):
# 1. 建立子彈精靈
bullet = Bullet()
# 2. 設定精靈的位置
bullet.rect.bottom = self.rect.y - i*20
bullet.rect.centerx = self.rect.centerx
# 3. 將精靈新增到精靈組
self.bullets.add(bullet)