Bootstrap

Pygame-飞机大战

1.游戏介绍

1.1 游戏的基本设定

  1. 敌方共有大中小3款飞机,分别为高中低三中速度,自己还可以设置一个游戏等级窗口,来改变自己刚开始进入游戏时难度等级;
  2. 子弹的射程并非全屏,而大概是屏幕长度的80%;
  3. 消灭飞机需要1发子弹,中飞机需要8发子弹,大飞机需要20发子弹;

1.2 对游戏做的改进

  1. 为中飞机和打飞机增加了血槽的显示,这样我们可以直观的知道敌机快被消灭了没有;
  2. 我方有三次机会,每次被敌人消灭后,新诞生的飞机有3秒钟的安全期

2.背景相关信息添加

2.1 添加飞机大战的基本信息

from pygame.locals import *
from random import *
import tkinter as tk  # 制作GUI界面库
import pygame
import math
import sys

pygame.init()  # 初始化
pygame.mixer.init()  # 混音器初始化
clock = pygame.time.Clock()  # 设置一个计时器
"""载入音乐文件"""
# 背景音乐
pygame.mixer.music.load("sound/game_music.mp3")  # 设置背景音乐
pygame.mixer.music.set_volume(1)  # 设置音量

# 游戏音效
pygame.mixer.music.load("sound/game_music.mp3")  # 背景音乐
pygame.mixer.music.set_volume(0.2)
bullet_sound = pygame.mixer.Sound("sound/bullet.mp3")  # 子弹音效
bullet_sound.set_volume(0.2)
get_bullet_sound = pygame.mixer.Sound("sound/bullet.mp3")  # 子弹音效
get_bullet_sound.set_volume(0.2)
upgrade_sound = pygame.mixer.Sound("sound/button.mp3")  # 按键音效
upgrade_sound.set_volume(0.2)
enemy3_fly_sound = pygame.mixer.Sound("sound/big_spaceship_flying.mp3")  # 大飞机出现
enemy3_fly_sound.set_volume(0.2)
enemy1_down_sound = pygame.mixer.Sound("sound/enemy1_down.mp3")  # 小飞机击落
enemy1_down_sound.set_volume(0.1)
enemy2_down_sound = pygame.mixer.Sound("sound/enemy2_down.mp3")  # 中飞机击落
enemy2_down_sound.set_volume(0.2)
enemy3_down_sound = pygame.mixer.Sound("sound/enemy3_down.mp3")  # 大飞机击落
enemy3_down_sound.set_volume(0.5)
me_down_sound = pygame.mixer.Sound("sound/use_bomb.mp3")  # 按键音效
me_down_sound.set_volume(0.2)
myself_down_sound = pygame.mixer.Sound("sound/game_over.mp3")  # 按键音效
myself_down_sound.set_volume(0.2)

"""图片文件路径"""
background_image = "image/background.png"  # 背景图的路径
bullet1_image = "image/bullet1.png"  # 第一种子弹图
enemy1_image = "image/enemy1.png"  # 小敌机图片
enemy2_image = "image/enemy2.png"  # 中敌机图片
enemy3_n1_image = "image/enemy3.png"  # 大敌机图片1
enemy3_n2_image = "image/enemy3_n2.png"  # 大敌机图片2
me1_image = "image/hero1.png"  # 自身飞机第一张图片
me2_image = "image/hero2.png"  # 自身飞机第二张图片

# 设置背景
bg_size = width, height = 430, 700  # 背景大小,bg_size为一个元组
screen = pygame.display.set_mode(bg_size)  # 这是背景大小
background = pygame.image.load(background_image).convert_alpha()  # 画背景
pygame.mixer.music.play(-1)  # 播放背景音乐,-1 表示无限循环播放

def main():
    while True:
        for event in pygame.event.get():     # 键盘操作
            if event.type == QUIT:
                sys.exit()
        screen.blit(background, (0, 0))  # 绘制背景
        pygame.display.flip()  # 不停的刷新画面,不停的绘画
        clock.tick(60)  # 设置帧率

if __name__ == "__main__":
    # 这样做的好处是双击打开时如果出现异常可以报告异常,而不是一闪而过!
    try:
        main()
    except SystemExit:  # 这是按下 × 的异常,直接忽略
        pass

3.我方战机

3.1 设置我方战机类

创建一个名为 myplane 的模块,然后把我方飞机的所有属性和方法定义在里边

######################## 设置我方战机类 #########################
class MyPlane(pygame.sprite.Sprite):  # 定义我的飞机类,继承动画精灵类(因为之后要进行碰撞检测)
    def __init__(self, bg_size,me1_image,me2_image):
        self.image1 = pygame.image.load(me1_image).convert_alpha()  # 第一张飞机图片
        self.image2 = pygame.image.load(me2_image).convert_alpha()  # 第二张飞机图片 两张图片是为了做出飞机喷气的效果
        self.rect = self.image1.get_rect()  # 获得飞机图片的尺寸
        self.width, self.height = bg_size[0], bg_size[1]  # 设置飞机允许活动地点
        self.rect.left, self.rect.top = [(self.width - self.rect.width) // 2, \
                                         (self.height - self.rect.height - 20)]  # 注意括号设置我方飞机出现的位置
        self.speed = 10  # 设置飞机出现的速度

    def moveup(self):  # 飞机向上飞的函数
        if self.rect.top > 0:  # 如果我方飞机没有飞出 上方边界
            self.rect.top -= 10  # 那么我方飞机朝上飞10个像素
        else:  # 飞出 上方边界
            self.rect.top = 0  # 锁定在0的位置,不再发生变化

    def movedown(self):  # 飞机向下飞的函数
        if self.rect.bottom < (self.height - 20):  # 如果我方飞机没有飞出 上方边界
            self.rect.bottom += 10  # 那么我方飞机朝下飞10个像素
        else:  # 飞出 下方边界
            self.rect.bottom = (self.height - 20)  # 锁定在底边界上方60的位置,不再发生变化

    def moveleft(self):  # 飞机向左飞的函数
        if self.rect.left > 0:  # 如果我方飞机没有飞出 左方边界
            self.rect.left -= 10  # 那么我方飞机朝下左10个像素
        else:  # 飞出 左方边界
            self.rect.left = 0  # 锁定在左边界的位置,不再发生变化

    def moveright(self):  # 飞机向下飞的函数
        if self.rect.right < self.width:  # 如果我方飞机没有飞出 上方边界
            self.rect.right += 10  # 那么我方飞机朝下飞10个像素
        else:  # 飞出 下方边界
            self.rect.right = self.width  # 锁定在底边界的位置,不再发生变化

3.2 显示我方战机

在main函数的while循环上面生成我方飞机类

me = MyPlane(bg_size, me1_image, me2_image) # 生成飞机类

在while循环里面,绘制背景的下面绘制我方战机

# 绘制飞机
screen.blit(me.image2, me.rect) # 绘制第一张飞机图

3.3 控制我方飞机移动

1、通过检测事件消息,检测到如果有 KEYDOWN 或者 KEYUP 事件,我们就知道是用户按下了键盘按键。(这是我们之前常用的一种方法)

2、调用 key 模块里的 get_pressed() 方法,会返回一个序列,该序列包含键盘上所有按键的布尔类型的值,如果这个值是True 的话,表示该按键被按下。

写在退出按键下面即可

# 检查是否有上下左右或wsad按下,如有则对飞机进行相应的控制
key_press = pygame.key.get_pressed()
if key_press[K_w] or key_press[K_UP]:  # 如果按下上键或者↑
    me.moveup()  # 飞船向上飞行
elif key_press[K_s] or key_press[K_DOWN]:  # 如果按下下键或者↓
    me.movedown()  # 飞船向下飞行
elif key_press[K_a] or key_press[K_LEFT]:  # 如果按下左键或者←
    me.moveleft()  # 飞船向左飞行
elif key_press[K_d] or key_press[K_RIGHT]:  # 如果按下右键或者→
    me.moveright()  # 飞船向右飞行

 

3.4 切换我方飞机造型

为了增加我方飞机的动态效果,我们可以通过两张图片(me1,png 和 me2.png)的切换来实现飞机冒烟的效果

设置两个变量switch_image,delay

switch_image 为True 画第一张飞机图

switch_image 为False 画第二张飞机图

delay为延时变量

写在while循环的上面

switch_image = True # 用于切换战机图片
delay = 100         # 用于延时

 写在绘制背景的下面

# 绘制我方飞机
if switch_image:  # 2如果改变属性为真  画第一张飞机图
    screen.blit(me.image1, me.rect)
else:  # 2如果改变属性为假    画第二张飞机图
    screen.blit(me.image2, me.rect)
# 切换图片
if delay % 5 == 0:
    switch_image = not switch_image
delay -= 1
if delay==0:
    delay = 100

3.5 目前所写代码 

from pygame.locals import *
from random import *
import tkinter as tk  # 制作GUI界面库
import pygame
import math
import sys

pygame.init()  # 初始化
pygame.mixer.init()  # 混音器初始化
clock = pygame.time.Clock()  # 设置一个计时器
"""载入音乐文件"""
# 背景音乐
pygame.mixer.music.load("sound/game_music.mp3")  # 设置背景音乐
pygame.mixer.music.set_volume(1)  # 设置音量

# 游戏音效
pygame.mixer.music.load("sound/game_music.mp3")  # 背景音乐
pygame.mixer.music.set_volume(0.2)
bullet_sound = pygame.mixer.Sound("sound/bullet.mp3")  # 子弹音效
bullet_sound.set_volume(0.2)
get_bullet_sound = pygame.mixer.Sound("sound/bullet.mp3")  # 子弹音效
get_bullet_sound.set_volume(0.2)
upgrade_sound = pygame.mixer.Sound("sound/button.mp3")  # 按键音效
upgrade_sound.set_volume(0.2)
enemy3_fly_sound = pygame.mixer.Sound("sound/big_spaceship_flying.mp3")  # 大飞机出现
enemy3_fly_sound.set_volume(0.2)
enemy1_down_sound = pygame.mixer.Sound("sound/enemy1_down.mp3")  # 小飞机击落
enemy1_down_sound.set_volume(0.1)
enemy2_down_sound = pygame.mixer.Sound("sound/enemy2_down.mp3")  # 中飞机击落
enemy2_down_sound.set_volume(0.2)
enemy3_down_sound = pygame.mixer.Sound("sound/enemy3_down.mp3")  # 大飞机击落
enemy3_down_sound.set_volume(0.5)
me_down_sound = pygame.mixer.Sound("sound/use_bomb.mp3")  # 按键音效
me_down_sound.set_volume(0.2)
myself_down_sound = pygame.mixer.Sound("sound/game_over.mp3")  # 按键音效
myself_down_sound.set_volume(0.2)

"""图片文件路径"""
background_image = "image/background.png"  # 背景图的路径
bullet1_image = "image/bullet1.png"  # 第一种子弹图
enemy1_image = "image/enemy1.png"  # 小敌机图片
enemy2_image = "image/enemy2.png"  # 中敌机图片
enemy3_n1_image = "image/enemy3.png"  # 大敌机图片1
enemy3_n2_image = "image/enemy3_n2.png"  # 大敌机图片2
me1_image = "image/hero1.png"  # 自身飞机第一张图片
me2_image = "image/hero2.png"  # 自身飞机第二张图片

# 设置背景
bg_size = width, height = 430, 700  # 背景大小,bg_size为一个元组
screen = pygame.display.set_mode(bg_size)  # 这是背景大小
background = pygame.image.load(background_image).convert_alpha()  # 画背景
pygame.mixer.music.play(-1)  # 播放背景音乐,-1 表示无限循环播放

