飞机大战

  • 1.main类
  • 2.配置类
  • 3.游戏主类
  • 4.游戏资源类
  • 5.资源下载
  • 6.游戏效果
  • 1.main类

    启动游戏。

    from MainWindow import MainWindow
    if __name__ == '__main__':
        app=MainWindow()
        app.run()
    

    2.配置类

    该类主要存放游戏的各种设置参数。

    #窗口尺寸
    #窗口尺寸
    import random
    import pygame
    WINDOW=pygame.Rect(0,0,512,768)
    #窗口名字
    WINDOW_NAME="飞机大战v1.0"
    
    #地图索引
    MAP_INDEX=random.randint(1,5)
    
    #英雄子弹类型
    HERO_BULLET_INDEX=1
    #敌人子弹类型
    ENEMY_BULLET_INDEX=3
    
    #敌机事件
    ENEMY_EVENT=pygame.USEREVENT#pygame用户事件(整型),有多个事件可以在后面+1以区分
    
    #英雄子弹事件
    BULLET_EVENT=pygame.USEREVENT+1#+1区分事件
    #敌机子弹事件
    BULLET_ENEMY_EVENT=pygame.USEREVENT+2#+2区分事件
    
    #英雄移动速度
    HERO_MOVE_SPEED=4
    #英雄子弹移动速度
    HERO_BULLET_MOVE_SPEED=4
    #英雄生命值
    HERO_HP=10
    

    3.游戏主类

    游戏主类主要由游戏窗口创建、精灵和精灵组的创建、游戏启动函数(1.碰撞检测、2.事件处理、3.精灵组更新、4.窗口刷新)等构成。

    import pygame
    from Config import *
    from GameSprite import *
    class MainWindow:
        def __init__(self):
            pygame.init()
            #游戏窗口初始化
            self.window=pygame.display.set_mode([WINDOW.width,WINDOW.height])
            pygame.display.set_caption(WINDOW_NAME)
            #背景音乐
            pygame.mixer.music.load("./source/music/bg.wav")
            pygame.mixer.music.set_volume(0.1)
            pygame.mixer.music.play(-1)
            #爆炸音效
            self.bomb=pygame.mixer.Sound("./source/music/bomb.wav")
            self.bomb.set_volume(0.2)
            #游戏分数
            self.score=0
            self.hp=HERO_HP
            self.pause_flag = False  # 暂停标志
    
            #FPS时钟
            self.clock=pygame.time.Clock()
            #激活敌机定时器,参数:事件、间隔时间ms
            pygame.time.set_timer(ENEMY_EVENT,500)
            # 激活英雄子弹定时器,参数:事件、间隔时间ms
            pygame.time.set_timer(BULLET_EVENT,500)
            pygame.time.set_timer(BULLET_ENEMY_EVENT,2000)
            #创建精灵组
            self.create_sprite_group()
    
        #精灵组创建
        def create_sprite_group(self):
            #地图精灵组
            map1=GameMap()
            map2=GameMap(True)
            self.map_group=pygame.sprite.Group(map1,map2)
            #英雄精灵
            self.hero=Hero()
            self.hero_group=pygame.sprite.Group(self.hero)
            #敌机精灵组
            self.enemy_group=pygame.sprite.Group()
            #英雄子弹精灵组
            self.bullet_group=pygame.sprite.Group()
            #敌机子弹精灵组
            self.bullet_enemy_group=pygame.sprite.Group()
            #爆炸动画精灵组
            self.bomb_group=pygame.sprite.Group()
            # 菜单精灵组
            self.resume_nor = Menu("./source/resume_nor.png")  # 正在暂停按钮图标
            self.pause_nor = Menu("./source/pause_nor.png")  # 正在运行图标
            self.restart = Menu("./source/again.png")  # 重新开始图标
            self.menu_group = pygame.sprite.Group()
            # 显示精灵组
            self.show_group = pygame.sprite.Group()
    
    
        # 碰撞检测
        def collie_check(self):
            #1.英雄子弹与敌机
            for bullet1 in self.bullet_group:
                #第一个参数是精灵、第二个参数是精灵组、第三个参数为是否删除与该精灵碰撞的所有精灵;返回值为与第一个参数碰撞的所有精灵列表
                eys=pygame.sprite.spritecollide(bullet1,self.enemy_group,True)#判断子弹精灵是否与敌机精灵组有碰撞,有则杀死所有敌机
                #表示有碰撞
                if len(eys)>0:
                    self.bomb.play()#发生碰撞,播放爆炸音效
                    self.score+=1#记录杀死的敌机数量
                    bullet1.kill()#杀死发生碰撞的子弹精灵
                    bomb_enemy=Bomb(eys[0])#将发生碰撞的敌传入爆炸类,方便使用爆炸的具体位置
                    self.bomb_group.add(bomb_enemy)#加入爆炸精灵组
    
            #2.敌机子弹与英雄
            bullet2=pygame.sprite.spritecollide(self.hero,self.bullet_enemy_group,True)
            if len(bullet2)>0:
                self.bomb.play()#发生碰撞,播放爆炸音效
                self.hp-=1#英雄与敌机子弹接触,自身HP值-1
    
            #敌机与英雄
            enemys=pygame.sprite.spritecollide(self.hero,self.enemy_group,True)
            if len(enemys)>0:
                self.bomb.play()#发生碰撞,播放爆炸音效
                self.hp-=1#英雄与敌机接触,自身HP值-1
                bomb_enemy2 = Bomb(enemys[0])#将发生碰撞的敌传入爆炸类,方便使用爆炸的具体位置
                self.bomb_group.add(bomb_enemy2)#加入爆炸精灵组
            # 英雄生命值为0,暂停游戏,并且显示重新开始
            if self.hp <0:
                self.hero.kill()
                self.enemy_group.empty()
                self.bullet_group.empty()
                self.bullet_enemy_group.empty()
                self.pause_flag = True
                self.restart.rect.centerx = self.window.get_rect().centerx
                self.restart.rect.centery = self.window.get_rect().centery
                self.menu_group.add(self.restart)
        # 更新精灵组位置并绘制
        def sprite_group_update_draw(self):
            #地图精灵组更新
            self.map_group.update()
            self.map_group.draw(self.window)
            #英雄精灵组更新
            self.hero_group.update()
            self.hero_group.draw(self.window)
            #敌机精灵组更新
            self.enemy_group.update()
            self.enemy_group.draw(self.window)
            #英雄子弹精灵组
            self.bullet_group.update()
            self.bullet_group.draw(self.window)
            #敌机子弹精灵组
            self.bullet_enemy_group.update()
            self.bullet_enemy_group.draw(self.window)
            #爆炸精灵组
            self.bomb_group.update()
            self.bomb_group.draw(self.window)
            # 菜单类精灵组
            self.menu_group.update()
            self.menu_group.draw(self.window)
            # 显示信息
            self.show_group.update()
            self.show_group.draw(self.window)
            #绘制数据 #游戏数据
            # 显示游戏信息
            self.score1 = Show("得分", self.score)
            self.score1.rect.x = 80
            self.score1.rect.y = 0
            self.hp1 = Show("生命值", self.hp)
            self.hp1.rect.x = 200
            self.hp1.rect.y = 0
            self.show_group.empty()
            self.show_group.add(self.score1, self.hp1)
    
    
        # 事件处理
        def handle_events(self):
            #pygame.event.get()获取当前时间帧的所有事件,返回一个事件列表,可以对此列表遍历
            for event in pygame.event.get():
                if event.type==pygame.QUIT:
                    pygame.quit()
                    exit()
                #用户事件1,固定时间生成敌机(时间可以在窗口初始化代码中修改)
                if event.type==pygame.USEREVENT:
                    self.enemy=Enemy()
                    self.enemy_group.add(self.enemy)
                #用户事件2,固定时间生成敌机子弹(时间可以在窗口初始化代码中修改)
                if event.type==pygame.USEREVENT+2:
                    #固定时间生成敌机子弹,需要遍历敌机精灵组,获取所有已经存在的敌机精灵,在对应的位置上绘制敌机子弹
                    for enemy_sprite in self.enemy_group:
                        self.bullet_enemy = Bullet(enemy_sprite.speed + 1,True)
                        self.bullet_enemy.rect.centerx = enemy_sprite.rect.centerx
                        self.bullet_enemy.rect.y =enemy_sprite.rect.bottom
                        #将敌机子弹精灵添加到敌机子弹精灵组
                        self.bullet_enemy_group.add(self.bullet_enemy)
                #用户事件3,固定时间生成英雄子弹(时间可以在窗口初始化代码中修改)
                if event.type==pygame.USEREVENT+1:
                    self.bullet_hero=Bullet(-HERO_BULLET_MOVE_SPEED)#英雄子弹飞行方向与敌机子弹飞行方向相反
                    #根据英雄的当前位置来设置英雄子弹的位置
                    self.bullet_hero.rect.centerx=self.hero.rect.centerx
                    self.bullet_hero.rect.y=self.hero.rect.y-self.bullet_hero.rect.height
                    # 将英雄飞机子弹精灵添加到英雄子弹精灵组
                    self.bullet_group.add(self.bullet_hero)
                # 按下ESC切换暂停
                if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
                    self.pause_flag = not self.pause_flag  # 切换暂停状态
                # 鼠标点击切换暂停
                if event.type == pygame.MOUSEBUTTONDOWN and event.button == pygame.BUTTON_LEFT:
                    if self.pause_nor.rect.collidepoint(event.pos):
                        self.pause_flag = not self.pause_flag
    
    
            #pygame.key.get_pressed()获取当前时间帧的所有键盘事件并返回一个列表,遍历列表控制英雄上下左右移动
            keys_event=pygame.key.get_pressed()
            if keys_event[pygame.K_a] or keys_event[pygame.K_LEFT]:
                self.hero.x_speed=-HERO_MOVE_SPEED
            elif keys_event[pygame.K_d] or keys_event[pygame.K_RIGHT]:
                self.hero.x_speed=HERO_MOVE_SPEED
            else:
                self.hero.x_speed = 0
            if keys_event[pygame.K_w] or keys_event[pygame.K_UP]:
                self.hero.y_speed=-HERO_MOVE_SPEED
            elif keys_event[pygame.K_s] or keys_event[pygame.K_DOWN]:
                self.hero.y_speed=HERO_MOVE_SPEED
            else:
                self.hero.y_speed=0
            # 暂停状态下
            if self.pause_flag:
                if self.pause_nor in self.menu_group:
                    self.menu_group.remove(self.pause_nor)  # 将运行图标的精灵移除
                self.menu_group.add(self.resume_nor)
                pygame.mixer.music.pause()#暂停背景音乐
            # 非暂停状态
            else:
                if self.resume_nor in self.menu_group:
                    self.menu_group.remove(self.resume_nor)  # 将暂停图标的精灵移除
                self.menu_group.add(self.pause_nor)
                pygame.mixer.music.unpause()
    
    
            # 显示游戏信息
            self.score1 = Show("得分", self.score)
            self.score1.rect.x = 80
            self.score1.rect.y = 0
            self.hp1 = Show("生命值", self.hp)
            self.hp1.rect.x = 200
            self.hp1.rect.y = 0
            self.show_group.empty()
            self.show_group.add(self.score1, self.hp1)
        #游戏主框架
        def run(self):
            pygame.init()
            while True:
                #暂停状态
                while self.pause_flag:
    
                    self.clock.tick(60)
                    for event in pygame.event.get():
                        if event.type == pygame.QUIT:
                            pygame.quit()
                            exit()
                        # 按下ESC暂停
                        if event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
                            self.pause_flag = not self.pause_flag  # 切换暂停状态
                            # 鼠标点击切换暂停
                        if event.type == pygame.MOUSEBUTTONDOWN and event.button == pygame.BUTTON_LEFT:
                            if self.pause_nor.rect.collidepoint(event.pos):
                                self.pause_flag = not self.pause_flag
                            # 当英雄死亡之后,点击重新开始
                        if event.type == pygame.MOUSEBUTTONDOWN and event.button == pygame.BUTTON_LEFT:
                            pos = pygame.mouse.get_pos()
                            # 如果英雄死亡了,点击重新开始
                            if self.hp < 0 and self.restart.rect.collidepoint(pos):
                                self.menu_group.remove(self.restart)
                                self.score = 0
                                self.hero_group.add(self.hero)
                                self.hp = HERO_HP
                                self.pause_flag = False
                    # 切换到非暂停状态
                    if not self.pause_flag:
                        break
    
                #正常运行
                while not self.pause_flag:
                    self.clock.tick(60)  # FPS
                    #碰撞检测
                    self.collie_check()
                    # 事件处理
                    self.handle_events()
                    #更新精灵组
                    self.sprite_group_update_draw()
                    # 窗口刷新
                    pygame.display.update()
                    # 切换到暂停状态
                    if self.pause_flag:
                        break
    
    
    

    4.游戏资源类

    游戏资源类主要包括各种游戏相关元素精灵、主要有基础精灵类、敌机精灵类、子弹精灵类、英雄飞机精灵类、爆炸动画精灵类等。

    import  pygame
    from Config import *
    import random
    #精灵类————基类,定义了基本的导入图片操作,以及图片垂直移动操作
    class GameSprite(pygame.sprite.Sprite):
        def __init__(self,image_url,speed=0):
            super().__init__()
            self.image=pygame.image.load(image_url)
            self.rect=self.image.get_rect()
            self.speed=speed
        def update(self, *args, **kwargs):
            self.rect.y+=self.speed
    #游戏地图类,地图由两张完全一样的图片拼接构成,其中两张图片的起始和末尾要无缝衔接
    #第一张图片起始位置与窗口完全重合,第二张图片的起始位置在第一张图片的上方
    class GameMap(GameSprite):
        #is_1表示是否是第二张图片
        def __init__(self,is_1=False):
            #地图给了5张,保证地图索引在1~5,否则随机给一个1~5
            self.map_index=MAP_INDEX if 1<=MAP_INDEX<=5 else random.randint(1,5)
            map_filename=f"./source/map/map-{self.map_index}.jpg"
            super().__init__(map_filename,2)
            if is_1:
                self.rect.y=-WINDOW.height#第二张图片的起始位置在第一张图片的上方
        def update(self):
            #更新图像的位置
            super().update()
            #如果地图图片完全运动到了窗口最下方,就将这张图片的位置移动到窗口的最上方,作为新的起始位置
            if self.rect.y>=WINDOW.height:
                self.rect.y=-WINDOW.height
    #英雄飞机类,初始化定义比较简单
    class Hero(GameSprite):
        def __init__(self):
            super().__init__("./source/plane/hero.png")
            #定义英雄飞机出生在窗口中的具体位置
            self.rect.centerx=WINDOW.centerx
            self.rect.y=WINDOW.height-120
            #初始移动速度为0,静止状态
            self.x_speed=0
            self.y_speed=0
        def update(self, *args, **kwargs):
            #水平方向移动
            self.rect.x+=self.x_speed
            #垂直方向移动
            self.rect.y+=self.y_speed
            #判断上、下、左、右四个边界条件,如果移动到了边界,让飞机停在原位
            if self.rect.x<=0:
                self.rect.x=0
            if self.rect.x>=WINDOW.width-self.rect.width:
                self.rect.x=WINDOW.width-self.rect.width
            if self.rect.y<=0:
                self.rect.y=0
            if self.rect.y>=WINDOW.height-self.rect.height:
                self.rect.y=WINDOW.height-self.rect.height
    #敌机类
    class Enemy(GameSprite):
        def __init__(self):
            #敌机有7中飞机,随机生成
            self.enemy_url=f"./source/plane/enemy-{random.randint(1,7)}.png"
            #敌机的垂直速度也是随机生成(1,3)
            super().__init__(self.enemy_url,random.randint(1,3))
            #敌机的初始水平位置需要随机生成,范围就是(0,WINDOW.width-self.rect.width)
            self.rect.x=random.randint(0,WINDOW.width-self.rect.width)
            #敌机的垂直位置y是固定值,保证敌机出现的位置在窗口之外
            self.rect.y=-self.rect.height
            #敌机水平方向的移动速度随机生成
            self.x_speed=random.randint(-1,1)
        def update(self, *args, **kwargs):
            #调用父类的update()函数
            super().update()
            #父类函数不够用的情况下,直接补充
            self.rect.x+=self.x_speed#水平移动
            #如果到达左右边界则反向运动
            if self.rect.x<=0 or self.rect.x>=WINDOW.width-self.rect.width:
                self.x_speed=-self.x_speed
            #敌机出了窗口底部则杀死此敌机精灵
            if self.rect.y>WINDOW.height:
                self.kill()
    #子弹类(英雄飞机子弹和敌机子弹)
    class Bullet(GameSprite):
        #is_enemy表示是否是敌机,敌机和英雄飞机使用的子弹图片不同
        def __init__(self,speed,is_enemy=False):
            if is_enemy:
                self.bullet_index=ENEMY_BULLET_INDEX
            else:
                self.bullet_index = HERO_BULLET_INDEX
            bullet_filename = f"./source/bullet/bullet_{self.bullet_index}.png"
            self.speed=speed
            super().__init__(bullet_filename,self.speed)
            #由于敌机和英雄飞机是相对运动,资源图片都是正向的,所以如果是敌机子弹,则需要对子弹图片做旋转180°操作
            if is_enemy:
                ##flip(翻转的图片、是否绕x轴翻转、是否绕y轴翻转)
                self.image=pygame.transform.flip(self.image,False,True)
    
        def update(self, *args, **kwargs):
            #垂直方向移动
            super().update()
            #超出屏幕则杀死此精灵
            if self.rect.y<-self.rect.height or self.rect.y>WINDOW.height+self.rect.height:
                self.kill()
    #爆炸动画类
    class Bomb(pygame.sprite.Sprite):
        def __init__(self,sprite1):
            super().__init__()
            #导入所有动画的图片
            self.images=[pygame.image.load(f"./source/bomb/bomb-{bomb_index}.png") for bomb_index in range(1,8)]
            self.sprite1=sprite1
            self.interval = 5 # 播放每一张图片的间隔 5帧
            self.interval_index = 0 #帧数计数器 初始值为0
            self.image_index=0#图片索引 初始值为0
            self.image = self.images[self.image_index]
            self.rect = self.image.get_rect()
            self.rect.x = self.sprite1.rect.x
            self.rect.y = self.sprite1.rect.y
    
        def update(self, *args, **kwargs):
            self.interval_index+=1#每一帧进入update()函数,帧计数器加1
            #当计数器到达设置值时,切换图片
            if self.interval_index>=self.interval:
                self.image=self.images[self.image_index]
               #帧计数器归零
                self.interval_index=0
                #切换图片
                self.image_index+=1
            #当所有图片都播放完毕之后杀死此精灵对象
            if self.image_index==len(self.images):
                self.kill()
    #菜单类,显示控制游戏的暂停、恢复游戏、重新开始游戏
    class Menu(GameSprite):
        def __init__(self,image_url):
            super().__init__(image_url)
    
        def update(self, *args, **kwargs):
            pass
    #显示游戏相关信息类,可以显示游戏中得分、英雄生命值等
    class Show(pygame.sprite.Sprite):
        def __init__(self,name,var):
            super().__init__()
            pygame.font.init()
            font1 = pygame.font.SysFont('华文宋体', 25)  # 加载系统自带字体
            text = f"{name}:{var}"  # 编辑文本
            text = font1.render(text, True, (255, 255, 0))  # 渲染字体,(字符串,抗锯齿,字体颜色,背景颜色)
            self.image=text
            self.rect=self.image.get_rect()
    
    

    5.资源下载

    链接:资源
    提取码:9mje

    6.游戏效果

    作者:ouyang_ouba

    物联沃分享整理
    物联沃-IOTWORD物联网 » pygame飞机大战

    发表回复