英雄飞机和敌人飞机都会发射子弹,我们先来实现子弹相关类。这里一共有两个类:
- Bullet 类:单个子弹类
- BulletForHero 类:英雄飞机携带的弹夹类
1. Bullet 类
Bullet 类是单个子弹的实现类,实现的效果如下:
其实现函数功能如下:
- move 子弹移动函数,需要根据具体的子弹发射策略来指定子弹的移动方向
- draw_element 绘制子弹对象
- set_unused 当子弹无效时设置可不见,并将其设置到一个不合法的位置上
- 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 个子弹。该类主要实现了子弹的发策略。
- calc_position 计算所有子弹的位置
- draw_element 绘制所有子弹对象
- 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)
没人吗?
学习碰到什么问题了吗?