######################## 设置我方战机类 #########################
class MyPlane(pygame.sprite.Sprite):  # 定义我的飞机类,继承动画精灵类(因为之后要进行碰撞检测)
    def __init__(self, bg_size,me1_image,me2_image):
        self.image1 = pygame.image.load(me1_image).convert_alpha()  # 第一张飞机图片
        self.image2 = pygame.image.load(me2_image).convert_alpha()  # 第二张飞机图片 两张图片是为了做出飞机喷气的效果
        self.rect = self.image1.get_rect()  # 获得飞机图片的尺寸
        self.width, self.height = bg_size[0], bg_size[1]  # 设置飞机允许活动地点
        self.rect.left, self.rect.top = [(self.width - self.rect.width) // 2, \
                                         (self.height - self.rect.height - 20)]  # 注意括号设置我方飞机出现的位置
        self.speed = 10  # 设置飞机出现的速度

    def moveup(self):  # 飞机向上飞的函数
        if self.rect.top > 0:  # 如果我方飞机没有飞出 上方边界
            self.rect.top -= 10  # 那么我方飞机朝上飞10个像素
        else:  # 飞出 上方边界
            self.rect.top = 0  # 锁定在0的位置,不再发生变化


    def movedown(self):  # 飞机向下飞的函数
        if self.rect.bottom < (self.height - 20):  # 如果我方飞机没有飞出 上方边界
            self.rect.bottom += 10  # 那么我方飞机朝下飞10个像素
        else:  # 飞出 下方边界
            self.rect.bottom = (self.height - 20)  # 锁定在底边界上方60的位置,不再发生变化

    def moveleft(self):  # 飞机向左飞的函数
        if self.rect.left > 0:  # 如果我方飞机没有飞出 左方边界
            self.rect.left -= 10  # 那么我方飞机朝下左10个像素
        else:  # 飞出 左方边界
            self.rect.left = 0  # 锁定在左边界的位置,不再发生变化

    def moveright(self):  # 飞机向下飞的函数
        if self.rect.right < self.width:  # 如果我方飞机没有飞出 上方边界
            self.rect.right += 10  # 那么我方飞机朝下飞10个像素
        else:  # 飞出 下方边界
            self.rect.right = self.width  # 锁定在底边界的位置,不再发生变化


def main():
    me = MyPlane(bg_size, me1_image, me2_image) # 生成飞机类
    switch_image = True # 用于切换战机图片
    delay = 100         # 用于延时
    while True:
        for event in pygame.event.get():     # 键盘操作
            if event.type == QUIT:
                sys.exit()
        # 检查是否有上下左右或wsad按下,如有则对飞机进行相应的控制
        key_press = pygame.key.get_pressed()
        if key_press[K_w] or key_press[K_UP]:  # 如果按下上键或者↑
            me.moveup()  # 飞船向上飞行
        elif key_press[K_s] or key_press[K_DOWN]:  # 如果按下下键或者↓
            me.movedown()  # 飞船向下飞行
        elif key_press[K_a] or key_press[K_LEFT]:  # 如果按下左键或者←
            me.moveleft()  # 飞船向左飞行
        elif key_press[K_d] or key_press[K_RIGHT]:  # 如果按下右键或者→
            me.moveright()  # 飞船向右飞行

        screen.blit(background, (0, 0))  # 绘制背景

        # 绘制我方飞机
        if switch_image:  # 2如果改变属性为真  画第一张飞机图
            screen.blit(me.image1, me.rect)
        else:  # 2如果改变属性为假    画第二张飞机图
            screen.blit(me.image2, me.rect)
        # 切换图片
        if delay % 5 == 0:
            switch_image = not switch_image
        delay -= 1
        if delay==0:
            delay = 100

        pygame.display.flip()  # 不停的刷新画面,不停的绘画
        clock.tick(60)  # 设置帧率


if __name__ == "__main__":
    # 这样做的好处是双击打开时如果出现异常可以报告异常,而不是一闪而过!
    try:
        main()
    except SystemExit:  # 这是按下 × 的异常,直接忽略
        pass

4.敌方战机

敌机分为小中大三个尺寸,它们的速度一次就是快中慢(越小越快),在页面上方,我们就需要随机创建一些敌机,可以通过在页面外部上方5个屏幕高度范围内随机生成一个敌机以保证不让敌机在一排出现。

4.1 小飞机

写在我方战机类的下面

####################### 设置敌方战机类 ##########################
# 小飞机
class SmallEnemy(pygame.sprite.Sprite):  #定义小敌机类,继承自动画精灵
    def __init__(self,bg_size,enemy1_image):
        pygame.sprite.Sprite.__init__(self)
        self.enemy1 = pygame.image.load(enemy1_image).convert_alpha()   # 载入小敌机图片
        self.width, self.height = bg_size[0] , bg_size[1]   # 获取生成小敌机的活动范围
        self.rect = self.enemy1.get_rect()   #获得低级敌机的尺寸
        # 在窗口的5倍之上的距离中产生飞机
        self.rect.left , self.rect.top = [randint(0 , self.width - self.rect.width ),\
                                                     randint(-5*self.height , 0)]
        self.speed = 1  # 设置小敌机移动的速度

    def move(self):    # 小敌机的移动函数
        if self.rect.top < self.height:    #如果小飞机的底超出窗口的下边框
            self.rect.top += self.speed  #小飞机向下移动他的速度
        else:  #如果小飞机已经超出窗口的下边界框
            self.reset() #重置小飞机

    def reset(self):   #重置小飞机函数
        # 在窗口的5倍之上的距离中产生飞机
        self.rect.left, self.rect.top = [randint(0 , self.width - self.rect.width ),\
                                                     randint(-5*self.height, 0)]

4.2 中飞机

写在小敌机类下面

# 中敌机
class MiddleEnemy(pygame.sprite.Sprite):  #定义中敌机,继承自动画精灵
    def __init__(self,bg_size,enemy2_image):
        pygame.sprite.Sprite.__init__(self)
        self.enemy2 = pygame.image.load(enemy2_image).convert_alpha()   #载入中级敌机图片
        self.width,self.height = bg_size[0], bg_size[1]   #获取生成低级敌机的活动范围
        self.rect = self.enemy2.get_rect()   #获得低级敌机的尺寸
        self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
                                                     randint(-5*self.height, 0)]      #在窗口的5倍之上的距离中产生飞机
        self.speed = 1  #设置中敌机移动的速度

    def move(self) :    #小敌机的移动函数
        if self.rect.top < self.height :    #如果小飞机的底超出窗口的下边框
            self.rect.top += self.speed  #小飞机向下移动他的速度
        else :  #如果小飞机已经超出窗口的下边界框
            self.reset() #重置中飞机

    def reset(self):   #重置中飞机函数
        self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
                                         randint(-5 * self.height, 0)]  # 在窗口的5倍之上的距离中产生飞机

4.3 大敌机

写在中敌机类下面

# 大敌机
class BigEnemy(pygame.sprite.Sprite):  #定义大敌机类,继承自动画精灵
    def __init__(self,bg_size,enemy3_n1_image,enemy3_n2_image):
        pygame.sprite.Sprite.__init__(self)
        self.enemy3_n1 = pygame.image.load(enemy3_n1_image).convert_alpha()   # 载入大敌机图片1
        self.enemy3_n2 = pygame.image.load(enemy3_n2_image).convert_alpha()   # 载入大敌机图片2
        self.width, self.height = bg_size[0] , bg_size[1]   # 获取生成大敌机的活动范围
        self.rect = self.enemy3_n1.get_rect()   #获得大敌机的尺寸
        self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
                                                     randint(-5*self.height, 0)]      #在窗口的5倍之上的距离中产生飞机
        self.speed = 1  #设置大敌机移动的速度

    def move(self) :    #大敌机的移动函数
        if self.rect.top < self.height :    #如果大飞机的底超出窗口的下边框
            self.rect.top += self.speed  #大飞机向下移动他的速度
        else :  #如果大飞机已经超出窗口的下边界框
            self.reset() #重置大飞机

    def reset(self):   #重置大飞机函数
        self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
                                         randint(-5 * self.height, 0)]  # 在窗口的5倍之上的距离中产生飞机

4.4 实例化敌机

    # 生成敌方飞机 定义精灵组,把生成的飞机放到这里
    enemies = pygame.sprite.Group()  # 生成整个飞机组
    smallenemies = pygame.sprite.Group()  # 生成小飞机组
    add_smallenemies(smallenemies, enemies, 20)  # 生成小型飞机
    middleenemies = pygame.sprite.Group()  # 生成中飞机组
    add_middleenemies(middleenemies, enemies, 10)  # 生成中型飞机
    bigenemies = pygame.sprite.Group()  # 生成大飞机组
    add_bigenemies(bigenemies, enemies, 4)  # 生成大型飞机

 

 创建实例化三种敌机生成函数

def add_smallenemies(group1, group2, num):
    for i in range(num):
        e1 = SmallEnemy(bg_size, enemy1_image)
        group1.add(e1)
        group2.add(e1)

def add_middleenemies(group1, group2, num):
    for i in range(num):
        e2 = MiddleEnemy(bg_size, enemy2_image)
        group1.add(e2)
        group2.add(e2)

def add_bigenemies(group1, group2, num):
    for i in range(num):
        e3 = BigEnemy(bg_size, enemy3_n1_image, enemy3_n2_image)
        group1.add(e3)
        group2.add(e3)

 

4.5 绘制显示敌机

可以给大飞机添加音效设置

switch_image为True显示大飞机图片1

switch_image为False显示大飞机图片2

写在绘制背景的下面

# 绘制大型敌机
for each in bigenemies:
    each.move()
    if switch_image:
        screen.blit(each.enemy3_n1, each.rect)
    else:
        screen.blit(each.enemy3_n2, each.rect)
    # 即将出现在画面中,播放音效
    if each.rect.bottom > -50:
        enemy3_fly_sound.play()

# 绘制中型敌机:
for each in middleenemies:
    each.move()
    screen.blit(each.enemy2, each.rect)

# 绘制小型敌机:
for each in smallenemies:
    each.move()
    screen.blit(each.enemy1, each.rect)

 4.6 目前所写代码

from pygame.locals import *
from random import *
import tkinter as tk  # 制作GUI界面库
import pygame
import math
import sys

pygame.init()  # 初始化
pygame.mixer.init()  # 混音器初始化
clock = pygame.time.Clock()  # 设置一个计时器

"""载入音乐文件"""
# 背景音乐
pygame.mixer.music.load("sound/game_music.mp3")  # 设置背景音乐
pygame.mixer.music.set_volume(1)  # 设置音量

# 游戏音效
pygame.mixer.music.load("sound/game_music.mp3")  # 背景音乐
pygame.mixer.music.set_volume(0.2)
bullet_sound = pygame.mixer.Sound("sound/bullet.mp3")  # 子弹音效
bullet_sound.set_volume(0.2)
get_bullet_sound = pygame.mixer.Sound("sound/bullet.mp3")  # 子弹音效
get_bullet_sound.set_volume(0.2)
upgrade_sound = pygame.mixer.Sound("sound/button.mp3")  # 按键音效
upgrade_sound.set_volume(0.2)
enemy3_fly_sound = pygame.mixer.Sound("sound/big_spaceship_flying.mp3")  # 大飞机出现
enemy3_fly_sound.set_volume(0.2)
enemy1_down_sound = pygame.mixer.Sound("sound/enemy1_down.mp3")  # 小飞机击落
enemy1_down_sound.set_volume(0.1)
enemy2_down_sound = pygame.mixer.Sound("sound/enemy2_down.mp3")  # 中飞机击落
enemy2_down_sound.set_volume(0.2)
enemy3_down_sound = pygame.mixer.Sound("sound/enemy3_down.mp3")  # 大飞机击落
enemy3_down_sound.set_volume(0.5)
me_down_sound = pygame.mixer.Sound("sound/use_bomb.mp3")  # 按键音效
me_down_sound.set_volume(0.2)
myself_down_sound = pygame.mixer.Sound("sound/game_over.mp3")  # 按键音效
myself_down_sound.set_volume(0.2)

"""图片文件路径"""
background_image = "image/background.png"  # 背景图的路径
bullet1_image = "image/bullet1.png"  # 第一种子弹图
enemy1_image = "image/enemy1.png"  # 小敌机图片
enemy2_image = "image/enemy2.png"  # 中敌机图片
enemy3_n1_image = "image/enemy3.png"  # 大敌机图片1
enemy3_n2_image = "image/enemy3_n2.png"  # 大敌机图片2
me1_image = "image/hero1.png"  # 自身飞机第一张图片
me2_image = "image/hero2.png"  # 自身飞机第二张图片

# 设置背景
bg_size = width, height = 430, 700  # 背景大小,bg_size为一个元组
screen = pygame.display.set_mode(bg_size)  # 这是背景大小
background = pygame.image.load(background_image).convert_alpha()  # 画背景
pygame.mixer.music.play(-1)  # 播放背景音乐,-1 表示无限循环播放


