1. 程式人生 > >Python_從零開始學習_(52) 飛機大戰_發射子彈

Python_從零開始學習_(52) 飛機大戰_發射子彈

1.  設計 英雄 和 子彈 類

英雄需求

  1. 遊戲啟動後,  英雄 出現在螢幕的 水平中間 位置,  距離 螢幕底部 120 畫素
  2. 英雄 每隔 0.5 秒發射一次子彈,  每次 連發三枚子彈
  3. 英雄 預設不會移動, 需要通過 左/右 方向鍵, 控制 英雄 在水平方向移動

子彈需求

  1. 子彈 從 英雄 的正上方 沿直線 向 上方 飛行
  2. 飛出屏幕後,  需要從 從精靈組 中刪除

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  繪製英雄

  1. 在 __create_sprites,  新增 英雄精靈 和 英雄精靈組 後續要針對 英雄 做 碰撞檢測 以及 發射子彈 所以 英雄 需要 單獨定義成屬性
  2. 在 __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  移動英雄位置

演練步驟

  1. 在 Hero 類中重寫 update 方法 用 速度 speed 和 英雄 rect.x 進行疊加不需要呼叫父類方法 ---- 父類方法只是實現了單純的垂直活動
  2. 在 __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 的 定時器:

  1. 定義 定時器常量 ---- eventid
  2. 初始化方法 中,  呼叫 set_timer 方法 設定定時器事件
  3. 遊戲迴圈 , 監聽定時器事件

程式碼實現

  • 在 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  發射子彈

演練步驟

  1. 在 Hero 的 初始化方法 中建立 子彈精靈組 屬性
  2. 呼叫 update 和 draw 方法
  3. 實現 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)