第091讲: Pygame:飞机大战2 | 学习记录(小甲鱼零基础入门学习Python)

之前我们实现了游戏的背景和背景音乐,接下来,我们应该让主角闪亮登场了,创建一个名为 myplane 的模块,然后把我方飞机的所有属性和方法定义在里边。(在这里我就是直接写在一个模块里了。图片啥的也都一开始全部导入了,先单独分开把,之后整合到一起)

from pygame.locals import *
from random import *
import pygame
import sys

"""\/\/\/\/\/\/\/\/------我的飞机类------\/\/\/\/\/\/\/\/"""

me1_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\me1.png" #自身飞机第一张图片
me2_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\me2.png" #自身飞机第二张图片

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 - 60) ]  #设置我方飞机出现的位置
        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 - 60) : #如果我方飞机没有飞出 上方边界
            self.rect.bottom += 10 #那么我方飞机朝下飞10个像素
        else :  #飞出 下方边界
            self.rect.bottom = (self.height - 60)  #锁定在底边界上方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 #锁定在底边界的位置,不再发生变化

那么接下来我们就需要在 main 模块中响应用户的键盘操作,响应用户的键盘操作有两种方法:

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

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

我们这里有一个建议:对于检测偶然触发的键盘事件,我们推荐使用方法1,例如该游戏中会设置一个全屏炸弹,按下空格键时爆炸,这是偶然触发的,没有经常触发,这时使用第1种方法较好;对于频繁触发的键盘事件,我们则建议使用第二种方法,例如控制飞机移动的4个方向键,我们就使用方法2。

接着来改一下我们的 main 函数:(已经将myplane()放入到主函数中)

from pygame.locals import *
from random import *
import traceback
import tkinter as tk
import pygame
import math
import sys

from pygame.locals import *
from random import *
import pygame
import sys