######################## 设置我方战机类 #########################
class MyPlane(pygame.sprite.Sprite):  # 定义我的飞机类,继承动画精灵类(因为之后要进行碰撞检测)
    def __init__(self, bg_size,me1_image,me2_image):
        self.image1 = pygame.image.load(me1_image).convert_alpha()  # 第一张飞机图片
        self.image2 = pygame.image.load(me2_image).convert_alpha()  # 第二张飞机图片 两张图片是为了做出飞机喷气的效果
        self.rect = self.image1.get_rect()  # 获得飞机图片的尺寸
        self.width, self.height = bg_size[0], bg_size[1]  # 设置飞机允许活动地点
        self.rect.left, self.rect.top = [(self.width - self.rect.width) // 2, \
                                         (self.height - self.rect.height - 20)]  # 注意括号设置我方飞机出现的位置
        self.speed = 10  # 设置飞机出现的速度

    def moveup(self):  # 飞机向上飞的函数
        if self.rect.top > 0:  # 如果我方飞机没有飞出 上方边界
            self.rect.top -= 10  # 那么我方飞机朝上飞10个像素
        else:  # 飞出 上方边界
            self.rect.top = 0  # 锁定在0的位置,不再发生变化

    def movedown(self):  # 飞机向下飞的函数
        if self.rect.bottom < (self.height - 20):  # 如果我方飞机没有飞出 上方边界
            self.rect.bottom += 10  # 那么我方飞机朝下飞10个像素
        else:  # 飞出 下方边界
            self.rect.bottom = (self.height - 20)  # 锁定在底边界上方60的位置,不再发生变化

    def moveleft(self):  # 飞机向左飞的函数
        if self.rect.left > 0:  # 如果我方飞机没有飞出 左方边界
            self.rect.left -= 10  # 那么我方飞机朝下左10个像素
        else:  # 飞出 左方边界
            self.rect.left = 0  # 锁定在左边界的位置,不再发生变化

    def moveright(self):  # 飞机向下飞的函数
        if self.rect.right < self.width:  # 如果我方飞机没有飞出 上方边界
            self.rect.right += 10  # 那么我方飞机朝下飞10个像素
        else:  # 飞出 下方边界
            self.rect.right = self.width  # 锁定在底边界的位置,不再发生变化



####################### 设置敌方战机类 ##########################
# 小飞机
class SmallEnemy(pygame.sprite.Sprite):  #定义小敌机,继承自动画精灵
    def __init__(self,bg_size,enemy1_image):
        pygame.sprite.Sprite.__init__(self)
        self.enemy1 = pygame.image.load(enemy1_image).convert_alpha()   # 载入小敌机图片
        self.width, self.height = bg_size[0] , bg_size[1]   # 获取生成小敌机的活动范围
        self.rect = self.enemy1.get_rect()   #获得低级敌机的尺寸
        # 在窗口的5倍之上的距离中产生飞机
        self.rect.left , self.rect.top = [randint(0 , self.width - self.rect.width ),\
                                                     randint(-5*self.height , 0)]
        self.speed = 2  # 设置小敌机移动的速度

    def move(self):    # 小敌机的移动函数
        if self.rect.top < self.height:    #如果小飞机的底超出窗口的下边框
            self.rect.top += self.speed  #小飞机向下移动他的速度
        else:  #如果小飞机已经超出窗口的下边界框
            self.reset() #重置小飞机

    def reset(self):   #重置小飞机函数
        # 在窗口的5倍之上的距离中产生飞机
        self.rect.left, self.rect.top = [randint(0 , self.width - self.rect.width ),\
                                                     randint(-5*self.height, 0)]

class MiddleEnemy(pygame.sprite.Sprite):  #定义中敌机,继承自动画精灵
    def __init__(self,bg_size,enemy2_image):
        pygame.sprite.Sprite.__init__(self)
        self.enemy2 = pygame.image.load(enemy2_image).convert_alpha()   #载入中级敌机照片
        self.width,self.height = bg_size[0], bg_size[1]   #获取生成低级敌机的活动范围
        self.rect = self.enemy2.get_rect()   #获得低级敌机的尺寸
        self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
                                                     randint(-5*self.height, 0)]      #在窗口的5倍之上的距离中产生飞机
        self.speed = 1  #设置中敌机移动的速度

    def move(self) :    #小敌机的移动函数
        if self.rect.top < self.height :    #如果小飞机的底超出窗口的下边框
            self.rect.top += self.speed  #小飞机向下移动他的速度
        else :  #如果小飞机已经超出窗口的下边界框
            self.reset() #重置中飞机

    def reset(self):   #重置中飞机函数
        self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
                                         randint(-5 * self.height, 0)]  # 在窗口的5倍之上的距离中产生飞机

# 大敌机
class BigEnemy(pygame.sprite.Sprite):  #定义大敌机类,继承自动画精灵
    def __init__(self,bg_size,enemy3_n1_image,enemy3_n2_image):
        pygame.sprite.Sprite.__init__(self)
        self.enemy3_n1 = pygame.image.load(enemy3_n1_image).convert_alpha()   # 载入大敌机图片1
        self.enemy3_n2 = pygame.image.load(enemy3_n2_image).convert_alpha()   # 载入大敌机图片2
        self.width, self.height = bg_size[0] , bg_size[1]   # 获取生成大敌机的活动范围
        self.rect = self.enemy3_n1.get_rect()   #获得大敌机的尺寸
        self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
                                                     randint(-5*self.height, 0)]      #在窗口的5倍之上的距离中产生飞机
        self.speed = 1  #设置大敌机移动的速度

    def move(self) :    #大敌机的移动函数
        if self.rect.top < self.height :    #如果大飞机的底超出窗口的下边框
            self.rect.top += self.speed  #大飞机向下移动他的速度
        else :  #如果大飞机已经超出窗口的下边界框
            self.reset() #重置大飞机

    def reset(self):   #重置大飞机函数
        self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
                                         randint(-5 * self.height, 0)]  # 在窗口的5倍之上的距离中产生飞机



def add_smallenemies(group1, group2, num):
    for i in range(num):
        e1 = SmallEnemy(bg_size, enemy1_image)
        group1.add(e1)
        group2.add(e1)

def add_middleenemies(group1, group2, num):
    for i in range(num):
        e2 = MiddleEnemy(bg_size, enemy2_image)
        group1.add(e2)
        group2.add(e2)

def add_bigenemies(group1, group2, num):
    for i in range(num):
        e3 = BigEnemy(bg_size, enemy3_n1_image, enemy3_n2_image)
        group1.add(e3)
        group2.add(e3)

def main():
    me = MyPlane(bg_size, me1_image, me2_image)  # 生成飞机类
    switch_image = True  # 用于切换战机图片
    delay = 100          # 用于延时

    # 生成敌方飞机 定义精灵组,把生成的飞机放到这里
    enemies = pygame.sprite.Group()  # 生成整个飞机组
    smallenemies = pygame.sprite.Group()  # 生成小飞机组
    add_smallenemies(smallenemies, enemies, 20)  # 生成小型飞机
    middleenemies = pygame.sprite.Group()  # 生成中飞机组
    add_middleenemies(middleenemies, enemies, 10)  # 生成中型飞机
    bigenemies = pygame.sprite.Group()  # 生成大飞机组
    add_bigenemies(bigenemies, enemies, 4)  # 生成大型飞机

    while True:
        for event in pygame.event.get():     # 键盘操作
            if event.type == QUIT:
                sys.exit()
        # 检查是否有上下左右或wsad按下,如有则对飞机进行相应的控制
        key_press = pygame.key.get_pressed()
        if key_press[K_w] or key_press[K_UP]:  # 如果按下上键或者↑
            me.moveup()  # 飞船向上飞行
        elif key_press[K_s] or key_press[K_DOWN]:  # 如果按下下键或者↓
            me.movedown()  # 飞船向下飞行
        elif key_press[K_a] or key_press[K_LEFT]:  # 如果按下左键或者←
            me.moveleft()  # 飞船向左飞行
        elif key_press[K_d] or key_press[K_RIGHT]:  # 如果按下右键或者→
            me.moveright()  # 飞船向右飞行

        screen.blit(background, (0, 0))  # 绘制背景

        # 绘制大型敌机
        for each in bigenemies:
            each.move()
            if switch_image:
                screen.blit(each.enemy3_n1, each.rect)
            else:
                screen.blit(each.enemy3_n2, each.rect)
            # 即将出现在画面中,播放音效
            if each.rect.bottom > -50:
                enemy3_fly_sound.play()

        # 绘制中型敌机:
        for each in middleenemies:
            each.move()
            screen.blit(each.enemy2, each.rect)

        # 绘制小型敌机:
        for each in smallenemies:
            each.move()
            screen.blit(each.enemy1, each.rect)

        # 绘制我方飞机
        if switch_image:  # 2如果改变属性为真  画第一张飞机图
            screen.blit(me.image1, me.rect)
        else:  # 2如果改变属性为假    画第二张飞机图
            screen.blit(me.image2, me.rect)
        # 切换图片
        if delay % 5 == 0:
            switch_image = not switch_image
        delay -= 1
        if delay == 0:
            delay = 100

        pygame.display.flip()  # 不停的刷新画面,不停的绘画
        clock.tick(60)  # 设置帧率


if __name__ == "__main__":
    # 这样做的好处是双击打开时如果出现异常可以报告异常,而不是一闪而过!
    try:
        main()
    except SystemExit:  # 这是按下 × 的异常,直接忽略
        pass

5.碰撞检测

5.1 为何碰撞检测

当敌方飞机和我方飞机发生碰撞时,两方应该是玉石俱焚的,所以在完成之前的基础操作后,现在要为每一个类增加撞击时发生的惨烈画面,具体情况如下:

enemy1:

enemy2:

enemy3:

me:

 

5.2 添加飞机爆炸图片

我方战机

# 添加坠机图片
self.destroy_images = []
self.destroy_images.extend([ \
    pygame.image.load("image/hero_blowup_n1.png").convert_alpha(), \
    pygame.image.load("image/hero_blowup_n2.png").convert_alpha(), \
    pygame.image.load("image/hero_blowup_n3.png").convert_alpha(), \
    pygame.image.load("image/hero_blowup_n4.png").convert_alpha()
])

 

5.3 判断飞机生存状态

接下来我们要为每一个类添加 active 属性,该属性表示飞机是死是活,也就是说:

当该属性为 True 时,我们就让飞机显示正常的飞行状态,

当该属性为 False 时,表示该飞机已经遇难了,我们就要依次显示 坠机的画面,显示完之后,调用该类的 resert() 方法。

为每个飞机类添加 active 属性

        self.active = True   # 表示飞机生存状态

大中小敌机需要在reset()函数上多添加一次

5.4 飞机爆炸状态显示

设置图片状态索引

# 中弹图片索引
e1_destroy_index = 0
e2_destroy_index = 0
e3_destroy_index = 0
me_destroy_index = 0

 

 大飞机毁灭状态添加

for each in bigenemies:
    if each.active:  # 如果大型敌机为生存状态
        each.move()
        if switch_image:
            screen.blit(each.enemy3_n1, each.rect)
        else:
            screen.blit(each.enemy3_n2, each.rect)
        # 即将出现在画面中,播放音效
        if each.rect.bottom > -50:
            enemy3_fly_sound.play()
    else: # 毁灭
        if not (delay % 3):  # 设置两张照片转换的时间延时
            # 只需要播放一次
            if e3_destroy_index == 0:
                enemy3_down_sound.play()

            screen.blit(each.destroy_images[e3_destroy_index], each.rect)
            e3_destroy_index = (e3_destroy_index + 1) % 6  # 循环播放爆炸图片
            if e3_destroy_index == 0:
                enemy3_fly_sound.stop()  # 关闭声音
                each.reset()

中飞机毁灭状态添加

# 绘制中型敌机:
for each in middleenemies:
    if each.active:
        each.move()
        screen.blit(each.enemy2, each.rect)
    else:
        # 毁灭
        if not (delay % 3):
            if e2_destroy_index == 0:
                enemy2_down_sound.play()
            screen.blit(each.destroy_images[e2_destroy_index], each.rect)
            e2_destroy_index = (e2_destroy_index + 1) % 4  # 循环播放爆炸图片
            if e2_destroy_index == 0:
                each.reset()

小飞机毁灭状态添加

# 绘制小型敌机:
for each in smallenemies:
    if each.active:
        each.move()
        screen.blit(each.enemy1, each.rect)
    else:
        # 毁灭
        if not(delay%3):
            if e1_destroy_index == 0:
                enemy1_down_sound.play()
            screen.blit(each.destroy_images[e1_destroy_index], each.rect)
            e1_destroy_index = (e1_destroy_index + 1)%4    # 循环播放爆炸图片
            if e1_destroy_index == 0:
                each.reset()

 

设置变量running

running 为True,表示游戏正常运行

running 为False,表示游戏结束

running = True      # 游戏执行状态

while running:

我方飞机毁灭状态添加

# 绘制我方飞机
if me.active:
    if switch_image:  # 如果改变属性为真  画第一张飞机图
        screen.blit(me.image1, me.rect)
    else:  # 2如果改变属性为假    画第二张飞机图
        screen.blit(me.image2, me.rect)
