The added features are: screen rendering to draw game scores, lives, super bombs, and pause

The display is as shown in the figure:

Required resources, which text resources font can not be uploaded, mo have a way, you can go to find their own, can also download my package above the connection (like to 6 points, a little cheeky 😂)

If you look at this step from the beginning, you’ll see that there’s a total of:

Main.py: Render components, run logic, etc. This step adds render scores, super bombs, lives, pause functions

Bullet. Py: Control of bullets, including various bullet attributes, and bullet resets

Enemy.py: enemy class, which contains enemy properties, runtime, reset, etc

Myplane. py: Controls the player’s plane, including various attributes of the player’s plane, up, down, left, right movement of the plane, and rebirth of the plane

Supply. Py: Supply control, including supply movement and resetting, is written pretty much the same way

Knowledge point (suggest oneself also baidu look) :

Pygame.font.font. Render ()* Render text on a new Surface object pygame.font. Render (text, AntiAlias, color, background=None)

A. text: Indicates the text to be displayed

B. Antialias: If it is True, the text image is smoother; if it is False, the text image is jagged

C. color: font color

D. Background: Specifies the background color (optional). The default color is small black screen

2.paused_rect.collidepoint(event.pos)

Buttons – a tuple of three numbers representing left, middle, and right buttons, with 1 being pressed.

Pos – is the location…

Rel – represents the distance now from the last mouse event

Here is the main. Py code directly, the rest of the code will not be put up in this step, otherwise it will be a lot of (this can not directly put the.py file is uncomfortable), if you need to go to the previous steps to view, or go to the package to download the whole.

import pygame
import sys
import traceback
from pygame.locals import *
from random import *
import myplane
import enemy
import bullet
import supply


# 初始化
pygame.init()
# 设置窗口大小
bg_size = width, height = 400, 700  # 实际上是元组
screen = pygame.display.set_mode(bg_size)  # 设置窗口
pygame.display.set_caption("飞机大战")  # 窗口标题
# 加载背景图片,对于普通图像的显示效果有没有convert都是一样的,但是 使用 convert 可以转换格式,提高 blit 的速度
background = pygame.image.load("images/background.png").convert()

# 设置黑、绿、红、百几种颜色对应值,后面会用到
BLACK = (0, 0, 0)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
WHITE = (255, 255, 255)

# 生成敌方小型飞机
def add_small_enemy(small_enemies, enemiesGroup, num):
    for i in range(num):
        smallenemy = enemy.SmallEnemy(bg_size)
        # 精灵组来实现多个图像,很适合处理精灵列表,有添加,移除,绘制,更新等方法
        # Group.sprites 精灵组
        # Group.copy 复制
        # Group.add 添加
        # Group.remove 移除
        # Group.has 判断精灵组成员
        # Group.update 更新
        # Group.draw 位块显示
        # Group.clear - 绘制背景
        # Group.empty 清空
        # 将这一组敌机都添加上小型飞机属性,相当于统一处理,统一赋值
        small_enemies.add(smallenemy)
        enemiesGroup.add(smallenemy)

