What this step does is:

1. Added super bombs and strengthened the replenishment function of bullets

2. After the user obtains the super bomb and strengthens the supply of bullets, the bullets will be strengthened first. At the same time, press the space bar to release the big move and empty the aircraft in the screen

First prepare resources, the network can also be downloaded, I directly use the tutorial resources here, why (really good, find their own miserable)

In the first few steps, the basic framework of the game is almost complete, which is to add a new function to the original framework. Here we add a new function called supply. Py: Supply control, including supply movement and reset

Import pygame from random import * # Bullet_Supply class (pygame.sprite.sprite): def __init__(self, bg_size): Self. Image = PyGame.image.load ('images/ bullet_supply-.png ').convert_alpha() Self.width = bg_size[0] self.height = bg_size[1] # get_rect() Self.rect = self.image.get_rect() # resupply position of random bullets. Randint (a,b) generates a<=n<=b, i.e., at the screen width, Left = randint(0, self.width - self.rect.width) self.rect.top = randint(-2 * self.height, Self. active = False # Self. speed = 5 # def move(self): If self. Rect. Top < self. Height: # if self. Self. Active = False # Def reset(self): Randint (a,b) generates a<=n<=b, i.e., at the screen width, Left = randint(0, self.width - self.rect.width) self.rect.top = randint(-2 * self.height, 0) # Bomb_Supply(pygame.sprite): def __init__(self, bg_size): Image = pygame.image.load('images/ bomb_supply-.png ').convert_alpha() # Self.width = bg_size[0] self.height = bg_size[1] # get_rect() Self.rect = self.image.get_rect() # resupply position of super bomb. Randint (a,b) generates a<=n<=b, i.e., at the screen width, Left = randint(0, self.width - self.rect.width) self.rect.top = randint(-2 * self.height, Self. active = False # Self. speed = 5 # def move(self): If self. Rect. Top < self. Height: # if self. Self. Active = False # Def reset(self): Randint (a,b) generates a<=n<=b, i.e., at the screen width, Self.rect. left = randint(0, self.width - self.rect.width) self.rect.top = randint(-2 * self.height, 0)Copy the code

Main.py: Added the rendering of super bullets, bullet timer events, resupply time events,

1. The ability to supply every 8 seconds, randomly selected (Super bombs/enhanced bullets)

2. Aircraft picking up supplies (handled by collision mechanism)

3. When you pick up a strengthened bullet, the bullet changes and the strengthened bullet lasts 4 seconds

4. Pick up the super bomb, the number of the super bomb changes (up to 3), at the same time the space put the super bomb big move, clear the screen notes as far as possible to write all write, write the feeling is a bit messy

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
    # 玩家带有超级炸弹数量
    bomb_num = 3


    # 游戏暂停,默认为非暂停状态
    paused = False

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

    # 游戏分数
    score = 0

    # 飞机爆炸的图片下标,依次为小型敌机,中型敌机,大型敌机,玩家飞机的爆炸的图片的下标,切换下标来改变爆炸图片
    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


        # 检测用户键盘操作,分别为上下左右
        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
                        print("炸弹数量:", bomb_num)



            # 绘制小型敌机,这里是由于上面定义了小型飞机组,飞机组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 += 1000
                            print("得分:", score)

            # 做碰撞检测,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





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


        # 更新整个待显示的  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

Bullet. Py: The control of bullets, including the various attributes of bullets, and the reset of bullets, with improved bullets, written differently

Import PyGame # Bullet1 class Bullet1(PyGame.sprite.sprite): Def __init__(self, position) def __init__(self, position): Initialization of base class Pygame.sprite.sprite.__init__ (self) self. Image = pyGame.sprite.__init__ (self) self Pygame.image.load ('images/bullet1.png').convert_alpha() # get_rect() is a method for processing rectangular images, Self.rect = self.image.get_rect() # Define the position of the bullet self.rect.left = position[0] Self. Rect. top = position[1] # check whether the bullet is active or not self. Self.mask = pygame.mask.from_surface(self.image) # def move(self): Self. Rect. top -= self. BulletSpeed # out of the screen, defined as inactive, and kill off, otherwise consume resources if self. Self. Active = False # def reset(self, position): Self. Active = True self. Rect. Left = position[0] self. Rect. Top = position[1] Class Bullet2(PyGame.sprite.sprite): Def __init__(self, position) def __init__(self, position): __init__(self) # Enhance bullet image self.image = pygame.image.load('images/bullet2.png').convert_alpha() # Get_rect () is a method for processing rectangular images, Self.rect = self.image.get_rect() # Define the position of the bullet self.rect.left = position[0] Self. Rect. top = position[1] # check whether the bullet is active self. Self.mask = pygame.mask.from_surface(self.image) # def move(self): Self. Rect. top -= self. BulletSpeed # off screen, defined as inactive if self. Rect. top < 0: Self. Active = False # def reset(self, position): self.active = True self.rect.left = position[0] self.rect.top = position[1]Copy the code

Myplane.py: is mainly the control of the player aircraft, including the player game aircraft various attributes, up and down around the aircraft movement, as well as the rebirth of the aircraft enemy.py (enemy aircraft class, including enemy aircraft attributes, operation, reset, etc.)

I’m not going to put it up here, it’s in the first few steps

The effect at this point is to control aircraft movement, shoot and destroy enemy aircraft