"""\/\/\/\/\/\/\/\/------我的飞机类------\/\/\/\/\/\/\/\/"""

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 - 60) ]  #设置我方飞机出现的位置
        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 - 60) : #如果我方飞机没有飞出 上方边界
            self.rect.bottom += 10 #那么我方飞机朝下飞10个像素
        else :  #飞出 下方边界
            self.rect.bottom = (self.height - 60)  #锁定在底边界上方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() :
    pygame.init()   #初始化
    pygame.mixer.init()     #混音器初始化

    clock = pygame.time.Clock()     #设置一个计时器

    """载入音乐文件"""
    #背景音乐
    pygame.mixer.music.load(r"D:\Code\Python\Pygame\pygame11:飞机大战1\sound\game_music.ogg")  #设置背景音乐
    pygame.mixer.music.set_volume(1)  #设置音量

    #游戏音效
    bullet_music = r"D:\Code\Python\Pygame\pygame11:飞机大战1\sound\bullet.wav"  #子弹特效
    button_music = r"D:\Code\Python\Pygame\pygame11:飞机大战1\sound\button.wav"    #按键特效
    enemy1_down_music = r"D:\Code\Python\Pygame\pygame11:飞机大战1\sound\enemy1_down.wav"    #低等敌机被击毁音效
    enemy2_down_music = r"D:\Code\Python\Pygame\pygame11:飞机大战1\sound\enemy2_down.wav"    #中等敌机被击毁音效
    enemy3_down_music = r"D:\Code\Python\Pygame\pygame11:飞机大战1\sound\enemy3_down.wav"    #高等敌机被击毁音效
    enemy3_fly_music = r"D:\Code\Python\Pygame\pygame11:飞机大战1\sound\enemy3_flying.wav"    #高等敌机出现音效
    get_bomb_music = r"D:\Code\Python\Pygame\pygame11:飞机大战1\sound\get_bomb.wav"    #获得全屏炸弹补给音效
    get_bullet_music = r"D:\Code\Python\Pygame\pygame11:飞机大战1\sound\get_bullet.wav"    #获得双倍子弹补给音效
    me_down_music = r"D:\Code\Python\Pygame\pygame11:飞机大战1\sound\me_down.wav"    #自身飞机被击毁(死亡)音效
    supply_music = r"D:\Code\Python\Pygame\pygame11:飞机大战1\sound\supply.wav"    #补给产生音效
    upgrade_music = r"D:\Code\Python\Pygame\pygame11:飞机大战1\sound\upgrade.wav"    #升级音效
    use_bomb_music = r"D:\Code\Python\Pygame\pygame11:飞机大战1\sound\use_bomb.wav"    #使用全屏炸弹音效

    """图片文件路径"""
    again_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\again.png"   #重新开始图片路径
    background_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\background.png"  #背景图的路径
    bomb_supply_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\bomb_supply.png" #全屏炸弹补给图
    bomb_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\bomb.png"   #全屏炸弹图
    bullet_supply_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\bullet_supply.png" #补给子弹图
    bullet1_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\bullet1.png" #第一种子弹图
    bullet2_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\bullet2.png" #第二种子弹图
    enemy1_down1_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy1_down1.png"    #低级敌机撞到爆炸第一张图片
    enemy1_down2_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy1_down2.png"    #低级敌机撞到爆炸第二张图片
    enemy1_down3_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy1_down3.png"    #低级敌机撞到爆炸第三张图片
    enemy1_down4_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy1_down4.png"    #低级敌机撞到爆炸第四张图片
    enemy1_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy1.png"  #低级敌机图片
    enemy2_down1_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy2_down1.png"    #中级敌机撞到爆炸第一张图片
    enemy2_down2_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy2_down2.png"    #中级敌机撞到爆炸第二张图片
    enemy2_down3_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy2_down3.png"    #中级敌机撞到爆炸第三张图片
    enemy2_down4_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy2_down4.png"    #中级敌机撞到爆炸第四张图片
    enemy2_hit_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy2_hit.png"   #中级敌机碰撞图片
    enemy2_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy2.png"  #中级敌机图片
    enemy3_down1_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy3_down1.png"    #高级敌机撞到爆炸第四张图片
    enemy3_down2_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy3_down2.png"    #高级敌机撞到爆炸第四张图片
    enemy3_down3_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy3_down3.png"    #高级敌机撞到爆炸第四张图片
    enemy3_down4_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy3_down4.png"    #高级敌机撞到爆炸第四张图片
    enemy3_down5_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy3_down5.png"    #高级敌机撞到爆炸第四张图片
    enemy3_down6_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy3_down6.png"    #高级敌机撞到爆炸第四张图片
    enemy3_hit_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy3_hit.png"  #高级敌机碰撞图片
    enemy3_n1_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy3_n1.png"   #高级敌机图片1
    enemy3_n2_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy3_n2.png"   #高级敌机图片2
    gameover_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\gameover.png"    #游戏结束图片
    life_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\life.png"    #表示生命值的图片
    me_destory_1_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\me_destroy_1.png"    #自身飞机炸毁第一张图片
    me_destory_2_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\me_destroy_2.png"    #自身飞机炸毁第二张图片
    me_destory_3_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\me_destroy_3.png"    #自身飞机炸毁第三张图片
    me_destory_4_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\me_destroy_4.png"    #自身飞机炸毁第四张图片
    me1_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\me1.png" #自身飞机第一张图片
    me2_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\me2.png" #自身飞机第二张图片
    pause_nor_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\pause_nor.png"   #暂停的时候图片
    pause_pressed_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\pause_pressed.png"   #暂停到继续的中间变换图
    resume_nor_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\resume_nor.png"  #继续的时候的图片
    resume_pressed_image =r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\resume_pressed.png"   #继续到暂停的中间变换图

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

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

    while True :
        for event in pygame.event.get() :
            if event.type == QUIT :
                sys.exit()

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

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

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

        pygame.display.flip()   #不停的刷新画面,不停的绘画

        clock.tick(60)     #设置帧率

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

我们的飞机就生成了,也可以根据键盘上的 AWSD 或者方向键进行移动控制。

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

第091讲: Pygame:飞机大战2 | 学习记录(小甲鱼零基础入门学习Python)_第1张图片

我们就只需要:

1、在 myplane.py中加多一种图片

from pygame.locals import *
from random import *
import pygame
import sys

"""\/\/\/\/\/\/\/\/------我的飞机类------\/\/\/\/\/\/\/\/"""

me1_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\me1.png" #自身飞机第一张图片
me2_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\me2.png" #自身飞机第二张图片

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 - 60) ]  #设置我方飞机出现的位置
        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 - 60) : #如果我方飞机没有飞出 上方边界
            self.rect.bottom += 10 #那么我方飞机朝下飞10个像素
        else :  #飞出 下方边界
            self.rect.bottom = (self.height - 60)  #锁定在底边界上方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 #锁定在底边界的位置,不再发生变化

2、在main.py中
首先计算一个布尔类型的变量用于控制切换图片;然后在绘制我方飞机这里交叉显示两张图片。