def main():
    # 创建时钟对象(可以控制游戏循环频率)
    clock = pygame.time.Clock()

    # 生成玩家飞机
    me = myplane.MyPlane(bg_size)

    # 存放所有敌方飞机,这个飞机组包含了小型飞机、中型飞机、大型飞机的各种属性,只要用于处理碰撞
    # 当程序中有大量的实体的时候,操作这些实体将会是一件相当麻烦的事
    # 使用pygame.sprite.Group()函数可以创建一个精灵组,从而统一管理,这里创建了一个敌机组
    enemiesGroup = pygame.sprite.Group()

    # 生成地方小型飞机,敌方小型飞机也是一个组,进行统一处理
    small_enemies = pygame.sprite.Group()
    add_small_enemy(small_enemies, enemiesGroup, 15)

    # 生成普通子弹,这里是四颗子弹循环
    bullet1s = []
    # 标记发生的哪颗子弹
    bullet1s_index = 0
    # 子弹数目
    bullet1_num = 4
    for i in range(bullet1_num):
        # 把玩家飞机的位置发给子弹类
        bullet1s.append(bullet.Bullet1(me.rect.midtop))

    # 生成加强子弹,这里是八颗子弹循环,左右各四颗
    bulletspro = []
    # 标记发生的哪颗子弹
    bulletspro_index = 0
    # 子弹数目
    bulletspro_num = 8
    # 左右各压入四颗子弹,//2表示的整除,其实用/2也一样
    for i in range(bulletspro_num // 2):
        # 这里(me.rect.centerx - 33, me.rect.centery)是指元组位置,centerx代表x轴,centery代表y轴
        bulletspro.append(bullet.Bullet2((me.rect.centerx - 33, me.rect.centery)))
        bulletspro.append(bullet.Bullet2((me.rect.centerx + 33, me.rect.centery)))

    # 初始化加强子弹补给,超级炸弹补给
    bullet_supply = supply.Bullet_Supply(bg_size)
    bomb_supply = supply.Bomb_Supply(bg_size)
    # 设置无敌时间事件,pygame.USEREVENT代表事件1,pygame.USEREVENT+1代表事件2,以此类推,这里相当于定义了一个事件
    invincible_event = pygame.USEREVENT
    # 设置补给时间事件
    bullet_time_supply = pygame.USEREVENT + 1
    # 设置加强子弹定时器事件,即加强子弹buff持续事件
    bulletpro_time = pygame.USEREVENT + 2
    # 设置定时器,8秒钟发放一次补给
    pygame.time.set_timer(bullet_time_supply, 8 * 1000)

    # 标记是否使用超级子弹
    is_double_bullet = False

    # 玩家三条命
    life_num = 3
    life_image = pygame.image.load('images/life.png').convert_alpha()
    life_rect = life_image.get_rect()
    # 玩家带有超级炸弹数量
    bomb_num = 3
    # 绘制超级炸弹
    bomb_image = pygame.image.load('images/bomb.png').convert_alpha()
    # 超级炸弹图片位置
    bomb_rect = bomb_image.get_rect()
    # 超级炸弹数量字体
    bomb_font = pygame.font.Font('font/font.ttf', 48)


    # 游戏暂停,默认为非暂停状态
    paused = False
    # 暂停图片
    pause_nor_image = pygame.image.load('images/pause_nor.png').convert_alpha()
    pause_pressed_image = pygame.image.load('images/pause_pressed.png').convert_alpha()
    # 继续图片
    resume_nor_image = pygame.image.load('images/resume_nor.png').convert_alpha()
    resume_pressed_image = pygame.image.load('images/resume_pressed.png').convert_alpha()
    # 设置默认图片
    paused_image = pause_nor_image
    # 暂停按钮位置
    paused_rect = pause_nor_image.get_rect()
    paused_rect.left, paused_rect.top = width - paused_rect.width - 10, 10


    # 控制玩家飞机图片切换,展示突突突的效果
    switch_image = True
    # 切换延时
    delay = 100

    # 游戏分数
    score = 0
    # 设定玩家分数字体样式,从一个字体文件创建一个 Font 对象
    score_font = pygame.font.Font('font/font.ttf', 36)

    # 飞机爆炸的图片下标,依次为小型敌机,中型敌机,大型敌机,玩家飞机的爆炸的图片的下标,切换下标来改变爆炸图片
    e1_destory_index = 0
    e2_destory_index = 0
    e3_destory_index = 0
    me_destory_index = 0

    running = True
    while running:
        # 获取事件
        for event in pygame.event.get():
            # 结束事件触发结束操作
            if event.type == QUIT:
                pygame.quit()
                sys.exit()
            # 在触发碰撞的时候,写了pygame.time.set_timer(invincible_event, 3*1000)
            # 意思就是3秒后将会执行invincible_event事件,这里捕获了invincible_event事件,执行后,将取消这个计时器,防止循环重复执行,等待下一次触发
            elif event.type == invincible_event:
                # 解除无敌状态
                me.invincible = False
                pygame.time.set_timer(invincible_event, 0)
            # 触发补给事件
            elif event.type == bullet_time_supply:
                # 随机进行一次判断,如果是True,就发放强化子弹补给
                if choice([True, False]):
                    # 发放强化子弹补给
                    bullet_supply.reset()
                else:
                    # 发放超级炸弹补给
                    bomb_supply.reset()
            # 加强子弹buff到时事件
            elif event.type == bulletpro_time:
                # 子弹切换为普通子弹
                is_double_bullet = False
                # 事件停止循环,等待下一次触发
                pygame.time.set_timer(bulletpro_time, 0)
            # 捕获按键操作
            elif event.type == KEYDOWN:
                # 如果按下的是空格,触发大招,超级炸弹清空屏幕内的飞机
                if event.key == K_SPACE:
                    if bomb_num > 0:
                        bomb_num -= 1
                        # 判断所有在场的敌机,是否在游戏屏幕内
                        for ei in enemiesGroup:
                            if ei.rect.bottom > 0:
                                ei.active = False
            # 鼠标移动事件
            elif event.type == MOUSEMOTION:
                # 鼠标移入到暂停的矩形框内,检测鼠标是否在矩形里,是则返回True,否则返回False ; pos – 就是鼠标位置
                if paused_rect.collidepoint(event.pos):
                    # 如果是暂停状态
                    if paused:
                        paused_image = resume_pressed_image
                    else:
                        paused_image = pause_pressed_image
                else:
                    if paused:
                        paused_image = resume_nor_image
                    else:
                        paused_image = pause_nor_image
            # 鼠标左键点击暂停按钮
            elif event.type == MOUSEBUTTONDOWN:
                # 如果是左键而且鼠标点击位置在暂停框内
                if event.button == 1 and paused_rect.collidepoint(event.pos):
                    # 切换暂停状态
                    paused = not paused
                # 如果点击暂停按钮后,游戏是暂停状态
                if paused:
                    # 绘制暂停按钮图片
                    paused_image = resume_pressed_image
                    # 暂停补给定时器
                    pygame.time.set_timer(bullet_time_supply, 0)
                # 如果点击暂停按钮后,游戏是继续状态
                else:
                    # 绘制继续按钮图片
                    paused_image = pause_pressed_image
                    # 继续补给定时器
                    pygame.time.set_timer(bullet_time_supply, 8 * 1000)


        # 检测用户键盘操作,分别为上下左右
        key_pressed = pygame.key.get_pressed()
        if key_pressed[K_w] or key_pressed[K_UP]:
            me.moveUp()
        if key_pressed[K_s] or key_pressed[K_DOWN]:
            me.moveDown()
        if key_pressed[K_a] or key_pressed[K_LEFT]:
            me.moveLeft()
        if key_pressed[K_d] or key_pressed[K_RIGHT]:
            me.moveRight()


        # 在屏幕上面绘制背景图像,并指定位置
        screen.blit(background, (0, 0))

        # 绘制子弹补给、炸弹补给、敌机、玩家飞机等等各种元素
        # 未暂停且生命大于0
        if paused == False and life_num > 0:
            # 绘制子弹补给,如果子弹补给状态为真,即触发子弹补给操作
            if bullet_supply.active:
                # 子弹开始运动,并且渲染子弹子弹补给图片
                bullet_supply.move()
                screen.blit(bullet_supply.image, bullet_supply.rect)
                # 下落过程中如果跟玩家飞机碰撞,说明玩家飞机拾取到子弹补给
                # pygame.sprite.collide_mask:两个精灵之间的像素遮罩检测,接收两个精灵作为参数,返回值是一个bool变量
                if pygame.sprite.collide_mask(bullet_supply, me):
                    # 改变子弹补给状态,包括隐藏以及不能再拾取了
                    bullet_supply.active = False
                    # 飞机子弹变为加强子弹
                    is_double_bullet = True
                    # 设置加强子弹buff持续事件,这里持续4s
                    pygame.time.set_timer(bulletpro_time, 4 * 1000)

            # 绘制超级炸弹补给,如果超级炸弹状态为真,即触发超级炸弹补给操作
            if bomb_supply.active:
                # 超级炸弹补给开始运动,并且渲染补给图片
                bomb_supply.move()
                screen.blit(bomb_supply.image, bomb_supply.rect)
                # 玩家飞机拾取到补给
                if pygame.sprite.collide_mask(bomb_supply, me):
                    # 改变补给状态,包括隐藏以及不能再拾取了
                    bomb_supply.active = False
                    # 判断超级炸弹数量,不能大于3
                    if bomb_num < 3:
                        bomb_num += 1



            # 绘制小型敌机,这里是由于上面定义了小型飞机组,飞机组add了小型飞机属性(速度、位置等),这时候地图上就生成了飞机
            # 如果这些飞机属于小型敌机类,即一起处理
            for ei in small_enemies:
                # 敌机是活的,未被击毁
                if ei.active == True:
                    # 绘制小型敌机,并且敌机开始运动
                    screen.blit(ei.image, ei.rect)
                    ei.samll_enemy_move()
                # 小型敌机被摧毁(被玩家击毁或者与玩家碰撞)
                else:
                    # 这里设置delay % 4是指爆炸画面为4帧(个人猜测),理解为爆炸停留时间,可自行设置
                    if not (delay % 4):
                        # 用于播放爆炸声音,每一架敌机只有一次
                        if e1_destory_index == 0:
                            print("播放敌机爆炸声音")
                        # 绘制敌机撞击爆炸画面
                        screen.blit(ei.destory_images[e1_destory_index], ei.rect)
                        # 切换爆炸图片下标,从而切换爆炸图片
                        e1_destory_index = (e1_destory_index + 1) % 4
                        # 经历完一轮爆炸的敌机,可以将其销毁,也可以重生,都是不能不处理,不然会一直爆炸、爆炸
                        # 这里选择将其重生
                        if e1_destory_index == 0:
                            ei.reset()
                            score += 100

            # 做碰撞检测,pygame.sprite.spritecollide(sprite,sprite_group,bool):一个组中的所有精灵都会逐个地对另外一个单个精灵进行冲突检测,发生冲突的精灵会作为一个列表返回。
            # 第一个参数就是单个精灵,第二个参数是精灵组,第三个参数是一个bool值,最后这个参数起了很大的作用。当为True的时候,会删除组中所有冲突的精灵,False的时候不会删除冲突的精灵
            # 第四个参数是:两个精灵之间的像素遮罩检测
            enemy_collide = pygame.sprite.spritecollide(me, enemiesGroup, False, pygame.sprite.collide_mask)
            # 碰撞处理,如果不是无敌状态下发生碰撞
            if enemy_collide and not me.invincible:
                # 玩家飞机触发摧毁状态
                me.active = False
                # enemy_collide是一个列表,存储所有跟玩家飞机发生碰撞的敌机,然后把碰撞的敌机状态置为摧毁状态
                for ei in enemy_collide:
                    ei.active = False

            # 绘制玩家飞机,如果飞机为激活状态
            if me.active:
                # 在屏幕上绘制玩家飞机,switch_image为是否切换图片
                if switch_image:
                    screen.blit(me.image1, me.rect)
                # 切换一下飞行图片
                else:
                    screen.blit(me.image2, me.rect)
            # 代表飞机遭到碰撞,激活爆炸事件
            else:
                if not (delay % 4):
                    # 用于播放爆炸声音,每一架敌机只有一次
                    if me_destory_index == 0:
                        print("玩家飞机爆炸声音")
                    # 绘制玩家撞击爆炸画面
                    screen.blit(me.destory_image[me_destory_index], me.rect)
                    # 切换爆炸图片下标,从而切换爆炸图片
                    me_destory_index = (me_destory_index + 1) % 4
                    # 爆炸画面播放完之后飞机重生
                    if me_destory_index == 0:
                        # 生命减一条,如果见到0,会自动跳过上一级循环
                        life_num -= 1
                        # 重置状态
                        me.reset()
                        # 无敌时间设置为3秒,3秒后,触发无敌时间事件,pygame.time.set_timer:就是每隔一段时间(这里是3毫秒 * 1000 = 3s),去执行一些动作
                        pygame.time.set_timer(invincible_event, 3 * 1000)

            # 每10个单位时间发射一颗子弹
            if not(delay % 10):
                # 如果是普通子弹
                if is_double_bullet == False:
                    bullets = bullet1s
                    # 先定子弹0的位置
                    bullets[bullet1s_index].reset(me.rect.midtop)
                    # 切换到下一颗子弹
                    bullet1s_index = (bullet1s_index + 1) % bullet1_num
                # 如果是超级子弹
                else:
                    # 则子弹切换为加强子弹
                    bullets = bulletspro
                    # 左右加强子弹重置位置,逻辑其实跟普通子弹一样的,只是位置变了
                    bullets[bulletspro_index].reset((me.rect.centerx - 33, me.rect.centery))
                    bullets[bulletspro_index + 1].reset((me.rect.centerx + 33, me.rect.centery))
                    # 切换到下一组子弹
                    bulletspro_index = (bulletspro_index + 2) % bulletspro_num


            # 绘制子弹
            for bul in bullets:
                if bul.active:
                    # 子弹如果是激活状态的话,就可以移动加绘制了
                    bul.move()
                    screen.blit(bul.image, bul.rect)
                    # 子弹与敌机的碰撞,子弹与敌机组之间的碰撞,正常情况下其实就是1对1的碰撞
                    enemy_hit = pygame.sprite.spritecollide(bul, enemiesGroup, False, pygame.sprite.collide_mask)
                    # 如果存在被子弹击中的敌机
                    if enemy_hit:
                        # 击中敌机的子弹先标为未激活状态,下一次循环到这个子弹的时候其实会重置的,又会显示出来
                        bul.active = False
                        for ei in enemy_hit:
                            ei.active = False

            # 绘制分数文字,pygame.font.Font.render():在一个新 Surface 对象上绘制文本
            # pygame.font.Font.render(text, antialias, color, background=None)
            # text:要显示的文字  antialias: 为True时文本图像显示更光滑,为False时文本图像显示有锯齿状
            # color:字体颜色 background:背景颜色(可选参数),默认为小黑屏
            score_text = score_font.render('Score : %s' % str(score), True, WHITE)
            screen.blit(score_text, (10, 5))

            # 绘制超级炸弹图片以及数量显示
            bomb_text = bomb_font.render('* %d' % bomb_num, True, WHITE)
            bomb_text_rect = bomb_text.get_rect()
            screen.blit(bomb_image, (10, height - 10 - bomb_rect.height))
            screen.blit(bomb_text, (bomb_rect.width + 20, height - 5 - bomb_text_rect.height))

            # 绘制玩家剩余生命数
            if life_num > 0:
                for i in range(life_num):
                    screen.blit(life_image, (width - 10 - (i+1)*life_rect.width, height - 10 - life_rect.height))


            delay -= 1
            if delay == 0:
                delay = 100
            # 每5帧切换一下飞行图片样式
            if delay % 5 == 0:
                switch_image = not switch_image

        # 绘制暂停按钮图片
        screen.blit(paused_image, paused_rect)
        # 更新整个待显示的  Surface 对象到屏幕上,将内存中的内容显示到屏幕上
        pygame.display.flip()
        # 通过时钟对象指定循环频率,每秒循环60次
        # 帧速率是指程序每秒在屏幕山绘制图
        clock.tick(60)

if __name__ == "__main__":
    try:
        main()
    # 服务正常退出
    except SystemExit:
        print("游戏正常退出!")
        # pass忽略错误并继续往下运行,其实这里以及退出了
        pass
    # 服务出现其他的异常
    except:
        # 直接将错误打印出来
        traceback.print_exc()
        pygame.quit()

Copy the code