牛骨文教育服务平台(让学习变的简单)

Python编写微信打飞机小游戏(十)

 

  在这篇博文里,我们将为我方飞机添加三条生命。

  1、加载相关资源

  在目前的游戏中,我方飞机是拥有不死生命的,损毁了就在下方复活,这显然不合逻辑,因此需要为我放飞机增加生命数,并在屏幕右下方显示对应图标。首先在main()函数中设置初始化生命数并加载小飞机图片:

    life_image = pygame.image.load("image/life.png").convert()
    life_rect = life_image.get_rect()
    life_num = 3  # 一共有三条命

  2、将“life_num”加入程序循环判断语句中

  既然我方飞机拥有了生命属性,那就意味着我们不能够再向之前那样随意的摆放while()循环中的代码了,很多代码在执行前都需要判断life_num是否为零,比如说发射子弹,我方飞机都已经挂掉了,再发射子弹就显得不尽合理了吧。

  因此我们需要考虑哪些代码在执行前需要判断life_num是否为零,具体来说,只要涉及到和精灵有关的操作都应该在life_num > 0时进行,因此我们将下列操作放在life_num的判断条件之外:(1)打印背景图片和分数的操作。因为不能因为我方飞机挂掉就让屏幕一篇漆黑,背景还是应该有的;(2)事件响应机制。因为我方飞机挂掉之后同样需要响应用户事件,比如鼠标单击事件、系统退出事件。除了以上这两个操作之外,其余操作都应该放在“if life_num:”的条件循环之内,因此可能需要我们将之前的代码顺序做一些调整:

    while running:
        # 将背景图片打印到内存的屏幕上# 检测用户的退出及暂停操作
        if life_num  
             # 绘制全屏炸弹数量和剩余生命数量# 检测用户的键盘操作# 绘制补给并检测玩家是否获得# 子弹与敌机的碰撞检测
             # 我方飞机碰撞检测
             # 绘制我方飞机# 绘制敌方飞机
             # …………………………
        elif life_num == 0:  # 生命值为零,绘制游戏结束画面
             pass
        # 将内存中绘制好的屏幕刷新到设备屏幕上
        # 设置帧数为60

  3、life_num递减操作

  重新安排完代码结构后,接下来只需在我方飞机损毁时,将life_num减一:

            if me.active:# 绘制我方飞机的两种不同的形式else:
                if not (delay % 3):
                    # 绘制我方飞机损毁画面
                    if me_destroy_index == 0:
                        life_num -= 1# 我方飞机重生

  当然这里也用了“me_destroy_index == 0”的限定条件,以保证在损毁期间只减一次生命数(详见之前博文)。

  4、绘制life_num图标

  在游戏过程中,为了显示当前玩家还有多少生命数,需要通过在屏幕右下方显示小飞机图标来指示,玩家当前有几条命就显示几个图标。小图标的资源已将在开始时加载好了,我们先给出完整的显示代码,稍后解释:

                for i in range(life_num):
                    screen.blit(life_image, (width - 10 - (i + 1) * life_rect.width, height - 10 - life_rect.height))

  这里只是做了一些简单的数学运算,“(width - 10 - (i + 1) * life_rect.width, height - 10 - life_rect.height)”这段代码就能够实现根据当前的life_num的值画出对应数量的小飞机图标。

  5、为我方飞机添加初始化无敌机制

  程序编写到这里貌似已经实现了预期目标,不过其实这里面有一个影藏的BUG,需要多次实现才会出现。因为我方飞机在重生时都是在固定位置出现的,那么就有这样一种可能性:就是在我方飞机重生时,在屏幕下方正中间(我方飞机重生的位置)正好有一架敌机,这就导致我方飞机一出生就挂掉,根本没有躲避的事件,虽然这种BUG出现的几率不大,但我们还是在这里提供一个解决方案,就是让我方飞机在重生之后具有三秒的无敌时间。因此我方飞机又多了一个属性:无敌。

  首先向我方飞机类的内部添加用来表示当前无敌状态的标志位:

self.invincible = False  # 飞机初始化时有三秒的无敌时间

  对应的在reset()成员函数中将其置为true:

        self.invincible = True

  接下来我们通过事件触发系统来设计一个定时器,用以记录无敌时间,首先在main函数中定义这个计时器:

invincible_time = USEREVENT + 2  # 接触我方飞机无敌时间定时器

  由于之前已经定义了两个用户事件了(supply_timer,double_bullet_timer),因此这里指定的标号为USEREVENT + 2。

  然后在我方飞机reset之后(invincible置为true,无敌状态开始),激活这个定时器,计时开始(3秒):

            if me.active:# 绘制我方飞机的两种不同的形式else:
                if not (delay % 3):
                    # 绘制我方飞机损毁画面
                    if me_destroy_index == 0:
                        me.reset()  # 我方飞机重生并开始无敌时间计时
                        pygame.time.set_timer(invincible_time, 3 * 1000)

  激活定时器之后,编写事件响应函数。若该事件被触发,说明三秒的无敌时间已过,需要将我方飞机的无敌标志位置为false,并关闭计时器:

        for event in pygame.event.get():  # 响应用户的偶然操作
            if event.type == QUIT: 
                # 如果用户按下屏幕上的关闭按钮,触发QUIT事件,程序退出elif event.type == invincible_time:  # 如果无敌时间已过
                me.invincible = False
                pygame.time.set_timer(invincible_time, 0)

  最后,我们修改一下我方飞机的碰撞检测函数,使得当我方飞机与敌机发生碰撞时,只有在我方飞机的invincible变量为false(非无敌状态)的情况下,才执行我方飞机和敌机的销毁操作:

            # ====================我方飞机碰撞检测====================
            enemies_down = pygame.sprite.spritecollide(me, enemies, False, pygame.sprite.collide_mask)
            if enemies_down and not me.invincible:  # 如果碰撞检测返回的列表非空,则说明已发生碰撞,若此时我方飞机处于无敌状态
                me.active = False
                for e in enemies_down:
                    e.active = False  # 敌机损毁

  这里就是在原有的if语句调价的基础上添加“not me.invincible”判断,且二者为“与”操作的关系。好的,程序到此就告一段落,顺利的实现了预期功能,在下一篇博文中我们在给游戏添加一个暂停的功能。