#绘制飞机
        if transform :  #如果改变属性为真  画第一张飞机图
            screen.blit(myself.image1,myself.rect)  #绘制第一张飞机图
            transform = False    #改变transform的属性来打到改变图片的效果
        else :  #如果改变属性为假  画第二张飞机图
            screen.blit(myself.image2,myself.rect)  #绘制第一张飞机图
            transform = True

但是我们这样改,飞机还是没有理想中 “突突突” 的感觉,毕竟我们的帧率为60(每秒切换60次),我们最好在不影响游戏性能的情况来延迟图片的切换,这里我们就使用单片机开发中常常用到的一招,增加一个延时变量:

#绘制飞机
        if transform :  #如果改变属性为真  画第一张飞机图
            if delay == 0:
                delay = 100
            delay -= 1
            transform = False    #改变transform的属性来打到改变图片的效果
        else :  #如果改变属性为假  画第二张飞机图
            if delay == 0:
                delay = 100
            delay -= 1
            transform = True

        if delay % 5 :
            screen.blit(myself.image2,myself.rect)  #绘制第二张飞机图
        elif not delay % 5 :
            screen.blit(myself.image1,myself.rect)  #绘制第一张飞机图

接下来就来创造敌机啦:

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

from pygame.locals import *
from random import *
import pygame
import sys

enemy1_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy1.png"  #低级敌机图片

enemy2_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy2.png"  #中级敌机图片

enemy3_n1_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy3_n1.png"   #高级敌机图片1
enemy3_n2_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy3_n2.png"   #高级敌机图片2

"""\/\/\/\/\/\/\/\/------敌机类------\/\/\/\/\/\/\/\/"""
"""本来这里其实可以使用类的继承,然后三种敌机分别继承这个敌机类生成新的敌机,但是在这里、
    没有这样做的必要,因为三个类的差别并不是很大,所以不用那么繁杂"""
class SmallEnemy(pygame.sprite.Sprite):  #定义我的敌机类,继承自动画精灵
    def __init__(self,bg_size,enemy1_image):
        pygame.sprite.Sprite.__init__(self)

        self.enemy1_image = enemy1_image
        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()   #获得低级敌机的尺寸
        self.rect.left , self.rect.top = [ randint(0 , self.width - self.rect.width ) ,\
                                                     randint(-5*self.height , 0) ]      #在窗口的5倍之上的距离中产生飞机
        self.speed = 3  #设置小敌机移动的速度

    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 MiddleEnemy(pygame.sprite.Sprite):  #定义我的敌机类,继承自动画精灵
    def __init__(self,bg_size,enemy2_image):
        pygame.sprite.Sprite.__init__(self)
        self.enemy2_image = enemy2_image
        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 = 2  #设置中敌机移动的速度

    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_image = enemy3_n1_image
        self.enemy3_n1 = pygame.image.load(enemy3_n1_image).convert_alpha()   #载入高级敌机照片
        self.enemy3_n2_image = enemy3_n1_image
        self.enemy3_n2 = pygame.image.load(enemy3_n2_image).convert_alpha()   #载入高级敌机照片

        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倍之上的距离中产生飞机

敌机的定义有了,我们接下来就在main 模块中将它们实例化:

from pygame.locals import *
from random import *
import traceback
import tkinter as tk
import pygame
import math
import sys