else:
    # 毁灭
    if not (delay % 3):
        if me_destroy_index == 0:
            me_down_sound.play()
        screen.blit(me.destroy_images[me_destroy_index], me.rect)
        me_destroy_index = (me_destroy_index + 1) % 4  # 循环播放爆炸图片
        if me_destroy_index == 0:
            print("Game Over")
            running = False

5.5 检测是否发生碰撞

写在我方飞机的上面

# 检测我方飞机和其他飞机发生碰撞  spritecollide矩形区域
enemies_down = pygame.sprite.spritecollide(me, enemies, False)
if enemies_down:
    me.active = False
    for e in enemies_down:
        e.active = False

5.6 完美碰撞检测

给类添加上mask属性,之后可以按照完美碰撞( 检测透明部分)

        # 我方飞机
        self.mask = pygame.mask.from_surface(self.image1)     
        # 小敌机
        self.mask = pygame.mask.from_surface(self.enemy1)
        # 中敌机
        self.mask = pygame.mask.from_surface(self.enemy2)
        # 大敌机
        self.mask = pygame.mask.from_surface(self.enemy3_n1)

 

from pygame.locals import *
from random import *
import traceback
import tkinter as tk  # 制作GUI界面库
import pygame
import math
import sys

pygame.init()  # 初始化
pygame.mixer.init()  # 混音器初始化
clock = pygame.time.Clock()  # 设置一个计时器

"""载入音乐文件"""
# 背景音乐
pygame.mixer.music.load("sound/game_music.mp3")  # 设置背景音乐
pygame.mixer.music.set_volume(1)  # 设置音量

# 游戏音效
pygame.mixer.music.load("sound/game_music.mp3")  # 背景音乐
pygame.mixer.music.set_volume(0.2)
bullet_sound = pygame.mixer.Sound("sound/bullet.mp3")  # 子弹音效
bullet_sound.set_volume(0.2)
get_bullet_sound = pygame.mixer.Sound("sound/bullet.mp3")  # 子弹音效
get_bullet_sound.set_volume(0.2)
upgrade_sound = pygame.mixer.Sound("sound/button.mp3")  # 按键音效
upgrade_sound.set_volume(0.2)
enemy3_fly_sound = pygame.mixer.Sound("sound/big_spaceship_flying.mp3")  # 大飞机出现
enemy3_fly_sound.set_volume(0.2)
enemy1_down_sound = pygame.mixer.Sound("sound/enemy1_down.mp3")  # 小飞机击落
enemy1_down_sound.set_volume(0.1)
enemy2_down_sound = pygame.mixer.Sound("sound/enemy2_down.mp3")  # 中飞机击落
enemy2_down_sound.set_volume(0.2)
enemy3_down_sound = pygame.mixer.Sound("sound/enemy3_down.mp3")  # 大飞机击落
enemy3_down_sound.set_volume(0.5)
me_down_sound = pygame.mixer.Sound("sound/use_bomb.mp3")  # 按键音效
me_down_sound.set_volume(0.2)
myself_down_sound = pygame.mixer.Sound("sound/game_over.mp3")  # 按键音效
myself_down_sound.set_volume(0.2)

"""图片文件路径"""
background_image = "image/background.png"  # 背景图的路径
bullet1_image = "image/bullet1.png"  # 第一种子弹图
enemy1_image = "image/enemy1.png"  # 小敌机图片
enemy2_image = "image/enemy2.png"  # 中敌机图片
enemy3_n1_image = "image/enemy3.png"  # 大敌机图片1
enemy3_n2_image = "image/enemy3_n2.png"  # 大敌机图片2
me1_image = "image/hero1.png"  # 自身飞机第一张图片
me2_image = "image/hero2.png"  # 自身飞机第二张图片

# 设置背景
bg_size = width, height = 430, 700  # 背景大小,bg_size为一个元组
screen = pygame.display.set_mode(bg_size)  # 这是背景大小
background = pygame.image.load(background_image).convert_alpha()  # 画背景
pygame.mixer.music.play(-1)  # 播放背景音乐,-1 表示无限循环播放


######################## 设置我方战机类 #########################
class MyPlane(pygame.sprite.Sprite):  # 定义我的飞机类,继承动画精灵类(因为之后要进行碰撞检测)
    def __init__(self, bg_size,me1_image,me2_image):
        self.me1_image = me1_image
        self.me2_image = me2_image
        self.image1 = pygame.image.load(me1_image).convert_alpha()  # 第一张飞机图片
        self.image2 = pygame.image.load(me2_image).convert_alpha()  # 第二张飞机图片 两张图片是为了做出飞机喷气的效果
        self.rect = self.image1.get_rect()  # 获得飞机图片的尺寸
        self.width, self.height = bg_size[0], bg_size[1]  # 设置飞机允许活动地点
        self.rect.left, self.rect.top = [(self.width - self.rect.width) // 2, \
                                         (self.height - self.rect.height - 20)]  # 注意括号设置我方飞机出现的位置
        self.speed = 10  # 设置飞机出现的速度
        # 添加坠机图片
        self.destroy_images = []
        self.destroy_images.extend([ \
            pygame.image.load("image/hero_blowup_n1.png").convert_alpha(), \
            pygame.image.load("image/hero_blowup_n2.png").convert_alpha(), \
            pygame.image.load("image/hero_blowup_n3.png").convert_alpha(), \
            pygame.image.load("image/hero_blowup_n4.png").convert_alpha()
        ])
        self.active = True  # 表示飞机生存状态
        self.mask = pygame.mask.from_surface(self.image1)     # 给类添加上mask属性,之后可以按照完美碰撞

    def moveup(self):  # 飞机向上飞的函数
        if self.rect.top > 0:  # 如果我方飞机没有飞出 上方边界
            self.rect.top -= 10  # 那么我方飞机朝上飞10个像素
        else:  # 飞出 上方边界
            self.rect.top = 0  # 锁定在0的位置,不再发生变化

    def movedown(self):  # 飞机向下飞的函数
        if self.rect.bottom < (self.height - 20):  # 如果我方飞机没有飞出 上方边界
            self.rect.bottom += 10  # 那么我方飞机朝下飞10个像素
        else:  # 飞出 下方边界
            self.rect.bottom = (self.height - 20)  # 锁定在底边界上方60的位置,不再发生变化

    def moveleft(self):  # 飞机向左飞的函数
        if self.rect.left > 0:  # 如果我方飞机没有飞出 左方边界
            self.rect.left -= 10  # 那么我方飞机朝下左10个像素
        else:  # 飞出 左方边界
            self.rect.left = 0  # 锁定在左边界的位置,不再发生变化

    def moveright(self):  # 飞机向下飞的函数
        if self.rect.right < self.width:  # 如果我方飞机没有飞出 上方边界
            self.rect.right += 10  # 那么我方飞机朝下飞10个像素
        else:  # 飞出 下方边界
            self.rect.right = self.width  # 锁定在底边界的位置,不再发生变化



####################### 设置敌方战机类 ##########################
# 小飞机
class SmallEnemy(pygame.sprite.Sprite):  #定义小敌机,继承自动画精灵
    def __init__(self,bg_size,enemy1_image):
        pygame.sprite.Sprite.__init__(self)
        self.enemy1 = pygame.image.load(enemy1_image).convert_alpha()   # 载入小敌机图片
        self.width, self.height = bg_size[0] , bg_size[1]   # 获取生成小敌机的活动范围
        self.rect = self.enemy1.get_rect()   #获得低级敌机的尺寸
        # 在窗口的5倍之上的距离中产生飞机
        self.rect.left , self.rect.top = [randint(0 , self.width - self.rect.width ),\
                                                     randint(-5*self.height , 0)]
        self.speed = 2  # 设置小敌机移动的速度
        # 添加坠机图片
        self.destroy_images = []
        self.destroy_images.extend([\
            pygame.image.load("image/enemy1_down1.png").convert_alpha(), \
            pygame.image.load("image/enemy1_down2.png").convert_alpha(), \
            pygame.image.load("image/enemy1_down3.png").convert_alpha(), \
            pygame.image.load("image/enemy1_down4.png").convert_alpha()])
        self.active = True  # 表示飞机生存状态
        self.mask = pygame.mask.from_surface(self.enemy1)   # 给类添加上mask属性,之后可以按照完美碰撞

    def move(self):    # 小敌机的移动函数
        if self.rect.top < self.height:    #如果小飞机的底超出窗口的下边框
            self.rect.top += self.speed  #小飞机向下移动他的速度
        else:  #如果小飞机已经超出窗口的下边界框
            self.reset() #重置小飞机

    def reset(self):   #重置小飞机函数
        self.active = True  # 表示飞机生存状态
        # 在窗口的5倍之上的距离中产生飞机
        self.rect.left, self.rect.top = [randint(0 , self.width - self.rect.width ),\
                                                     randint(-5*self.height, 0)]

class MiddleEnemy(pygame.sprite.Sprite):  #定义中敌机,继承自动画精灵
    def __init__(self,bg_size,enemy2_image):
        pygame.sprite.Sprite.__init__(self)
        self.enemy2 = pygame.image.load(enemy2_image).convert_alpha()   #载入中级敌机照片
        self.width,self.height = bg_size[0], bg_size[1]   #获取生成低级敌机的活动范围
        self.rect = self.enemy2.get_rect()   #获得低级敌机的尺寸
        self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
                                                     randint(-5*self.height, 0)]      #在窗口的5倍之上的距离中产生飞机
        self.speed = 1  #设置中敌机移动的速度
        # 添加坠机图片
        self.destroy_images = []
        self.destroy_images.extend([ \
            pygame.image.load("image/enemy2_down1.png").convert_alpha(), \
            pygame.image.load("image/enemy2_down2.png").convert_alpha(), \
            pygame.image.load("image/enemy2_down3.png").convert_alpha(), \
            pygame.image.load("image/enemy2_down4.png").convert_alpha()])
        self.active = True  # 表示飞机生存状态
        self.mask = pygame.mask.from_surface(self.enemy2)   # 给类添加上mask属性,之后可以按照完美碰撞

    def move(self):    #中敌机的移动函数
        if self.rect.top < self.height :    #如果小飞机的底超出窗口的下边框
            self.rect.top += self.speed  #小飞机向下移动他的速度
        else :  #如果小飞机已经超出窗口的下边界框
            self.reset() #重置中飞机

    def reset(self):   #重置中飞机函数
        self.active = True  # 表示飞机生存状态
        self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
                                         randint(-5 * self.height, 0)]  # 在窗口的5倍之上的距离中产生飞机

# 大敌机
class BigEnemy(pygame.sprite.Sprite):  #定义大敌机类,继承自动画精灵
    def __init__(self,bg_size,enemy3_n1_image,enemy3_n2_image):
        pygame.sprite.Sprite.__init__(self)
        self.enemy3_n1 = pygame.image.load(enemy3_n1_image).convert_alpha()   # 载入大敌机图片1
        self.enemy3_n2 = pygame.image.load(enemy3_n2_image).convert_alpha()   # 载入大敌机图片2
        self.width, self.height = bg_size[0] , bg_size[1]   # 获取生成大敌机的活动范围
        self.rect = self.enemy3_n1.get_rect()   #获得大敌机的尺寸
        self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
                                                     randint(-5*self.height, 0)]      #在窗口的5倍之上的距离中产生飞机
        self.speed = 1  #设置大敌机移动的速度
        # 添加坠机图片
        self.destroy_images = []
        self.destroy_images.extend([ \
            pygame.image.load("image/enemy3_down1.png").convert_alpha(), \
            pygame.image.load("image/enemy3_down2.png").convert_alpha(), \
            pygame.image.load("image/enemy3_down3.png").convert_alpha(), \
            pygame.image.load("image/enemy3_down4.png").convert_alpha(), \
            pygame.image.load("image/enemy3_down5.png").convert_alpha(), \
            pygame.image.load("image/enemy3_down6.png").convert_alpha()])
        self.active = True  # 表示飞机生存状态
        self.mask = pygame.mask.from_surface(self.enemy3_n1)  # 给类添加上mask属性,之后可以按照完美碰撞

    def move(self):    #大敌机的移动函数
        if self.rect.top < self.height :    #如果大飞机的底超出窗口的下边框
            self.rect.top += self.speed  #大飞机向下移动他的速度
        else:  #如果大飞机已经超出窗口的下边界框
            self.reset() #重置大飞机

    def reset(self):   #重置大飞机函数
        self.active = True  # 表示飞机生存状态
        self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
                                         randint(-5 * self.height, 0)]  # 在窗口的5倍之上的距离中产生飞机



def add_smallenemies(group1, group2, num):
    for i in range(num):
        e1 = SmallEnemy(bg_size, enemy1_image)
        group1.add(e1)
        group2.add(e1)

