《Python 飞机大战》(五)子弹实现

英雄飞机和敌人飞机都会发射子弹,我们先来实现子弹相关类。这里一共有两个类:

  1. Bullet 类:单个子弹类
  2. BulletForHero 类:英雄飞机携带的弹夹类

1. Bullet 类

Bullet 类是单个子弹的实现类,实现的效果如下:

其实现函数功能如下:

  1. move 子弹移动函数,需要根据具体的子弹发射策略来指定子弹的移动方向
  2. draw_element 绘制子弹对象
  3. set_unused 当子弹无效时设置可不见,并将其设置到一个不合法的位置上
  4. set_used 当子弹发射时设置可见,并设置初始位置
import random

import pygame
from Config import *

class Bullet:

    def __init__(self, scene, is_enemy=False):

        # 保存主场景
        self.scene = scene
        # 子弹是否可见
        self.visible = False
        # 加载子弹资源
        bullet_index = ENEM_BULLET_INDEX if is_enemy else HERO_BULLET_INDEX
        bullet_filename = f'source/bullet/bullet_{bullet_index}.png'
        self.image = pygame.image.load(bullet_filename)
        if is_enemy:
            self.image = pygame.transform.flip(self.image, False, True)
        # 子弹位置边框
        self.bbox = self.image.get_rect()

    def move(self, dx, dy):
        if not self.visible:
            return
        self.bbox.move_ip(dx, dy)
        if self.bbox[1] < 0 or self.bbox[1] > SCENE_H - 10:
            self.set_unused()

    def draw_element(self):
        if not self.visible:
            return
        self.scene.blit(self.image, self.bbox)

    def set_unused(self):
        self.visible = False
        self.bbox[0] = -1000
        self.bbox[1] = -1000

    def set_used(self, start_x, start_y):
        self.visible = True
        self.bbox[0] = start_x
        self.bbox[1] = start_y

测试子弹类:

from Bullet import Bullet
import pygame


if __name__ == '__main__':

    pygame.init()
    window = pygame.display.set_mode([512, 768])
    clock = pygame.time.Clock()

    # 初始化子弹
    bullet1 = Bullet(window)
    bullet1.set_used(100, 600)

    bullet2 = Bullet(window)
    bullet2.set_used(300, 600)

    while True:

        # 清空屏幕
        window.fill((0, 0, 0))

        # 子弹坐标
        bullet1.move(0, -5)
        bullet2.move(0, -3)

        # 子弹绘制
        bullet1.draw_element()
        bullet2.draw_element()

        if bullet1.bbox[1] <= 0:
            bullet1.set_used(100, 600)

        if bullet2.bbox[1] <= 0:
            bullet2.set_used(300, 600)

        # 读取事件,避免窗口卡顿
        pygame.event.get()

        pygame.display.update()
        clock.tick(60)

2. BulletForHero 弹夹类

一个英雄飞机中会包含多种子弹发射策略,例如:按下不同的键会同时发出 1 、3、5 个子弹。该类主要实现了子弹的发策略。

  1. calc_position 计算所有子弹的位置
  2. draw_element 绘制所有子弹对象
  3. shoot 子弹发射的策略。在该函数的开始位置,我们增加了函数触发的间隔,例如:当键按下时,经过 10 帧时间才会发射子弹,这样有助于控制子弹发射间隔。
子弹初始化位置计算示意图
import math
from Bullet import Bullet


class BulletForHero:

    def __init__(self, scene):
        # 初始化子弹列表
        self.bullet_list = [Bullet(scene) for _ in range(15)]
        # 子弹发射频率
        self.frame_limit = 8
        self.frame_index = 0

    def calc_position(self):
        for bullet in self.bullet_list:
            bullet.move(0, -15)

    def draw_element(self):
        for bullet in self.bullet_list:
            bullet.draw_element()

    def shoot(self, start_x, start_y, shoot_number):

        self.frame_index += 1
        if self.frame_index < self.frame_limit:
            return
        self.frame_index = 0

        # 计算子弹初始位置
        distance = 31
        position_xs = [ start_x + (index - math.floor(shoot_number / 2)) * distance for index in range(shoot_number)]

        wait_for_shoot = []
        for bullet in self.bullet_list:
            if not bullet.visible:
                wait_for_shoot.append(bullet)
            if len(wait_for_shoot) == shoot_number:
                break

        if len(wait_for_shoot) == shoot_number:
            for bullet, x in zip(wait_for_shoot, position_xs):
                bullet.set_used(x - bullet.bbox[2]/2, start_y - bullet.bbox[3])

测试 BulletForHero 类:

from BulletForHero import BulletForHero
import pygame


if __name__ == '__main__':

    pygame.init()
    window = pygame.display.set_mode([512, 768])
    clock = pygame.time.Clock()

    # 初始化弹夹
    bullets = BulletForHero(window)


    while True:

        # 清空屏幕
        window.fill((0, 0, 0))

        # 子弹坐标
        bullets.calc_position()
        # 子弹绘制
        bullets.draw_element()
        # 发射子弹
        bullets.shoot(250, 600, 3)

        # 读取事件,避免窗口卡顿
        pygame.event.get()

        pygame.display.update()
        clock.tick(60)

未经允许不得转载:一亩三分地 » 《Python 飞机大战》(五)子弹实现
评论 (0)

8 + 6 =