"""\/\/\/\/\/\/\/\/------我的飞机类------\/\/\/\/\/\/\/\/"""
class MyPlane (pygame.sprite.Sprite):       #定义我的飞机类,继承动画精灵类(因为之后要进行碰撞检测)
    def __init__(self,bg_size,me1_image,me2_image) :
        pygame.sprite.Sprite.__init__(self)
        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 - 60) ]  #设置我方飞机出现的位置
        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 - 60) : #如果我方飞机没有飞出 上方边界
            self.rect.bottom += 10 #那么我方飞机朝下飞10个像素
        else :  #飞出 下方边界
            self.rect.bottom = (self.height - 60)  #锁定在底边界上方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_image = enemy1_image
        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()   #获得低级敌机的尺寸
        self.rect.left , self.rect.top = [ randint(0 , self.width - self.rect.width ) ,\
                                                     randint(-5*self.height , 0) ]      #在窗口的5倍之上的距离中产生飞机
        self.speed = 3  #设置小敌机移动的速度

    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 MiddleEnemy(pygame.sprite.Sprite):  #定义我的敌机类,继承自动画精灵
    def __init__(self,bg_size,enemy2_image):
        pygame.sprite.Sprite.__init__(self)
        self.enemy2_image = enemy2_image
        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 = 2  #设置中敌机移动的速度

    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_image = enemy3_n1_image
        self.enemy3_n1 = pygame.image.load(enemy3_n1_image).convert_alpha()   #载入高级敌机照片
        self.enemy3_n2_image = enemy3_n1_image
        self.enemy3_n2 = pygame.image.load(enemy3_n2_image).convert_alpha()   #载入高级敌机照片

        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 main() :
    pygame.init()   #初始化
    pygame.mixer.init()     #混音器初始化

    clock = pygame.time.Clock()     #设置一个计时器

    transform = False   #设置一个是否改变的变量
    delay = 100 #类似于单片机,设置一个延时变量,让飞机的改变看起来更加的顺滑
    switch_image = True     # 用于切换图片

    """载入音乐文件"""
    #背景音乐
    pygame.mixer.music.load(r"D:\Code\Python\Pygame\pygame11:飞机大战1\sound\game_music.ogg")  #设置背景音乐
    pygame.mixer.music.set_volume(1)  #设置音量

    #游戏音效
    bullet_sound = pygame.mixer.Sound( r"D:\Code\Python\Pygame\pygame11:飞机大战1\sound\bullet.wav")  #子弹特效
    bullet_sound.set_volume(0.2)
    button_sound = pygame.mixer.Sound( r"D:\Code\Python\Pygame\pygame11:飞机大战1\sound\button.wav")    #按键特效
    button_sound.set_volume(0.3)
    enemy1_down_sound = pygame.mixer.Sound( r"D:\Code\Python\Pygame\pygame11:飞机大战1\sound\enemy1_down.wav")    #低等敌机被击毁音效
    enemy1_down_sound.set_volume(0.3)
    enemy2_down_sound = pygame.mixer.Sound( r"D:\Code\Python\Pygame\pygame11:飞机大战1\sound\enemy2_down.wav")    #中等敌机被击毁音效
    enemy2_down_sound.set_volume(0.3)
    enemy3_down_sound = pygame.mixer.Sound( r"D:\Code\Python\Pygame\pygame11:飞机大战1\sound\enemy3_down.wav")    #高等敌机被击毁音效
    enemy3_down_sound.set_volume(0.3)
    enemy3_fly_sound = pygame.mixer.Sound( r"D:\Code\Python\Pygame\pygame11:飞机大战1\sound\enemy3_flying.wav")    #高等敌机出现音效
    enemy3_fly_sound.set_volume(0.3)
    get_bomb_sound = pygame.mixer.Sound(  r"D:\Code\Python\Pygame\pygame11:飞机大战1\sound\get_bomb.wav")    #获得全屏炸弹补给音效
    get_bomb_sound.set_volume(0.4)
    get_bullet_sound = pygame.mixer.Sound(  r"D:\Code\Python\Pygame\pygame11:飞机大战1\sound\get_bullet.wav")    #获得双倍子弹补给音效
    get_bullet_sound.set_volume(0.4)
    me_down_sound = pygame.mixer.Sound(  r"D:\Code\Python\Pygame\pygame11:飞机大战1\sound\me_down.wav")    #自身飞机被击毁(死亡)音效
    me_down_sound.set_volume(0.3)
    supply_sound = pygame.mixer.Sound(  r"D:\Code\Python\Pygame\pygame11:飞机大战1\sound\supply.wav")    #补给产生音效
    supply_sound.set_volume(0.4)
    upgrade_sound = pygame.mixer.Sound(  r"D:\Code\Python\Pygame\pygame11:飞机大战1\sound\upgrade.wav")    #升级音效
    upgrade_sound.set_volume(0.3)
    use_bomb_sound = pygame.mixer.Sound(  r"D:\Code\Python\Pygame\pygame11:飞机大战1\sound\use_bomb.wav")    #使用全屏炸弹音效
    use_bomb_sound.set_volume(0.4)

    """图片文件路径"""
    again_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\again.png"   #重新开始图片路径
    background_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\background.png"  #背景图的路径
    bomb_supply_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\bomb_supply.png" #全屏炸弹补给图
    bomb_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\bomb.png"   #全屏炸弹图
    bullet_supply_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\bullet_supply.png" #补给子弹图
    bullet1_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\bullet1.png" #第一种子弹图
    bullet2_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\bullet2.png" #第二种子弹图
    enemy1_down1_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy1_down1.png"    #低级敌机撞到爆炸第一张图片
    enemy1_down2_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy1_down2.png"    #低级敌机撞到爆炸第二张图片
    enemy1_down3_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy1_down3.png"    #低级敌机撞到爆炸第三张图片
    enemy1_down4_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy1_down4.png"    #低级敌机撞到爆炸第四张图片
    enemy1_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy1.png"  #低级敌机图片
    enemy2_down1_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy2_down1.png"    #中级敌机撞到爆炸第一张图片
    enemy2_down2_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy2_down2.png"    #中级敌机撞到爆炸第二张图片
    enemy2_down3_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy2_down3.png"    #中级敌机撞到爆炸第三张图片
    enemy2_down4_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy2_down4.png"    #中级敌机撞到爆炸第四张图片
    enemy2_hit_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy2_hit.png"   #中级敌机被子弹打到后图片
    enemy2_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy2.png"  #中级敌机图片
    enemy3_down1_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy3_down1.png"    #高级敌机撞到爆炸第四张图片
    enemy3_down2_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy3_down2.png"    #高级敌机撞到爆炸第四张图片
    enemy3_down3_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy3_down3.png"    #高级敌机撞到爆炸第四张图片
    enemy3_down4_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy3_down4.png"    #高级敌机撞到爆炸第四张图片
    enemy3_down5_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy3_down5.png"    #高级敌机撞到爆炸第四张图片
    enemy3_down6_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy3_down6.png"    #高级敌机撞到爆炸第四张图片
    enemy3_hit_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy3_hit.png"  #高级敌机被子弹打到后图片
    enemy3_n1_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy3_n1.png"   #高级敌机图片1
    enemy3_n2_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\enemy3_n2.png"   #高级敌机图片2
    gameover_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\gameover.png"    #游戏结束图片
    life_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\life.png"    #表示生命值的图片
    me_destory_1_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\me_destroy_1.png"    #自身飞机炸毁第一张图片
    me_destory_2_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\me_destroy_2.png"    #自身飞机炸毁第二张图片
    me_destory_3_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\me_destroy_3.png"    #自身飞机炸毁第三张图片
    me_destory_4_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\me_destroy_4.png"    #自身飞机炸毁第四张图片
    me1_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\me1.png" #自身飞机第一张图片
    me2_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\me2.png" #自身飞机第二张图片
    pause_nor_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\pause_nor.png"   #暂停的时候图片
    pause_pressed_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\pause_pressed.png"   #暂停到继续的中间变换图
    resume_nor_image = r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\resume_nor.png"  #继续的时候的图片
    resume_pressed_image =r"D:\Code\Python\Pygame\pygame11:飞机大战1\images\resume_pressed.png"   #继续到暂停的中间变换图

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

    #生成自己飞机
    myself = MyPlane(bg_size,me1_image,me2_image)    

    #生成敌机组
    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)

    #生成敌机组
    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()

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

        # 绘制大型敌机
        for each in bigenemies:
            each.move()
            if switch_image:
                switch_image = False
                screen.blit(each.enemy3_n1, each.rect)
            else:
                switch_image = True
                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 transform :  #如果改变属性为真  画第一张飞机图
            if delay == 0:
                delay = 100
            delay -= 1
            transform = False    #改变transform的属性来打到改变图片的效果

        else :  #如果改变属性为假  画第二张飞机图
            if delay == 0:
                delay = 100
            delay -= 1
            transform = True

        if delay % 5 :
            screen.blit(myself.image2,myself.rect)  #绘制第二张飞机图
        elif not delay % 5 :
            screen.blit(myself.image1,myself.rect)  #绘制第一张飞机图

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





        pygame.display.flip()   #不停的刷新画面,不停的绘画

        clock.tick(60)     #设置帧率


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

我们可以看到敌机依次出来,由于我们现在还没有做碰撞检测,所以它们可以友好的交叉飞过,我们在下节课中会教大家如何做完美的碰撞检测,因为飞机是不规则的图形,所有我们没办法像之前讲小球一样弄一个半径。但是别担心,这种不规则的图形也可以做完美的碰撞检测,大家拭目以待吧。
第091讲: Pygame:飞机大战2 | 学习记录(小甲鱼零基础入门学习Python)_第2张图片

你可能感兴趣的:(第091讲: Pygame:飞机大战2 | 学习记录(小甲鱼零基础入门学习Python))