def add_middleenemies(group1, group2, num):
    for i in range(num):
        e2 = MiddleEnemy(bg_size, enemy2_image)
        group1.add(e2)
        group2.add(e2)

def add_bigenemies(group1, group2, num):
    for i in range(num):
        e3 = BigEnemy(bg_size, enemy3_n1_image, enemy3_n2_image)
        group1.add(e3)
        group2.add(e3)

def main():
    me = MyPlane(bg_size, me1_image, me2_image)  # 生成飞机类
    switch_image = True  # 用于切换战机图片
    delay = 100          # 用于延时

    # 生成敌方飞机 定义精灵组,把生成的飞机放到这里
    enemies = pygame.sprite.Group()  # 生成整个飞机组
    smallenemies = pygame.sprite.Group()  # 生成小飞机组
    add_smallenemies(smallenemies, enemies, 20)  # 生成小型飞机
    middleenemies = pygame.sprite.Group()  # 生成中飞机组
    add_middleenemies(middleenemies, enemies, 10)  # 生成中型飞机
    bigenemies = pygame.sprite.Group()  # 生成大飞机组
    add_bigenemies(bigenemies, enemies, 4)  # 生成大型飞机

    # 中弹图片索引
    e1_destroy_index = 0
    e2_destroy_index = 0
    e3_destroy_index = 0
    me_destroy_index = 0

    running = True      # 游戏执行状态

    while running:
        for event in pygame.event.get():     # 键盘操作
            if event.type == QUIT:
                sys.exit()
        # 检查是否有上下左右或wsad按下,如有则对飞机进行相应的控制
        key_press = pygame.key.get_pressed()
        if key_press[K_w] or key_press[K_UP]:  # 如果按下上键或者↑
            me.moveup()  # 飞船向上飞行
        elif key_press[K_s] or key_press[K_DOWN]:  # 如果按下下键或者↓
            me.movedown()  # 飞船向下飞行
        elif key_press[K_a] or key_press[K_LEFT]:  # 如果按下左键或者←
            me.moveleft()  # 飞船向左飞行
        elif key_press[K_d] or key_press[K_RIGHT]:  # 如果按下右键或者→
            me.moveright()  # 飞船向右飞行

        screen.blit(background, (0, 0))  # 绘制背景

        # 绘制大型敌机
        for each in bigenemies:
            if each.active:  # 如果大型敌机为生存状态
                each.move()
                if switch_image:
                    screen.blit(each.enemy3_n1, each.rect)
                else:
                    screen.blit(each.enemy3_n2, each.rect)
                # 即将出现在画面中,播放音效
                if each.rect.bottom > -50:
                    enemy3_fly_sound.play()
            else: # 毁灭
                if not (delay % 3):  # 设置两张照片转换的时间延时
                    # 只需要播放一次
                    if e3_destroy_index == 0:
                        enemy3_down_sound.play()

                    screen.blit(each.destroy_images[e3_destroy_index], each.rect)
                    e3_destroy_index = (e3_destroy_index + 1) % 6  # 循环播放爆炸图片
                    if e3_destroy_index == 0:
                        enemy3_fly_sound.stop()  # 关闭声音
                        each.reset()

        # 绘制中型敌机:
        for each in middleenemies:
            if each.active:
                each.move()
                screen.blit(each.enemy2, each.rect)
            else:
                # 毁灭
                if not (delay % 3):
                    if e2_destroy_index == 0:
                        enemy2_down_sound.play()
                    screen.blit(each.destroy_images[e2_destroy_index], each.rect)
                    e2_destroy_index = (e2_destroy_index + 1) % 4  # 循环播放爆炸图片
                    if e2_destroy_index == 0:
                        each.reset()

        # 绘制小型敌机:
        for each in smallenemies:
            if each.active:
                each.move()
                screen.blit(each.enemy1, each.rect)
            else:
                # 毁灭
                if not(delay%3):
                    if e1_destroy_index == 0:
                        enemy1_down_sound.play()
                    screen.blit(each.destroy_images[e1_destroy_index], each.rect)
                    e1_destroy_index = (e1_destroy_index + 1)%4    # 循环播放爆炸图片
                    if e1_destroy_index == 0:
                        each.reset()

        # 检测我方飞机和其他飞机发生碰撞  spritecollide矩形区域, pygame.sprite.collide_mask检测边缘碰撞
        enemies_down = pygame.sprite.spritecollide(me, enemies, False, pygame.sprite.collide_mask)
        if enemies_down:
            me.active = False
            for e in enemies_down:
                e.active = False

        # 绘制我方飞机
        if me.active:
            if switch_image:  # 如果改变属性为真  画第一张飞机图
                screen.blit(me.image1, me.rect)
            else:  # 2如果改变属性为假    画第二张飞机图
                screen.blit(me.image2, me.rect)
        else:
            # 毁灭
            if not (delay % 3):
                if me_destroy_index == 0:
                    me_down_sound.play()
                screen.blit(me.destroy_images[me_destroy_index], me.rect)
                me_destroy_index = (me_destroy_index + 1) % 4  # 循环播放爆炸图片
                if me_destroy_index == 0:
                    print("Game Over")
                    running = False
        # 切换图片
        if delay % 5 == 0:
            switch_image = not switch_image
        delay -= 1
        if delay == 0:
            delay = 100

        pygame.display.flip()  # 不停的刷新画面,不停的绘画
        clock.tick(60)  # 设置帧率


if __name__ == "__main__":
    # 这样做的好处是双击打开时如果出现异常可以报告异常,而不是一闪而过!
    try:
        main()
    except SystemExit:  # 这是按下 × 的异常,直接忽略
        pass

  

6.设置子弹

6.1 添加子弹类

写在敌机类的下面

########################### 子弹 ################################
class Bullet1(pygame.sprite.Sprite):     #定义子弹类,继承动画精灵类(因为之后要进行碰撞检测)
    def __init__(self, position,bullet1_image):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load(bullet1_image).convert_alpha()    # 加载子弹1图
        self.rect = self.image.get_rect()            # 获得子弹1图的尺寸
        self.rect.left, self.rect.top = position     # 把飞机的位置传给子弹
        self.speed = 15    # 子弹运动的速度
        self.avtive = True   # 用来表示这颗子弹是或否失效

    def move(self):
        self.rect.top -= self.speed  # 子弹运动

        if self.rect.top < 0:    # 如果子弹射出屏幕外
            self.active = False   # 将子弹设为失效

    def reset(self, position):
        self.rect.left, self.rect.top = position
        self.active = True

6.2 生成子弹

写在生成飞机下面

# 生成普通子弹
bullet1 = []
bullet1_index = 0
bullet_num = 4
for i in range(bullet_num):
    bullet1.append(Bullet1(me.rect.midtop, bullet1_image))  # midtop表示顶部

6.3 设置子弹发射频率 

    # 发射子弹 每10桢绘制一次子弹
    if not (delay % 10):
        bullet1[bullet1_index].reset(me.rect.midtop)
        bullet1_index = (bullet1_index + 1) % bullet_num

6.4 检测子弹是否击中敌机 

    for b in bullet1:  # 对于列表中的的所有子弹
        if b.active:  # 如果子弹有效
            b.move()  # 子弹移动
            screen.blit(b.image, b.rect)  # 把子弹绘制在背景上
            # 将所有与子弹发生碰撞的敌方飞机都加入到组中
            enemies_hit = pygame.sprite.spritecollide(b, enemies, False,\
                                                      collided=pygame.sprite.collide_mask)
            if enemies_hit:  # 如果有敌机与子弹相碰
                for e in enemies_hit:  # 对于所有相撞的敌机
                    e.active = False  # 将他们的状态设置为死亡

6.5 目前所写代码 

from pygame.locals import *
from random import *
import traceback
import tkinter as tk  # 制作GUI界面库
import pygame
import math
import sys

pygame.init()  # 初始化
pygame.mixer.init()  # 混音器初始化
clock = pygame.time.Clock()  # 设置一个计时器

"""载入音乐文件"""
# 背景音乐
pygame.mixer.music.load("sound/game_music.mp3")  # 设置背景音乐
pygame.mixer.music.set_volume(1)  # 设置音量

# 游戏音效
pygame.mixer.music.load("sound/game_music.mp3")  # 背景音乐
pygame.mixer.music.set_volume(0.2)
bullet_sound = pygame.mixer.Sound("sound/bullet.mp3")  # 子弹音效
bullet_sound.set_volume(0.2)
get_bullet_sound = pygame.mixer.Sound("sound/bullet.mp3")  # 子弹音效
get_bullet_sound.set_volume(0.2)
upgrade_sound = pygame.mixer.Sound("sound/button.mp3")  # 按键音效
upgrade_sound.set_volume(0.2)
enemy3_fly_sound = pygame.mixer.Sound("sound/big_spaceship_flying.mp3")  # 大飞机出现
enemy3_fly_sound.set_volume(0.2)
enemy1_down_sound = pygame.mixer.Sound("sound/enemy1_down.mp3")  # 小飞机击落
enemy1_down_sound.set_volume(0.1)
enemy2_down_sound = pygame.mixer.Sound("sound/enemy2_down.mp3")  # 中飞机击落
enemy2_down_sound.set_volume(0.2)
enemy3_down_sound = pygame.mixer.Sound("sound/enemy3_down.mp3")  # 大飞机击落
enemy3_down_sound.set_volume(0.5)
me_down_sound = pygame.mixer.Sound("sound/use_bomb.mp3")  # 按键音效
me_down_sound.set_volume(0.2)
myself_down_sound = pygame.mixer.Sound("sound/game_over.mp3")  # 按键音效
myself_down_sound.set_volume(0.2)

"""图片文件路径"""
background_image = "image/background.png"  # 背景图的路径
bullet1_image = "image/bullet1.png"  # 第一种子弹图
enemy1_image = "image/enemy1.png"  # 小敌机图片
enemy2_image = "image/enemy2.png"  # 中敌机图片
enemy3_n1_image = "image/enemy3.png"  # 大敌机图片1
enemy3_n2_image = "image/enemy3_n2.png"  # 大敌机图片2
me1_image = "image/hero1.png"  # 自身飞机第一张图片
me2_image = "image/hero2.png"  # 自身飞机第二张图片

# 设置背景
bg_size = width, height = 430, 700  # 背景大小,bg_size为一个元组
screen = pygame.display.set_mode(bg_size)  # 这是背景大小
background = pygame.image.load(background_image).convert_alpha()  # 画背景
pygame.mixer.music.play(-1)  # 播放背景音乐,-1 表示无限循环播放


######################## 设置我方战机类 #########################
class MyPlane(pygame.sprite.Sprite):  # 定义我的飞机类,继承动画精灵类(因为之后要进行碰撞检测)
    def __init__(self, bg_size,me1_image,me2_image):
        self.me1_image = me1_image
        self.me2_image = me2_image
        self.image1 = pygame.image.load(me1_image).convert_alpha()  # 第一张飞机图片
        self.image2 = pygame.image.load(me2_image).convert_alpha()  # 第二张飞机图片 两张图片是为了做出飞机喷气的效果
        self.rect = self.image1.get_rect()  # 获得飞机图片的尺寸
        self.width, self.height = bg_size[0], bg_size[1]  # 设置飞机允许活动地点
        self.rect.left, self.rect.top = [(self.width - self.rect.width) // 2, \
                                         (self.height - self.rect.height - 20)]  # 注意括号设置我方飞机出现的位置
        self.speed = 10  # 设置飞机出现的速度
        # 添加坠机图片
        self.destroy_images = []
        self.destroy_images.extend([ \
            pygame.image.load("image/hero_blowup_n1.png").convert_alpha(), \
            pygame.image.load("image/hero_blowup_n2.png").convert_alpha(), \
            pygame.image.load("image/hero_blowup_n3.png").convert_alpha(), \
            pygame.image.load("image/hero_blowup_n4.png").convert_alpha()
        ])
        self.active = True  # 表示飞机生存状态
        self.mask = pygame.mask.from_surface(self.image1)     # 给类添加上mask属性,之后可以按照完美碰撞

    def moveup(self):  # 飞机向上飞的函数
        if self.rect.top > 0:  # 如果我方飞机没有飞出 上方边界
            self.rect.top -= 10  # 那么我方飞机朝上飞10个像素
        else:  # 飞出 上方边界
            self.rect.top = 0  # 锁定在0的位置,不再发生变化

    def movedown(self):  # 飞机向下飞的函数
        if self.rect.bottom < (self.height - 20):  # 如果我方飞机没有飞出 上方边界
            self.rect.bottom += 10  # 那么我方飞机朝下飞10个像素
        else:  # 飞出 下方边界
            self.rect.bottom = (self.height - 20)  # 锁定在底边界上方60的位置,不再发生变化

    def moveleft(self):  # 飞机向左飞的函数
        if self.rect.left > 0:  # 如果我方飞机没有飞出 左方边界
            self.rect.left -= 10  # 那么我方飞机朝下左10个像素
        else:  # 飞出 左方边界
            self.rect.left = 0  # 锁定在左边界的位置,不再发生变化

    def moveright(self):  # 飞机向下飞的函数
        if self.rect.right < self.width:  # 如果我方飞机没有飞出 上方边界
            self.rect.right += 10  # 那么我方飞机朝下飞10个像素
        else:  # 飞出 下方边界
            self.rect.right = self.width  # 锁定在底边界的位置,不再发生变化



