Python游戏之Pygame——太空飞机大战(四)

上一篇(Python游戏之Pygame——太空飞机大战(三))完成了英雄战机和星空,那么基本上飞机大战的主要元素都已经完成,该是总结成功玩自己游戏的时候了。
哦,差点忘了,Bullet类对于普通子弹和导弹发射来说是通用的,但是对于核弹,发射核弹部分当然也是相同的,但核弹爆炸的效果图以及杀伤情况就完全不同了。下面先给出展示核弹爆炸的方法:

# 处理核弹爆炸,由于核弹爆炸属于特殊事件,放在类里处理不合OOP理念。当然也可以单独为核弹做一个类,不放在 Bullet 类中
def nuclear_explosiing(targetSurf, sound):
    for nuclear in nuclearGroup:
        if nuclear.rect.top < 500:
            nuclear.image = pygame.image.load(IMAGE_PATH + "nuclear_explosing.png").convert_alpha()
            for i in range(10):
                nuclear.image = pygame.transform.smoothscale(nuclear.image, (110 + 150 * i, 110 + 150 * i))
                nuclear.rect = Rect((0, 0), nuclear.image.get_size())
                nuclear.rect.center = (SCREEN_SIZE[0] // 2, SCREEN_SIZE[1] // 3)
                targetSurf.blit(nuclear.image, nuclear.rect)
                pygame.display.update()

            sound.play()

            # 核弹 kill
            nuclear.kill()
            return True

    return False

这里主要使用了pygame的transform功能,如果想让核弹爆的过程炸稍微慢一点,可以在update()后添加一个延时方法就可以了。有兴趣的朋友可以自己试一下。
下面开始主程序了。

def main():
    pygame.init()
    screen = pygame.display.set_mode(SCREEN_SIZE, 0, 32)
    pygame.display.set_caption("New Space Fighting")

    # 播放背景音乐
    pygame.mixer.init()
    pygame.mixer.music.set_volume(0.2)
    pygame.mixer.music.load(SOUND_PATH + 'bg.ogg')
    pygame.mixer.music.play(-1)

    bulletSound = pygame.mixer.Sound(SOUND_PATH + 'shoot_missile.ogg')
    bombSound = pygame.mixer.Sound(SOUND_PATH + 'bomb.ogg')
    nuclearSound = pygame.mixer.Sound(SOUND_PATH + 'shoot_nuclear.ogg')
    failureSound = pygame.mixer.Sound(SOUND_PATH + 'failure.ogg')

    screen.fill((0, 0, 0))

    # 初始化 星空,英雄战机等
    space = Space(screen)

    # 所有子弹、敌机、英雄战机、导弹、核弹、package都在这个 layerGroup中,当然他们也在自己的功能Group里。
    layerGroup = LayeredUpdates()

    # 初始化英雄战机的总数量
    heroPlaneQty = HERO_PLANE_QTY
    
    # 先生产一架英雄战机
    heroPlane = HeroPlane(random.choice(list(HERO_PLANES.keys())),
                          (SCREEN_SIZE[0] // 2, SCREEN_SIZE[1] - 100),
                          layerGroup, heroPlaneGroup)

    heroPlaneGroup.draw(screen)
    pygame.display.update()

    # 重复按键设置,所有键响应延迟一样
    # 游戏过程中根据得分情况改变参数, 得分达到一定级别 降低延迟,就提高了速度---------------------------
    pygame.key.set_repeat(30, 40)

    # 控制update()的频率
    fpsClock = pygame.time.Clock()
    
    # 用于控制Space中Star的数量和速度等
    spaceClock = pygame.time.Clock()

    while heroPlaneQty:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                exit()

			# SPACE KEYDOWN 飞机变形,KEYUP 恢复
            heroPlane.transform(event)
			
            key_pressed = pygame.key.get_pressed()
			# a,s,w,d 控制英雄战机的飞行
            heroPlane.move(key_pressed)
			
			# i,j,k,l 分别发射核弹,普通子弹,导弹,强力子弹
            heroPlane.shoot(key_pressed, (bulletSound, nuclearSound))

        # 根据核弹位置是否引爆核弹。这里将nuclear_explosiing()放在公共函数文件中了。
        if gf.nuclear_explosiing(screen, nuclearSound):
            # 核爆过后,整个世界安静了
            for sp in enemyPlaneGroup:
                sp.kill()
            for sp in enemyBulletGroup:
                sp.kill()
            for sp in heroBulletGroup:
                sp.kill()

        # 间隔 一段时候后增加敌机,可以通过这个改变生产敌机的速度和每次生产敌机的数量。
        if pygame.time.get_ticks() % 20 <= 1:
            EnemyPlane(random.choice(list(ENEMY_PLANES.keys())), layerGroup, enemyPlaneGroup)

        # 敌我子弹碰撞互相消灭
        pygame.sprite.groupcollide(enemyBulletGroup, heroBulletGroup, True, True)

        # 击中敌机后使用杀伤力和防御力计算是否消失
        for enemyPlane in enemyPlaneGroup:
            enemyPlane.was_shot(heroBulletGroup, bombSound)

        # 英雄战机捡到包裹
        for package in packageGroup:
            if pygame.sprite.collide_rect(package, heroPlane):
                heroPlane.pickup_package(package.type)
                package.kill()

        # 处理 heroPlane 被子弹击中 或者被 敌机撞击
        if heroPlane.was_collided(enemyBulletGroup) or heroPlane.was_collided(enemyPlaneGroup):
            heroPlane.kill()
            # 游戏失败
            if heroPlaneQty < 1:
                failureSound.play()
                break

            heroPlaneQty -= 1
            heroPlane = HeroPlane(random.choice(list(HERO_PLANES.keys())),
                                  (SCREEN_SIZE[0] // 2, SCREEN_SIZE[1] - 100),
                                  layerGroup, heroPlaneGroup)

        # 更新集群中精灵的位置
        tick = pygame.time.get_ticks()
        layerGroup.update(tick)

		# 刷新背景
        screen.fill((0, 0, 0))
		
		# 星空背景
        space.showspace(spaceClock)

        # 显示集群中所有精灵
        layerGroup.draw(screen)
		
		# 刷新屏幕
        pygame.display.update()

		# 控制帧率
        fpsClock.tick(40)


if __name__ == "__main__":
    main()

好了,现在基本上可以玩游戏了。当然,还缺少素材还有文件组织。为了方便有兴趣的朋友,我自己做了一点素材,这里提供给给大家。
由于不让添加压缩文件,只好一个一个上了。
简单说一下,头向上的是英雄战机和子弹,向下的是敌机和子弹,还有package(药箱、核弹、强力子弹),核爆效果图等,有兴趣的朋友可以根据配置文件来给图片命名。也可以修改配置文件改为自己喜欢的名字。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
Python游戏之Pygame——太空飞机大战(四)_第1张图片
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
都说没有声音,再好的戏也出不来。但是没办法上传声音啊,哀莫能租。但是这难不倒真正有兴趣的朋友。
Python游戏之Pygame——太空飞机大战(四)_第2张图片
大家可以从万能的网上找到自己喜欢的音效。
下面是本游戏的文件组织
Python游戏之Pygame——太空飞机大战(四)_第3张图片
嗯?怎么这里还有label,button,message,scoreboard啊?在这个系列的第一篇已经说过了,之前单独有一篇关于一文学习pygame之Layer的文章,大家可以看一下。不过这些不是玩游戏必须的,通过这个系列四篇文章的内容,完全可以开始自己的游戏之旅了。当然有兴趣继续探索的朋友可以给游戏添加辅助功能,比如记分、显示剩余战机数量、适当修改程序提供选择那种战机、选择那种子弹组合、剩余多少核弹等等,这些就留给真正感兴趣的朋友吧,动手是最好的学习方法,不是吗?

有兴趣的朋友可以根据自己的理解组织文件结构,然后调试的过程中自己 import相关的包。说明一下,我的环境是 win10 + python3.7 + pycharm。需要引入的包如下:

import pygame
from pygame.sprite import Group
from pygame.sprite import Sprite
from pygame.sprite import LayeredUpdates
from pygame.locals import *
import random
from sys import exit

另外几个全局Group放在setting里面了

enemyBulletGroup = Group()		# 敌机发射的子弹组
heroBulletGroup = Group()		# 英雄子弹组
enemyPlaneGroup = Group()		# 敌机组
heroPlaneGroup = Group()		# 英雄组
nuclearGroup = Group()			# 核弹组
packageGroup = Group()          # 被击落的敌机可能掉出的包

好了,我也是个初学Python的菜鸟,编码的过程难免有些不雅的地方。有些可以改善的地方,比如
1、敌机和英雄战机可以把公共部分组织为一个飞机基类,然后对基类扩展为响应的敌机类和英雄战机类
2、尽可能减小主程序中while 循环体的大小,将相关 fighting过程打包为函数放在公共的 functions.py里面
等等,这些就留给真正有兴趣,想写出更优雅python代码的朋友吧。

有些小的细节,比如事件处理中为什么同时使用了键盘事件的两种方式,需要大家动手玩一玩就会更清楚,比如用了Group,为什么通篇都没有看到 Group的 .add() 和 remove()方法等,精灵怎么进入gourp的?怎么remove的?如果改用 add() 和 remove() 方法,会有什么问题吗?需要实践去探索。

另外,有些参数并不是最佳的,比如键盘响应时间间隔、帧率、敌机生产速度、发射子弹的频率等等,还有相关素材,如果想要更好的效果,需要更好的图片和声音素材,需要对参数进行细调。这些就不在本文的范畴了。

谢谢大家的阅读!

你可能感兴趣的:(Python,Pygame,Sprite)