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

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

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

1. Bullet 类

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

其实现函数功能如下:

  1. move 子弹移动函数,需要根据具体的子弹发射策略来指定子弹的移动方向
  2. draw_element 绘制子弹对象
  3. set_unused 当子弹无效时设置可不见,并将其设置到一个不合法的位置上
  4. set_used 当子弹发射时设置可见,并设置初始位置
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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
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
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

测试子弹类:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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)
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)
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 帧时间才会发射子弹,这样有助于控制子弹发射间隔。
子弹初始化位置计算示意图
Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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])
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])
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 类:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
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)
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)
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 飞机大战》(五)子弹实现
评论 (2)

3 + 8 =

  1. avatar
    阿发11-21 15:58回复

    没人吗?