####################### 设置敌方战机类 ##########################
# 小飞机
class SmallEnemy(pygame.sprite.Sprite):  #定义小敌机,继承自动画精灵
    def __init__(self,bg_size,enemy1_image):
        pygame.sprite.Sprite.__init__(self)
        self.enemy1 = pygame.image.load(enemy1_image).convert_alpha()   # 载入小敌机图片
        self.width, self.height = bg_size[0] , bg_size[1]   # 获取生成小敌机的活动范围
        self.rect = self.enemy1.get_rect()   #获得低级敌机的尺寸
        # 在窗口的5倍之上的距离中产生飞机
        self.rect.left , self.rect.top = [randint(0 , self.width - self.rect.width ),\
                                                     randint(-5*self.height , 0)]
        self.speed = 2  # 设置小敌机移动的速度
        # 添加坠机图片
        self.destroy_images = []
        self.destroy_images.extend([\
            pygame.image.load("image/enemy1_down1.png").convert_alpha(), \
            pygame.image.load("image/enemy1_down2.png").convert_alpha(), \
            pygame.image.load("image/enemy1_down3.png").convert_alpha(), \
            pygame.image.load("image/enemy1_down4.png").convert_alpha()])
        self.active = True  # 表示飞机生存状态
        self.mask = pygame.mask.from_surface(self.enemy1)   # 给类添加上mask属性,之后可以按照完美碰撞

    def move(self):    # 小敌机的移动函数
        if self.rect.top < self.height:    #如果小飞机的底超出窗口的下边框
            self.rect.top += self.speed  #小飞机向下移动他的速度
        else:  #如果小飞机已经超出窗口的下边界框
            self.reset() #重置小飞机

    def reset(self):   #重置小飞机函数
        self.active = True  # 飞机碰撞时写
        # 在窗口的5倍之上的距离中产生飞机
        self.rect.left, self.rect.top = [randint(0 , self.width - self.rect.width ),\
                                                     randint(-5*self.height, 0)]

class MiddleEnemy(pygame.sprite.Sprite):  #定义中敌机,继承自动画精灵
    def __init__(self,bg_size,enemy2_image):
        pygame.sprite.Sprite.__init__(self)
        self.enemy2 = pygame.image.load(enemy2_image).convert_alpha()   #载入中级敌机照片
        self.width,self.height = bg_size[0], bg_size[1]   #获取生成低级敌机的活动范围
        self.rect = self.enemy2.get_rect()   #获得低级敌机的尺寸
        self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
                                                     randint(-5*self.height, 0)]      #在窗口的5倍之上的距离中产生飞机
        self.speed = 1  #设置中敌机移动的速度
        # 添加坠机图片
        self.destroy_images = []
        self.destroy_images.extend([ \
            pygame.image.load("image/enemy2_down1.png").convert_alpha(), \
            pygame.image.load("image/enemy2_down2.png").convert_alpha(), \
            pygame.image.load("image/enemy2_down3.png").convert_alpha(), \
            pygame.image.load("image/enemy2_down4.png").convert_alpha()])
        self.active = True  # 表示飞机生存状态
        self.mask = pygame.mask.from_surface(self.enemy2)   # 给类添加上mask属性,之后可以按照完美碰撞

    def move(self):    #中敌机的移动函数
        if self.rect.top < self.height :    #如果小飞机的底超出窗口的下边框
            self.rect.top += self.speed  #小飞机向下移动他的速度
        else :  #如果小飞机已经超出窗口的下边界框
            self.reset() #重置中飞机

    def reset(self):   #重置中飞机函数
        self.active = True  # 飞机碰撞时写
        self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
                                         randint(-5 * self.height, 0)]  # 在窗口的5倍之上的距离中产生飞机

# 大敌机
class BigEnemy(pygame.sprite.Sprite):  #定义大敌机类,继承自动画精灵
    def __init__(self,bg_size,enemy3_n1_image,enemy3_n2_image):
        pygame.sprite.Sprite.__init__(self)
        self.enemy3_n1 = pygame.image.load(enemy3_n1_image).convert_alpha()   # 载入大敌机图片1
        self.enemy3_n2 = pygame.image.load(enemy3_n2_image).convert_alpha()   # 载入大敌机图片2
        self.width, self.height = bg_size[0] , bg_size[1]   # 获取生成大敌机的活动范围
        self.rect = self.enemy3_n1.get_rect()   #获得大敌机的尺寸
        self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
                                                     randint(-5*self.height, 0)]      #在窗口的5倍之上的距离中产生飞机
        self.speed = 1  #设置大敌机移动的速度
        # 添加坠机图片
        self.destroy_images = []
        self.destroy_images.extend([ \
            pygame.image.load("image/enemy3_down1.png").convert_alpha(), \
            pygame.image.load("image/enemy3_down2.png").convert_alpha(), \
            pygame.image.load("image/enemy3_down3.png").convert_alpha(), \
            pygame.image.load("image/enemy3_down4.png").convert_alpha(), \
            pygame.image.load("image/enemy3_down5.png").convert_alpha(), \
            pygame.image.load("image/enemy3_down6.png").convert_alpha()])
        self.active = True  # 表示飞机生存状态
        self.mask = pygame.mask.from_surface(self.enemy3_n1)  # 给类添加上mask属性,之后可以按照完美碰撞

    def move(self):    #大敌机的移动函数
        if self.rect.top < self.height :    #如果大飞机的底超出窗口的下边框
            self.rect.top += self.speed  #大飞机向下移动他的速度
        else:  #如果大飞机已经超出窗口的下边界框
            self.reset() #重置大飞机

    def reset(self):   #重置大飞机函数
        self.active = True  # 飞机碰撞时写
        self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
                                         randint(-5 * self.height, 0)]  # 在窗口的5倍之上的距离中产生飞机

########################### 子弹 ################################
class Bullet1(pygame.sprite.Sprite):     #定义子弹类,继承动画精灵类(因为之后要进行碰撞检测)
    def __init__(self, position, bullet1_image):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load(bullet1_image).convert_alpha()    # 加载子弹1图
        self.rect = self.image.get_rect()            # 获得子弹1图的尺寸
        self.rect.left, self.rect.top = position     # 把飞机的位置传给子弹
        self.speed = 15    # 子弹运动的速度
        self.active = True   # 用来表示这颗子弹是或否失效
        self.mask = pygame.mask.from_surface(self.image)  # 给类添加上mask属性,之后可以按照完美碰撞

    def move(self):
        self.rect.top -= self.speed  # 子弹运动

        if self.rect.top < 0:    # 如果子弹射出屏幕外
            self.active = False   # 将子弹设为失效

    def reset(self, position):
        self.rect.left, self.rect.top = position
        self.active = True


def add_smallenemies(group1, group2, num):
    for i in range(num):
        e1 = SmallEnemy(bg_size, enemy1_image)
        group1.add(e1)
        group2.add(e1)

def add_middleenemies(group1, group2, num):
    for i in range(num):
        e2 = MiddleEnemy(bg_size, enemy2_image)
        group1.add(e2)
        group2.add(e2)

def add_bigenemies(group1, group2, num):
    for i in range(num):
        e3 = BigEnemy(bg_size, enemy3_n1_image, enemy3_n2_image)
        group1.add(e3)
        group2.add(e3)

def main():
    me = MyPlane(bg_size, me1_image, me2_image)  # 生成飞机类
    switch_image = True  # 用于切换战机图片
    delay = 100          # 用于延时

    # 生成敌方飞机 定义精灵组,把生成的飞机放到这里
    enemies = pygame.sprite.Group()  # 生成整个飞机组
    smallenemies = pygame.sprite.Group()  # 生成小飞机组
    add_smallenemies(smallenemies, enemies, 20)  # 生成小型飞机
    middleenemies = pygame.sprite.Group()  # 生成中飞机组
    add_middleenemies(middleenemies, enemies, 10)  # 生成中型飞机
    bigenemies = pygame.sprite.Group()  # 生成大飞机组
    add_bigenemies(bigenemies, enemies, 4)  # 生成大型飞机

    # 生成普通子弹
    bullet1 = []
    bullet1_index = 0
    bullet_num = 4
    for i in range(bullet_num):
        bullet1.append(Bullet1(me.rect.midtop, bullet1_image))  # midtop表示顶部

    # 中弹图片索引
    e1_destroy_index = 0
    e2_destroy_index = 0
    e3_destroy_index = 0
    me_destroy_index = 0

    running = True      # 游戏执行状态

    while running:
        for event in pygame.event.get():     # 键盘操作
            if event.type == QUIT:
                sys.exit()
        # 检查是否有上下左右或wsad按下,如有则对飞机进行相应的控制
        key_press = pygame.key.get_pressed()
        if key_press[K_w] or key_press[K_UP]:  # 如果按下上键或者↑
            me.moveup()  # 飞船向上飞行
        elif key_press[K_s] or key_press[K_DOWN]:  # 如果按下下键或者↓
            me.movedown()  # 飞船向下飞行
        elif key_press[K_a] or key_press[K_LEFT]:  # 如果按下左键或者←
            me.moveleft()  # 飞船向左飞行
        elif key_press[K_d] or key_press[K_RIGHT]:  # 如果按下右键或者→
            me.moveright()  # 飞船向右飞行

        screen.blit(background, (0, 0))  # 绘制背景

        # 绘制大型敌机
        for each in bigenemies:
            if each.active:  # 如果大型敌机为生存状态
                each.move()
                if switch_image:
                    screen.blit(each.enemy3_n1, each.rect)
                else:
                    screen.blit(each.enemy3_n2, each.rect)
                # 即将出现在画面中,播放音效
                if each.rect.bottom > -50:
                    enemy3_fly_sound.play()
            else: # 毁灭
                if not (delay % 3):  # 设置两张照片转换的时间延时
                    # 只需要播放一次
                    if e3_destroy_index == 0:
                        enemy3_down_sound.play()

                    screen.blit(each.destroy_images[e3_destroy_index], each.rect)
                    e3_destroy_index = (e3_destroy_index + 1) % 6  # 循环播放爆炸图片
                    if e3_destroy_index == 0:
                        enemy3_fly_sound.stop()  # 关闭声音
                        each.reset()

        # 绘制中型敌机:
        for each in middleenemies:
            if each.active:
                each.move()
                screen.blit(each.enemy2, each.rect)
            else:
                # 毁灭
                if not (delay % 3):
                    if e2_destroy_index == 0:
                        enemy2_down_sound.play()
                    screen.blit(each.destroy_images[e2_destroy_index], each.rect)
                    e2_destroy_index = (e2_destroy_index + 1) % 4  # 循环播放爆炸图片
                    if e2_destroy_index == 0:
                        each.reset()

        # 绘制小型敌机:
        for each in smallenemies:
            if each.active:
                each.move()
                screen.blit(each.enemy1, each.rect)
            else:
                # 毁灭
                if not(delay%3):
                    if e1_destroy_index == 0:
                        enemy1_down_sound.play()
                    screen.blit(each.destroy_images[e1_destroy_index], each.rect)
                    e1_destroy_index = (e1_destroy_index + 1)%4    # 循环播放爆炸图片
                    if e1_destroy_index == 0:
                        each.reset()

        # 检测我方飞机和其他飞机发生碰撞  spritecollide矩形区域, pygame.sprite.collide_mask检测边缘碰撞
        enemies_down = pygame.sprite.spritecollide(me, enemies, False, pygame.sprite.collide_mask)
        if enemies_down:
            me.active = False
            for e in enemies_down:
                e.active = False

        # 发射子弹 每10桢绘制一次子弹
        if not (delay % 10):
            bullet1[bullet1_index].reset(me.rect.midtop)
            bullet1_index = (bullet1_index + 1) % bullet_num

        # 检测子弹是否击中敌机
        for b in bullet1:  # 对于列表中的的所有子弹
            if b.active:  # 如果子弹有效
                b.move()  # 子弹移动
                screen.blit(b.image, b.rect)  # 把子弹绘制在背景上
                # 将所有与子弹发生碰撞的敌方飞机都加入到组中
                enemies_hit = pygame.sprite.spritecollide(b, enemies, False,\
                                                          collided=pygame.sprite.collide_mask)
                if enemies_hit:  # 如果有敌机与子弹相碰
                    for e in enemies_hit:  # 对于所有相撞的敌机
                        e.active = False  # 将他们的状态设置为死亡

        # 绘制我方飞机
        if me.active:
            if switch_image:  # 如果改变属性为真  画第一张飞机图
                screen.blit(me.image1, me.rect)
            else:  # 2如果改变属性为假    画第二张飞机图
                screen.blit(me.image2, me.rect)
        else:
            # 毁灭
            if not (delay % 3):
                if me_destroy_index == 0:
                    me_down_sound.play()
                screen.blit(me.destroy_images[me_destroy_index], me.rect)
                me_destroy_index = (me_destroy_index + 1) % 4  # 循环播放爆炸图片
                if me_destroy_index == 0:
                    print("Game Over")
                    running = False
        # 切换图片
        if delay % 5 == 0:
            switch_image = not switch_image
        delay -= 1
        if delay == 0:
            delay = 100

        pygame.display.flip()  # 不停的刷新画面,不停的绘画
        clock.tick(60)  # 设置帧率


if __name__ == "__main__":
    # 这样做的好处是双击打开时如果出现异常可以报告异常,而不是一闪而过!
    try:
        main()
    except SystemExit:  # 这是按下 × 的异常,直接忽略
        pass

7.生成血条

7.1 设置颜色

写在设置计时器下面

# 设置游戏名称
pygame.display.set_caption("飞机大战")

# RGB颜色
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
RED = (255, 0, 0)

7.2 设置中大飞机血量 

# 大飞机血量
energy = 20
# 中飞机血量
energy = 8

 

7.3 画中大飞机血条

大飞机 

# 绘制血槽 红黑绿
pygame.draw.line(screen, BLACK, \
                 (each.rect.left, each.rect.top - 5), \
                 (each.rect.right, each.rect.top - 5), \
                 2)

# 当生命大于20%显示绿色,否则显示红色
energy_remain = each.energy / BigEnemy.energy
if energy_remain > 0.2:
    energy_color = GREEN
else:
    energy_color = RED
pygame.draw.line(screen, energy_color, \
                 (each.rect.left, each.rect.top - 5), \
                 (each.rect.left + each.rect.width * energy_remain, \
                  each.rect.top - 5), 2)

 

中飞机

# 绘制血槽 红黑绿
pygame.draw.line(screen, BLACK, \
                 (each.rect.left, each.rect.top - 5), \
                 (each.rect.right, each.rect.top - 5), \
                 2)

# 当生命大于20%显示绿色,否则显示红色
energy_remain = each.energy / MiddleEnemy.energy
if energy_remain > 0.2:
    energy_color = GREEN
else:
    energy_color = RED
pygame.draw.line(screen, energy_color, \
                 (each.rect.left, each.rect.top - 5), \
                 (each.rect.left + each.rect.width * energy_remain, \
                  each.rect.top - 5), 2)

7.4 设置掉血效果 

    # 检测子弹是否击中敌机
    for b in bullet1:  # 对于列表中的的所有子弹
        if b.active:  # 如果子弹有效
            b.move()  # 子弹移动
            screen.blit(b.image, b.rect)  # 把子弹绘制在背景上
            enemies_hit = pygame.sprite.spritecollide(b, enemies, False,
                                                      collided=pygame.sprite.collide_mask)  # 将所有与子弹发生碰撞的敌方飞机都加入到组中
            if enemies_hit:  # 如果有敌机与子弹相碰
                b.active = False  # 将碰撞后在子弹设置为未激活,使其消失,不再继续存在在画面中
                for e in enemies_hit:  # 对于所有相撞的敌机
                    # 中大型敌机
                    if e in middleenemies or e in bigenemies:   # 如果敌机是中型飞机或者大型飞机
                        e.energy -= 1
                        if e.energy == 0:        # 如果生命值变为0
                            e.active = False     # 将敌机的生命属性设置为死亡
                    else:
                        # 小飞机
                        e.active = False

 7.5 目前所写代码

from pygame.locals import *
from random import *
import traceback
import tkinter as tk  # 制作GUI界面库
import pygame
import math
import sys

pygame.init()  # 初始化
pygame.mixer.init()  # 混音器初始化
clock = pygame.time.Clock()  # 设置一个计时器

# 设置游戏名称
pygame.display.set_caption("飞机大战")

# RGB颜色
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
RED = (255, 0, 0)

"""载入音乐文件"""
# 背景音乐
pygame.mixer.music.load("sound/game_music.mp3")  # 设置背景音乐
pygame.mixer.music.set_volume(1)  # 设置音量

# 游戏音效
pygame.mixer.music.load("sound/game_music.mp3")  # 背景音乐
pygame.mixer.music.set_volume(0.2)
bullet_sound = pygame.mixer.Sound("sound/bullet.mp3")  # 子弹音效
bullet_sound.set_volume(0.2)
get_bullet_sound = pygame.mixer.Sound("sound/bullet.mp3")  # 子弹音效
get_bullet_sound.set_volume(0.2)
upgrade_sound = pygame.mixer.Sound("sound/button.mp3")  # 按键音效
upgrade_sound.set_volume(0.2)
enemy3_fly_sound = pygame.mixer.Sound("sound/big_spaceship_flying.mp3")  # 大飞机出现
enemy3_fly_sound.set_volume(0.2)
enemy1_down_sound = pygame.mixer.Sound("sound/enemy1_down.mp3")  # 小飞机击落
enemy1_down_sound.set_volume(0.1)
enemy2_down_sound = pygame.mixer.Sound("sound/enemy2_down.mp3")  # 中飞机击落
enemy2_down_sound.set_volume(0.2)
enemy3_down_sound = pygame.mixer.Sound("sound/enemy3_down.mp3")  # 大飞机击落
enemy3_down_sound.set_volume(0.5)
me_down_sound = pygame.mixer.Sound("sound/use_bomb.mp3")  # 按键音效
me_down_sound.set_volume(0.2)
myself_down_sound = pygame.mixer.Sound("sound/game_over.mp3")  # 按键音效
myself_down_sound.set_volume(0.2)

"""图片文件路径"""
background_image = "image/background.png"  # 背景图的路径
bullet1_image = "image/bullet1.png"  # 第一种子弹图
enemy1_image = "image/enemy1.png"  # 小敌机图片
enemy2_image = "image/enemy2.png"  # 中敌机图片
enemy3_n1_image = "image/enemy3.png"  # 大敌机图片1
enemy3_n2_image = "image/enemy3_n2.png"  # 大敌机图片2
me1_image = "image/hero1.png"  # 自身飞机第一张图片
me2_image = "image/hero2.png"  # 自身飞机第二张图片

# 设置背景
bg_size = width, height = 430, 700  # 背景大小,bg_size为一个元组
screen = pygame.display.set_mode(bg_size)  # 这是背景大小
background = pygame.image.load(background_image).convert_alpha()  # 画背景
pygame.mixer.music.play(-1)  # 播放背景音乐,-1 表示无限循环播放


######################## 设置我方战机类 #########################
class MyPlane(pygame.sprite.Sprite):  # 定义我的飞机类,继承动画精灵类(因为之后要进行碰撞检测)
    def __init__(self, bg_size,me1_image,me2_image):
        self.me1_image = me1_image
        self.me2_image = me2_image
        self.image1 = pygame.image.load(me1_image).convert_alpha()  # 第一张飞机图片
        self.image2 = pygame.image.load(me2_image).convert_alpha()  # 第二张飞机图片 两张图片是为了做出飞机喷气的效果
        self.rect = self.image1.get_rect()  # 获得飞机图片的尺寸
        self.width, self.height = bg_size[0], bg_size[1]  # 设置飞机允许活动地点
        self.rect.left, self.rect.top = [(self.width - self.rect.width) // 2, \
                                         (self.height - self.rect.height - 20)]  # 注意括号设置我方飞机出现的位置
        self.speed = 10  # 设置飞机出现的速度
        # 添加坠机图片
        self.destroy_images = []
        self.destroy_images.extend([ \
            pygame.image.load("image/hero_blowup_n1.png").convert_alpha(), \
            pygame.image.load("image/hero_blowup_n2.png").convert_alpha(), \
            pygame.image.load("image/hero_blowup_n3.png").convert_alpha(), \
            pygame.image.load("image/hero_blowup_n4.png").convert_alpha()
        ])
        self.active = True  # 表示飞机生存状态
        self.mask = pygame.mask.from_surface(self.image1)     # 给类添加上mask属性,之后可以按照完美碰撞

    def moveup(self):  # 飞机向上飞的函数
        if self.rect.top > 0:  # 如果我方飞机没有飞出 上方边界
            self.rect.top -= 10  # 那么我方飞机朝上飞10个像素
        else:  # 飞出 上方边界
            self.rect.top = 0  # 锁定在0的位置,不再发生变化

    def movedown(self):  # 飞机向下飞的函数
        if self.rect.bottom < (self.height - 20):  # 如果我方飞机没有飞出 上方边界
            self.rect.bottom += 10  # 那么我方飞机朝下飞10个像素
        else:  # 飞出 下方边界
            self.rect.bottom = (self.height - 20)  # 锁定在底边界上方60的位置,不再发生变化

    def moveleft(self):  # 飞机向左飞的函数
        if self.rect.left > 0:  # 如果我方飞机没有飞出 左方边界
            self.rect.left -= 10  # 那么我方飞机朝下左10个像素
        else:  # 飞出 左方边界
            self.rect.left = 0  # 锁定在左边界的位置,不再发生变化

    def moveright(self):  # 飞机向下飞的函数
        if self.rect.right < self.width:  # 如果我方飞机没有飞出 上方边界
            self.rect.right += 10  # 那么我方飞机朝下飞10个像素
        else:  # 飞出 下方边界
            self.rect.right = self.width  # 锁定在底边界的位置,不再发生变化



####################### 设置敌方战机类 ##########################
# 小飞机
class SmallEnemy(pygame.sprite.Sprite):  #定义小敌机,继承自动画精灵
    def __init__(self,bg_size,enemy1_image):
        pygame.sprite.Sprite.__init__(self)
        self.enemy1 = pygame.image.load(enemy1_image).convert_alpha()   # 载入小敌机图片
        self.width, self.height = bg_size[0] , bg_size[1]   # 获取生成小敌机的活动范围
        self.rect = self.enemy1.get_rect()   #获得低级敌机的尺寸
        # 在窗口的5倍之上的距离中产生飞机
        self.rect.left , self.rect.top = [randint(0 , self.width - self.rect.width ),\
                                                     randint(-5*self.height , 0)]
        self.speed = 2  # 设置小敌机移动的速度
        # 添加坠机图片
        self.destroy_images = []
        self.destroy_images.extend([\
            pygame.image.load("image/enemy1_down1.png").convert_alpha(), \
            pygame.image.load("image/enemy1_down2.png").convert_alpha(), \
            pygame.image.load("image/enemy1_down3.png").convert_alpha(), \
            pygame.image.load("image/enemy1_down4.png").convert_alpha()])
        self.active = True  # 表示飞机生存状态
        self.mask = pygame.mask.from_surface(self.enemy1)   # 给类添加上mask属性,之后可以按照完美碰撞

    def move(self):    # 小敌机的移动函数
        if self.rect.top < self.height:    #如果小飞机的底超出窗口的下边框
            self.rect.top += self.speed  #小飞机向下移动他的速度
        else:  #如果小飞机已经超出窗口的下边界框
            self.reset() #重置小飞机

    def reset(self):   #重置小飞机函数
        self.active = True  # 飞机碰撞时写
        # 在窗口的5倍之上的距离中产生飞机
        self.rect.left, self.rect.top = [randint(0 , self.width - self.rect.width ),\
                                                     randint(-5*self.height, 0)]

class MiddleEnemy(pygame.sprite.Sprite):  #定义中敌机,继承自动画精灵
    energy = 8
    def __init__(self,bg_size,enemy2_image):
        pygame.sprite.Sprite.__init__(self)
        self.enemy2 = pygame.image.load(enemy2_image).convert_alpha()   #载入中级敌机照片
        self.width,self.height = bg_size[0], bg_size[1]   #获取生成低级敌机的活动范围
        self.rect = self.enemy2.get_rect()   #获得低级敌机的尺寸
        self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
                                                     randint(-5*self.height, 0)]      #在窗口的5倍之上的距离中产生飞机
        self.speed = 1  #设置中敌机移动的速度
        # 添加坠机图片
        self.destroy_images = []
        self.destroy_images.extend([ \
            pygame.image.load("image/enemy2_down1.png").convert_alpha(), \
            pygame.image.load("image/enemy2_down2.png").convert_alpha(), \
            pygame.image.load("image/enemy2_down3.png").convert_alpha(), \
            pygame.image.load("image/enemy2_down4.png").convert_alpha()])
        self.active = True  # 表示飞机生存状态
        self.mask = pygame.mask.from_surface(self.enemy2)   # 给类添加上mask属性,之后可以按照完美碰撞

    def move(self):    #中敌机的移动函数
        if self.rect.top < self.height :    #如果小飞机的底超出窗口的下边框
            self.rect.top += self.speed  #小飞机向下移动他的速度
        else :  #如果小飞机已经超出窗口的下边界框
            self.reset() #重置中飞机

    def reset(self):   #重置中飞机函数
        self.energy = 8
        self.active = True  # 飞机碰撞时写
        self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
                                         randint(-5 * self.height, 0)]  # 在窗口的5倍之上的距离中产生飞机

# 大敌机
class BigEnemy(pygame.sprite.Sprite):  #定义大敌机类,继承自动画精灵
    energy = 20
    def __init__(self,bg_size,enemy3_n1_image,enemy3_n2_image):
        pygame.sprite.Sprite.__init__(self)
        self.enemy3_n1 = pygame.image.load(enemy3_n1_image).convert_alpha()   # 载入大敌机图片1
        self.enemy3_n2 = pygame.image.load(enemy3_n2_image).convert_alpha()   # 载入大敌机图片2
        self.width, self.height = bg_size[0] , bg_size[1]   # 获取生成大敌机的活动范围
        self.rect = self.enemy3_n1.get_rect()   #获得大敌机的尺寸
        self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
                                                     randint(-5*self.height, 0)]      #在窗口的5倍之上的距离中产生飞机
        self.speed = 1  #设置大敌机移动的速度
        # 添加坠机图片
        self.destroy_images = []
        self.destroy_images.extend([ \
            pygame.image.load("image/enemy3_down1.png").convert_alpha(), \
            pygame.image.load("image/enemy3_down2.png").convert_alpha(), \
            pygame.image.load("image/enemy3_down3.png").convert_alpha(), \
            pygame.image.load("image/enemy3_down4.png").convert_alpha(), \
            pygame.image.load("image/enemy3_down5.png").convert_alpha(), \
            pygame.image.load("image/enemy3_down6.png").convert_alpha()])
        self.active = True  # 表示飞机生存状态
        self.mask = pygame.mask.from_surface(self.enemy3_n1)  # 给类添加上mask属性,之后可以按照完美碰撞


    def move(self):    #大敌机的移动函数
        if self.rect.top < self.height :    #如果大飞机的底超出窗口的下边框
            self.rect.top += self.speed  #大飞机向下移动他的速度
        else:  #如果大飞机已经超出窗口的下边界框
            self.reset() #重置大飞机

    def reset(self):   #重置大飞机函数
        self.energy = 20
        self.active = True  # 飞机碰撞时写
        self.rect.left, self.rect.top = [randint(0, self.width - self.rect.width),\
                                         randint(-5 * self.height, 0)]  # 在窗口的5倍之上的距离中产生飞机


########################### 子弹 ################################
class Bullet1(pygame.sprite.Sprite):     #定义子弹类,继承动画精灵类(因为之后要进行碰撞检测)
    def __init__(self, position, bullet1_image):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load(bullet1_image).convert_alpha()    # 加载子弹1图
        self.rect = self.image.get_rect()            # 获得子弹1图的尺寸
        self.rect.left, self.rect.top = position     # 把飞机的位置传给子弹
        self.speed = 15    # 子弹运动的速度
        self.active = True   # 用来表示这颗子弹是或否失效
        self.mask = pygame.mask.from_surface(self.image)  # 给类添加上mask属性,之后可以按照完美碰撞

    def move(self):
        self.rect.top -= self.speed  # 子弹运动

        if self.rect.top < 0:    # 如果子弹射出屏幕外
            self.active = False   # 将子弹设为失效

    def reset(self, position):
        self.rect.left, self.rect.top = position
        self.active = True


def add_smallenemies(group1, group2, num):
    for i in range(num):
        e1 = SmallEnemy(bg_size, enemy1_image)
        group1.add(e1)
        group2.add(e1)

def add_middleenemies(group1, group2, num):
    for i in range(num):
        e2 = MiddleEnemy(bg_size, enemy2_image)
        group1.add(e2)
        group2.add(e2)

def add_bigenemies(group1, group2, num):
    for i in range(num):
        e3 = BigEnemy(bg_size, enemy3_n1_image, enemy3_n2_image)
        group1.add(e3)
        group2.add(e3)

def main():
    me = MyPlane(bg_size, me1_image, me2_image)  # 生成飞机类
    switch_image = True  # 用于切换战机图片
    delay = 100          # 用于延时

    # 生成敌方飞机 定义精灵组,把生成的飞机放到这里
    enemies = pygame.sprite.Group()  # 生成整个飞机组
    smallenemies = pygame.sprite.Group()  # 生成小飞机组
    add_smallenemies(smallenemies, enemies, 20)  # 生成小型飞机
    middleenemies = pygame.sprite.Group()  # 生成中飞机组
    add_middleenemies(middleenemies, enemies, 10)  # 生成中型飞机
    bigenemies = pygame.sprite.Group()  # 生成大飞机组
    add_bigenemies(bigenemies, enemies, 4)  # 生成大型飞机

    # 生成普通子弹
    bullet1 = []
    bullet1_index = 0
    bullet_num = 4
    for i in range(bullet_num):
        bullet1.append(Bullet1(me.rect.midtop, bullet1_image))  # midtop表示顶部

    # 中弹图片索引
    e1_destroy_index = 0
    e2_destroy_index = 0
    e3_destroy_index = 0
    me_destroy_index = 0

    running = True      # 游戏执行状态

    while running:
        for event in pygame.event.get():     # 键盘操作
            if event.type == QUIT:
                sys.exit()
        # 检查是否有上下左右或wsad按下,如有则对飞机进行相应的控制
        key_press = pygame.key.get_pressed()
        if key_press[K_w] or key_press[K_UP]:  # 如果按下上键或者↑
            me.moveup()  # 飞船向上飞行
        elif key_press[K_s] or key_press[K_DOWN]:  # 如果按下下键或者↓
            me.movedown()  # 飞船向下飞行
        elif key_press[K_a] or key_press[K_LEFT]:  # 如果按下左键或者←
            me.moveleft()  # 飞船向左飞行
        elif key_press[K_d] or key_press[K_RIGHT]:  # 如果按下右键或者→
            me.moveright()  # 飞船向右飞行

        screen.blit(background, (0, 0))  # 绘制背景

        # 绘制大型敌机
        for each in bigenemies:
            if each.active:  # 如果大型敌机为生存状态
                each.move()
                if switch_image:
                    screen.blit(each.enemy3_n1, each.rect)
                else:
                    screen.blit(each.enemy3_n2, each.rect)

                # 绘制血槽 红黑绿
                pygame.draw.line(screen, BLACK, \
                                 (each.rect.left, each.rect.top - 5), \
                                 (each.rect.right, each.rect.top - 5), \
                                 2)

                # 当生命大于20%显示绿色,否则显示红色
                energy_remain = each.energy / BigEnemy.energy
                if energy_remain > 0.2:
                    energy_color = GREEN
                else:
                    energy_color = RED
                pygame.draw.line(screen, energy_color, \
                                 (each.rect.left, each.rect.top - 5), \
                                 (each.rect.left + each.rect.width * energy_remain, \
                                  each.rect.top - 5), 2)

                # 即将出现在画面中,播放音效
                if each.rect.bottom > -50:
                    enemy3_fly_sound.play()
            else: # 毁灭
                if not (delay % 3):  # 设置两张照片转换的时间延时
                    # 只需要播放一次
                    if e3_destroy_index == 0:
                        enemy3_down_sound.play()

                    screen.blit(each.destroy_images[e3_destroy_index], each.rect)
                    e3_destroy_index = (e3_destroy_index + 1) % 6  # 循环播放爆炸图片
                    if e3_destroy_index == 0:
                        enemy3_fly_sound.stop()  # 关闭声音
                        each.reset()

        # 绘制中型敌机:
        for each in middleenemies:
            if each.active:
                each.move()
                screen.blit(each.enemy2, each.rect)

                # 绘制血槽 红黑绿
                pygame.draw.line(screen, BLACK, \
                                 (each.rect.left, each.rect.top - 5), \
                                 (each.rect.right, each.rect.top - 5), \
                                 2)

                # 当生命大于20%显示绿色,否则显示红色
                energy_remain = each.energy / MiddleEnemy.energy
                if energy_remain > 0.2:
                    energy_color = GREEN
                else:
                    energy_color = RED
                pygame.draw.line(screen, energy_color, \
                                 (each.rect.left, each.rect.top - 5), \
                                 (each.rect.left + each.rect.width * energy_remain, \
                                  each.rect.top - 5), 2)
            else:
                # 毁灭
                if not (delay % 3):
                    if e2_destroy_index == 0:
                        enemy2_down_sound.play()
                    screen.blit(each.destroy_images[e2_destroy_index], each.rect)
                    e2_destroy_index = (e2_destroy_index + 1) % 4  # 循环播放爆炸图片
                    if e2_destroy_index == 0:
                        each.reset()

        # 绘制小型敌机:
        for each in smallenemies:
            if each.active:
                each.move()
                screen.blit(each.enemy1, each.rect)
            else:
                # 毁灭
                if not(delay%3):
                    if e1_destroy_index == 0:
                        enemy1_down_sound.play()
                    screen.blit(each.destroy_images[e1_destroy_index], each.rect)
                    e1_destroy_index = (e1_destroy_index + 1)%4    # 循环播放爆炸图片
                    if e1_destroy_index == 0:
                        each.reset()

        # 检测我方飞机和其他飞机发生碰撞  spritecollide矩形区域, pygame.sprite.collide_mask检测边缘碰撞
        enemies_down = pygame.sprite.spritecollide(me, enemies, False, pygame.sprite.collide_mask)
        if enemies_down:
            me.active = False
            for e in enemies_down:
                e.active = False

        # 发射子弹 每10桢绘制一次子弹
        if not (delay % 10):
            bullet1[bullet1_index].reset(me.rect.midtop)
            bullet1_index = (bullet1_index + 1) % bullet_num

        # 检测子弹是否击中敌机
        for b in bullet1:  # 对于列表中的的所有子弹
            if b.active:  # 如果子弹有效
                b.move()  # 子弹移动
                screen.blit(b.image, b.rect)  # 把子弹绘制在背景上
                enemies_hit = pygame.sprite.spritecollide(b, enemies, False,
                                                          collided=pygame.sprite.collide_mask)  # 将所有与子弹发生碰撞的敌方飞机都加入到组中
                if enemies_hit:  # 如果有敌机与子弹相碰
                    b.active = False  # 将碰撞后在子弹设置为未激活,使其消失,不再继续存在在画面中
                    for e in enemies_hit:  # 对于所有相撞的敌机
                        # 中大型敌机
                        if e in middleenemies or e in bigenemies:   # 如果敌机是中型飞机或者大型飞机
                            e.energy -= 1
                            if e.energy == 0:        # 如果生命值变为0
                                e.active = False     # 将敌机的生命属性设置为死亡
                        else:
                            # 小飞机
                            e.active = False

        # 绘制我方飞机
        if me.active:
            if switch_image:  # 如果改变属性为真  画第一张飞机图
                screen.blit(me.image1, me.rect)
            else:  # 2如果改变属性为假    画第二张飞机图
                screen.blit(me.image2, me.rect)
        else:
            # 毁灭
            if not (delay % 3):
                if me_destroy_index == 0:
                    me_down_sound.play()
                screen.blit(me.destroy_images[me_destroy_index], me.rect)
                me_destroy_index = (me_destroy_index + 1) % 4  # 循环播放爆炸图片
                if me_destroy_index == 0:
                    print("Game Over")
                    running = False
        # 切换图片
        if delay % 5 == 0:
            switch_image = not switch_image
        delay -= 1
        if delay == 0:
            delay = 100

        pygame.display.flip()  # 不停的刷新画面,不停的绘画
        clock.tick(60)  # 设置帧率


if __name__ == "__main__":
    # 这样做的好处是双击打开时如果出现异常可以报告异常,而不是一闪而过!
    try:
        print()
        main()
    except SystemExit:  # 这是按下 × 的异常,直接忽略
        pass

;