首页 > 其他分享 >FileNotFoundError: No file './飞机大战/res/images/background.png' found in working....

FileNotFoundError: No file './飞机大战/res/images/background.png' found in working....

时间:2022-11-24 14:12:10浏览次数:45  
标签:group working No self def score pygame background rect

问题

某飞机大战代码弄好之后在VSCode中运行不报错,但是Pyinstaller打包之后报错

解决

FileNotFoundError: No file './飞机大战/res/images/background.png' found in working directory....
把路径改为绝对路径

后续

上面这个问题解决之后后面ttc字体文件和音乐文件也会有同样的错误,按照上面来修改即可

代码

game.py

import pygame
import random
from game_hud import *
from game_music import *
from game_items import *

class Game(object):
    """游戏类"""
    
    def __init__(self):
        # 游戏主窗口
        self.main_window = pygame.display.set_mode(SCREEN_RECT.size)
        pygame.display.set_caption("飞机大战")
        # 游戏状态属性
        self.is_game_over = False            # 游戏结束标记
        self.is_pause = False           # 游戏暂停标记

        # 精灵组属性
        self.all_group = pygame.sprite.Group()          # 所有精灵组
        self.enemies_group = pygame.sprite.Group()          # 敌机精灵组
        self.supplies_group = pygame.sprite.Group()         # 道具精灵组

        # 创建精灵
        # 背景精灵,交替滚动
        self.all_group.add(Background(False),Background(True))


        # 指示器面板
        self.hud_panel = HudPanel(self.all_group)

        # 创建敌机
        self.create_enemies()

        # 英雄精灵,静止不动
        self.hero = Hero(self.all_group)
        # 设置面板中炸弹的数量
        self.hud_panel.show_bomb(self.hero.bomb_count)

        # 创建道具
        self.create_supplies()

        # 创建音乐播放器
        self.player = MusicPlayer("game_music.ogg")
        self.player.play_music()

        # # TODO: 将所有敌机的速度设置为0,并修改敌机的初始位置
        # for enemy in self.enemies_group.sprites():
        #     enemy.speed = 0
        #     enemy.rect.y += 400
        # self.hero.speed = 1
        # self.hero = Plane(1000,5,0,"me_down.wav",
        #                     ["me%d.png" % i for i in range(1,3)],
        #                     "me1.png",
        #                     ["me_destroy_%d.png" % i for i in range(1,5)],self.all_group)
        # self.hero.rect.center = SCREEN_RECT.center              # 显示在屏幕中央
        # hero = GameSprite("me1.png",0,self.all_group)
        # hero = Plane(["me%d.png" % i for i in range(1,3)],self.all_group)
        # hero.rect.center = SCREEN_RECT.center           # 显示在屏幕中央

        

    def create_enemies(self):
        """根据游戏级别创建不同数量的敌机"""
        # 敌机精灵组中的精灵数量
        count = len(self.enemies_group.sprites())
        # 要添加到的精灵组
        groups = (self.all_group,self.enemies_group)
        # 判断游戏级别及已有的敌机数量
        if self.hud_panel.level == 1 and count == 0:        # 关卡1
            for i in range(16):
                Enemy(0,3,*groups)
        elif self.hud_panel.level == 2 and count == 16:         # 关卡2
            # 1> 增加敌机的最大速度
            for enemy in self.enemies_group.sprites():
                enemy.max_speed = 5
            # 2> 创建敌机
            for i in range(8):
                Enemy(0,5,*groups)
            for i in range(2):
                Enemy(1,1,*groups)
        elif self.hud_panel.level == 3 and count == 26:     # 关卡3
            # 1> 增加敌机的最大速度
            for enemy in self.enemies_group.sprites():
                enemy.max_speed = 7 if enemy.kind == 0 else 3
            # 2> 创建敌机
            for i in range(8):
                Enemy(0,7,*groups)
            for i in range(2):
                Enemy(1,3,*groups)
            for i in range(2):
                Enemy(2,1,*groups)



    def reset_game(self):
        """重置游戏"""
        self.is_game_over = False           # 游戏结束标记
        self.is_pause = False           # 游戏暂停标记
        self.hud_panel.reset_panel()        # 重置指示器面板

        # 设置英雄飞机初始位置
        self.hero.rect.midbottom = HERO_DEFAULT_MID_BOTTOM

        # 清空所有敌机
        for enemy in self.enemies_group:
            enemy.kill()
        # 清空残留子弹
        for bullet in self.hero.bullets_group:
            bullet.kill()
        # 重新创建敌机
        self.create_enemies()
        
    def event_handler(self):
        """事件监听
        :return: 如果监听到退出事件,返回True,否则返回False
        """
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                return True
            elif event.type == pygame.KEYDOWN and event.key == pygame.K_ESCAPE:
                return True
            elif event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
                if self.is_game_over:   # 游戏已经结束
                    self.reset_game()   # 重新开始游戏
                else:
                    self.is_pause = not self.is_pause       # 切换暂停状态

                    self.player.pause_music(self.is_pause)

            # 判断是否正在游戏
            if not self.is_game_over and not self.is_pause:
                # 监听关闭子弹增强
                if event.type == BULLET_ENHANCED_OFF_EVENT:
                    self.hero.bullets_kind = 0
                    pygame.time.set_timer(BULLET_ENHANCED_OFF_EVENT,0)
                # 监听投放道具事件
                if event.type == THROW_SUPPLY_EVENT:
                    self.player.play_sound("supply.wav")
                    supply = random.choice(self.supplies_group.sprites())
                    supply.throw_supply()

                # 监听子弹发射事件
                if event.type == HERO_FIRE_EVENT:
                    self.player.play_sound("bullet.wav")
                    self.hero.fire(self.all_group)
                # 监听取消英雄飞机无敌的事件
                if event.type == HERO_POWER_OFF_EVENT:
                    print("取消无敌状态")
                    # 设置英雄飞机状态
                    self.hero.is_power = False
                    # 取消定时器
                    pygame.time.set_timer(HERO_POWER_OFF_EVENT,0)


                # 监听英雄飞机牺牲事件
                if event.type == HERO_DEAD_EVENT:
                    print("英雄牺牲了...")
                    # 生命计数-1
                    self.hud_panel.lives_count -= 1
                    # 更新生命计数显示
                    self.hud_panel.show_lives()
                    # 更新炸弹显示
                    self.hud_panel.show_bomb(self.hero.bomb_count)
            # 监听玩家按下字母 b,引爆炸弹
                if event.type == pygame.KEYDOWN and event.key == pygame.K_b:
                    # # TODO 测试炸弹数量变化(# TODO 表示待完成提醒,在vscode里可以查询待做任务)
                    # self.hud_panel.show_bomb(random.randint(0,100))
                    # # TODO 测试生命计数数量变化
                    # self.hud_panel.lives_count = random.randint(0,10)
                    # self.hud_panel.show_lives()
                    # # TODO 测试停止游戏后是否可以重新开始游戏
                    # # self.hud_panel.lives_count = 0
                    # # TODO 测试炸毁所有敌机
                    # for enemy in self.enemies_group.sprites():
                    #     enemy.hp = 0
                    # 引爆炸弹
                    if self.hero.hp > 0 and self.hero.bomb_count > 0:
                        self.player.play_sound("use_bomb.wav")
                    score = self.hero.blowup(self.enemies_group)
                    # 更新炸弹数量显示
                    self.hud_panel.show_bomb(self.hero.bomb_count)
                    # 更新游戏得分,如果游戏等级提升,创建新的敌机
                    if self.hud_panel.increase_score(score):
                        self.create_enemies()
        return False

    def start(self):
        """开始游戏"""
        clock = pygame.time.Clock()         # 游戏时钟
        frame_counter = 0                   # 逐帧动画计数器
        while True:                         # 开始游戏循环
            # 生命计数等于 0,表示游戏结束
            self.is_game_over = self.hud_panel.lives_count == 0
            if self.event_handler():            # 事件监听
                self.hud_panel.save_best_score()
                return
            # 判断游戏状态
            if self.is_game_over:
                # print("游戏已经结束,按空格键重新开始...")
                self.hud_panel.panel_pause(True,self.all_group)
            elif self.is_pause:
                # print("游戏已经暂停,按空格键继续...")
                self.hud_panel.panel_pause(False,self.all_group)
            else:
                # print("游戏进行中...")
                self.hud_panel.panel_resume(self.all_group)
                # 碰撞检测
                self.check_collide()
                # # TODO 测试修改游戏得分
                # if self.hud_panel.increase_score(100):
                #     print("升级到 %d" % self.hud_panel.level)
                #     self.create_enemies()
                # TODO 模拟英雄飞机受到伤害
                # self.hero.hp -= 30
                # 通过pygame里key模块的get_pressed()方法获得当前时刻的按键元组
                keys = pygame.key.get_pressed()
                # # 判断是否按下右边方向键
                # if keys[pygame.K_RIGHT]:
                #     self.hero.rect.x += 10
                # 水平移动基数
                move_hor = keys[pygame.K_RIGHT] - keys[pygame.K_LEFT]
                # 垂直移动基数
                move_ver = keys[pygame.K_DOWN] - keys[pygame.K_UP]
                # 修改逐帧动画计数器
                frame_counter = (frame_counter + 1) % FRAME_INTERVAL
                # 更新 all_group.update(),更新所有精灵
                self.all_group.update(frame_counter == 0,move_hor,move_ver)
            # 绘制 all_group 中所有的精灵
            self.all_group.draw(self.main_window)
            pygame.display.update()         # 更新显示
            clock.tick(60)              # 设置刷新频率
    
    def check_collide(self):
        """碰撞检测"""
        # 检测英雄飞机和敌机的碰撞
        if not self.hero.is_power:
            enemies = pygame.sprite.spritecollide(self.hero,
                                                self.enemies_group,
                                                False,
                                                pygame.sprite.collide_mask)
            # 过滤掉已经被摧毁的敌机
            enemies = list(filter(lambda x: x.hp > 0,enemies))
            # 是否撞到敌机
            if enemies:
                self.player.play_sound(self.hero.wav_name)
                self.hero.hp = 0            # 英雄飞机被撞毁
            for enemy in enemies:
                enemy.hp = 0            # 摧毁发生碰撞的敌机

        # 检测被子弹击中
        hit_enemies = pygame.sprite.groupcollide(self.enemies_group,
                                                self.hero.bullets_group,
                                                False,
                                                False,
                                                pygame.sprite.collide_mask)

        # 遍历字典
        for enemy in hit_enemies:
            # 已经被摧毁的敌机不需要浪费子弹
            if enemy.hp <= 0:
                continue
            # 遍历击中敌机的子弹列表
            for bullet in hit_enemies[enemy]:
                # 将子弹从所有精灵组中移除
                bullet.kill()
                # 修改敌机的生命值
                enemy.hp -= bullet.damage
                # 如果敌机没有被摧毁继续下一颗子弹
                if enemy.hp > 0:
                    continue
                # 修改游戏得分并判断是否升级
                if self.hud_panel.increase_score(enemy.value):
                    self.player.play_sound("upgrade.wav")
                    self.create_enemies()
                self.player.play_sound(enemy.wav_name)
                # 退出遍历循环
                break
        # 英雄拾取道具
        supplies = pygame.sprite.spritecollide(self.hero,self.supplies_group,False,pygame.sprite.collide_mask)
        
        if supplies:
            supply = supplies[0]
            self.player.play_sound(supply.wav_name)
            # 将道具设置到游戏窗口下方
            supply.rect.y = SCREEN_RECT.h
            # 判断道具类型
            if supply.kind == 0:
                self.hero.bomb_count += 1
                self.hud_panel.show_bomb(self.hero.bomb_count)
            else:
                self.hero.bullets_kind = 1
                # 设置关闭子弹增强的定时器事件
                pygame.time.set_timer(BULLET_ENHANCED_OFF_EVENT,20000)
    def create_supplies(self):
        """创建道具"""
        Supply(0,self.supplies_group,self.all_group)
        Supply(1,self.supplies_group,self.all_group)
        # 设置30s投放道具定时器事件
        pygame.time.set_timer(THROW_SUPPLY_EVENT,30000)

if __name__ == "__main__":
    pygame.init()               # 初始化pygame
    Game().start()              # 通过Game()创建对象并调用start方法开始游戏
    pygame.quit()               # 退出pygame

game_items.py

import pygame
import random

# 全局常用定义
SCREEN_RECT = pygame.Rect(0,0,480,700)          # 游戏窗口区域
FRAME_INTERVAL = 10             # 逐帧动画间隔帧数

HERO_BOMB_COUNT = 3             # 英雄默认炸弹数量
# 英雄默认初始位置
HERO_DEFAULT_MID_BOTTOM = (SCREEN_RECT.centerx,SCREEN_RECT.bottom - 90)

HERO_DEAD_EVENT = pygame.USEREVENT
HERO_POWER_OFF_EVENT = pygame.USEREVENT + 1
HERO_FIRE_EVENT = pygame.USEREVENT + 2

THROW_SUPPLY_EVENT = pygame.USEREVENT + 3
BULLET_ENHANCED_OFF_EVENT = pygame.USEREVENT + 4

class GameSprite(pygame.sprite.Sprite):
    """游戏精灵类"""
    res_path = "D:/intelligent-data-analysis/飞机大战/res/images/"      # 图片资源路径
    def __init__(self,image_name,speed,*groups):
        """构造方法
        :param image_name: 要加载的图片文件名
        :param speed: 移动速度,0 表示禁止
        :param groups: 要添加到的精灵组,不传则不添加
        """
        # 调用父类方法实现精灵的创建
        super().__init__(*groups)
        self.image = pygame.image.load(self.res_path + image_name)      # 图像
        self.rect = self.image.get_rect()           # 矩形区域,默认在左上角
        self.speed = speed              # 移动速度
        # 图像遮罩,可以提高碰撞检测的执行性能
        self.mask = pygame.mask.from_surface(self.image)

    def update(self, *args):
        """更新精灵位置,默认在垂直方向移动"""
        self.rect.y += self.speed           # 改变y值实现垂直移动

class Background(GameSprite):
    """背景精灵类"""
    def __init__(self, is_alt,*groups):
        # 调用父类方法实现精灵的创建
        super().__init__("background.png",1,*groups)
        # 判断是否是另1个精灵,如果是,需要设置初始位置
        if is_alt:
            self.rect.y = -self.rect.h          # 设置到游戏窗口正上方
    
    def update(self, *args):
        # 调用父类的方法实现向下运动
        super().update(*args)           # 向下运动
        # 判断是否移出游戏窗口,如果移出屏幕,将图像设置到屏幕的上方
        if self.rect.y >= self.rect.h:
            self.rect.y = -self.rect.h

class StatusButton(GameSprite):
    """状态按钮类"""
    def __init__(self,image_names,*groups):
        """构造方法
        :param image_names: 要加载的图像名称列表
        :param groups: 要添加到的精灵组
        """
        # 调用父类方法实现精灵的创建
        super().__init__(image_names[0],0,*groups)
        # 加载图像
        self.images = [pygame.image.load(self.res_path + name) for name in image_names]

    def switch_status(self,is_pause):
        """切换状态
        :param is_pause: 是否暂停
        """
        self.image = self.images[1 if is_pause else 0]

class Label(pygame.sprite.Sprite):
    """文本标签精灵"""
    font_path = "D:/intelligent-data-analysis/飞机大战/res/font/MarkerFelt.ttc"     # 字体文件路径

    def __init__(self,text,size,color,*groups):
        """初始化方法
        :param text: 文本内容
        :param size: 字体大小
        :param color: 字体颜色
        :param groups: 要添加到的精灵组
        """
        #调用父类方法实现精灵的创建
        super().__init__(*groups)

        self.font = pygame.font.Font(self.font_path,size)
        self.color = color
        self.image = self.font.render(text,True,self.color)
        self.rect = self.image.get_rect()

    def set_text(self,text):
        """设置文本,使用指定的文本重新渲染 image,并且更新 rect
        :param text: 文本内容
        """
        self.image = self.font.render(text,True,self.color)
        self.rect = self.image.get_rect()

class Plane(GameSprite):
    """飞机类"""
    def __init__(self,hp,speed,value,wav_name,
                normal_names,hurt_name,destroy_names,*groups):
        """初始化方法
        :param hp: 生命值
        :param speed: 速度
        :param value: 得分
        :param wav_name: 音频文件名
        :param normal_names: 正常飞行图像名称列表
        :param hurt_name: 受伤图像文件名
        :param destroy_names: 被摧毁图像文件名
        :param groups: 要添加到的精灵组
        """
        super().__init__(normal_names[0],speed,*groups)
        # 飞机属性
        self.hp = hp
        self.max_hp = hp
        self.value = value
        self.wav_name = wav_name
        # 图像属性
        # 正常图像列表及索引
        self.normal_images = [pygame.image.load(self.res_path + name) for name in normal_names]
        self.normal_index = 0
        # 受伤图像
        self.hurt_image = pygame.image.load(self.res_path + hurt_name)
        # 被摧毁图像列表及索引
        self.destroy_images = [pygame.image.load(self.res_path + name) for name in destroy_names]
        self.destroy_index = 0

    def reset_plane(self):
        """重置飞机"""
        self.hp = self.max_hp           # 生命值
        self.normal_index = 0           # 正常状态图像索引
        self.destroy_index = 0          # 被摧毁状态图像索引
        self.image = self.normal_images[0]      # 恢复正常图像

        

    def update(self,*args):     
        # 如果第 0 个参数为 False,不需要更新图像,直接返回
        if not args[0]:
            return
        # 判断飞机状态
        if self.hp == self.max_hp:          # 未受伤
            self.image = self.normal_images[self.normal_index]
            count = len(self.normal_images)
            self.normal_index = (self.normal_index + 1) % count
        elif self.hp > 0:                   # 受伤
            self.image = self.hurt_image
        else:
            # 判断是否显示到最后一张图像,如果是说明飞机完全被摧毁
            if self.destroy_index < len(self.destroy_images):
                self.image = self.destroy_images[self.destroy_index]
                self.destroy_index += 1
            else:
                self.reset_plane()

        # # 设置图像
        # self.image = self.normal_images[self.normal_index]
        # # 更新索引
        # count = len(self.normal_images)
        # self.normal_index = (self.normal_index + 1) % count

class Enemy(Plane):
    """敌机类"""
    def __init__(self,kind,max_speed,*groups):
        """敌机类"""
        # 记录敌机类型和最大速度
        self.kind = kind
        self.max_speed = max_speed
        # 根据类型调用父类方法传递不同参数
        if kind == 0:
            super().__init__(1,1,1000,"enemy1_down.wav",
                            ["enemy1.png"],
                            "enemy1.png",
                            ["enemy1_down%d.png" % i for i in range(1,5)],
                            *groups)
        elif kind == 1:
            super().__init__(6,1,6000,"enemy2_down.wav",
                            ["enemy2.png"],
                            "enemy2_hit.png",
                            ["enemy2_down%d.png" % i for i in range(1,5)],
                            *groups)
        else:
            super().__init__(15,1,15000,"enemy3_down.wav",
                            ["enemy3_n1.png","enemy3_n2.png"],
                            "enemy3_hit.png",
                            ["enemy3_down%d.png" % i for i in range(1,7)],
                            *groups)
        # 调用重置飞机方法,设置敌机初始位置和速度
        self.reset_plane()

    def reset_plane(self):
        """重置飞机"""
        super().reset_plane()
        # 设置初始随机位置和速度
        x = random.randint(0,SCREEN_RECT.w - self.rect.w)           # 设置随机x值
        y = random.randint(0,SCREEN_RECT.h - self.rect.h) - SCREEN_RECT.h       # 设置随机y值
        # y = random.randint(0,SCREEN_RECT.h - self.rect.h)
        self.rect.topleft = (x,y)
        self.speed = random.randint(1,self.max_speed)

    def update(self,*args):
        """更新图像和位置"""
        # 调用父类方法更新飞机图像 - 注意 args 需要拆包
        super().update(*args)
        # 判断敌机是否被摧毁,否则使用速度更新飞机位置
        if self.hp > 0:
            self.rect.y += self.speed
        # 判断是否飞出屏幕,如果是,重置飞机
        if self.rect.y >= SCREEN_RECT.h:
            self.reset_plane()

class Hero(Plane):
    """英雄类"""

    def __init__(self,*groups):
        """初始化方法
        :param groups: 要添加到的精灵组
        """
        super().__init__(1000,5,0,"me_down.wav",
                        ["me%d.png" % i for i in range(1,3)],
                        "me1.png",
                        ["me_destroy_%d.png" % i for i in range(1,5)],
                        *groups)
        self.is_power = False               # 无敌标记
        self.bomb_count = HERO_BOMB_COUNT               # 炸yao数量
        self.bullets_kind = 0               # 子弹类型
        self.bullets_group = pygame.sprite.Group()          # 子弹精灵组
        # 初始位置
        self.rect.midbottom = HERO_DEFAULT_MID_BOTTOM
        # 设置0.2秒发射子弹定时器事件
        pygame.time.set_timer(HERO_FIRE_EVENT,200)

    def update(self, *args):
        """更新英雄的图像及矩形区域
        :param args: 0 更新图像标记 1 水平移动基数 2 垂直移动基数
        """
        # 调用父类方法更新飞机图像 - 注意 args 需要拆包
        super().update(*args)
        # 如果没有传递方向基数或者英雄被撞毁,直接返回
        if len(args) != 3 or self.hp <= 0:
            return
        # 调整水平移动距离
        self.rect.x += args[1] * self.speed
        self.rect.y += args[2] * self.speed
        # 限定在游戏窗口内部移动
        self.rect.x = 0 if self.rect.x < 0 else self.rect.x
        if self.rect.right > SCREEN_RECT.right:
            self.rect.right = SCREEN_RECT.right
        self.rect.y = 0 if self.rect.y < 0 else self.rect.y
        if self.rect.bottom > SCREEN_RECT.bottom:
            self.rect.bottom = SCREEN_RECT.bottom

    def blowup(self,enemies_group):
        """引爆炸弹
        :param enemies_group: 敌机精灵组
        :return: 累计得分
        """
        # 如果没有足够数量的炸弹或者英雄被撞毁,直接返回
        if self.bomb_count <= 0 or self.hp <= 0:
            return 0
        self.bomb_count -= 1                # 炸弹数量 - 1
        score = 0                   # 本次得分
        count = 0                   # 炸毁数量
        # 遍历敌机精灵组,将游戏窗口内的敌机引爆
        for enemy in enemies_group.sprites():
            # 判断敌机是否进入游戏窗口
            if enemy.rect.bottom > 0:
                score += enemy.value            # 计算得分
                count += 1                      # 累计数量
                enemy.hp = 0                     # 摧毁敌机
        print("炸毁了 %d 架敌机,得分 %d" % (count,score))
        return score

    def reset_plane(self):
        """重置英雄"""
        # 调用父类方法重置图像相关信息
        super().reset_plane()
        self.is_power = True
        self.bomb_count = HERO_BOMB_COUNT
        self.bullets_kind = 0
        # 发布英雄牺牲事件
        pygame.event.post(pygame.event.Event(HERO_DEAD_EVENT))
        # 三秒无敌
        pygame.time.set_timer(HERO_POWER_OFF_EVENT,3000)

    def fire(self,display_group):
        """发射子弹
        :param  display_group:要添加的显示精灵组
        """
        # 需要将子弹精灵添加倒两个精灵组
        groups = (self.bullets_group,display_group)
        # 测试子弹增强效果
        # self.bullets_kind = 1

        for i in range(3):
            # 创建子弹精灵
            bullet1 = Bullet(self.bullets_kind,*groups)
            # 计算子弹的垂直位置
            y = self.rect.y - i * 15
            # 判断子弹类型
            if self.bullets_kind == 0:
                bullet1.rect.midbottom = (self.rect.centerx,y)
            else:
                bullet1.rect.midbottom = (self.rect.centerx - 20,y)
                # 再创建一颗子弹
                bullet2 = Bullet(self.bullets_kind,*groups)
                bullet2.rect.midbottom = (self.rect.centerx + 20,y)

class Bullet(GameSprite):
    """子弹类"""
    def __init__(self,kind,*groups):
        """初始化方法
        :param kind: 子弹类型
        :param groups: 要添加到的精灵组
        """
        image_name = "bullet1.png" if kind == 0 else "bullet2.png"
        super().__init__(image_name,-12,*groups)
        self.damage = 1
    
    def update(self, *args):
        super().update(*args)
        # 判断上方是否飞出窗口
        if self.rect.bottom < 0:
            self.kill()

class Supply(GameSprite):
    """道具类"""
    def __init__(self,kind,*groups):
        """初始化方法
        :param groups: 要添加到的精灵组
        :param kind: 道具类型
        """

        # 调用父类方法
        image_name = "%s_supply.png" % ("bomb" if kind == 0 else "bullet")
        super().__init__(image_name,5,*groups)
        # 道具类型
        self.kind = kind
        # 音频文件名
        self.wav_name = "get_%s.wav" % ("bomb" if kind == 0 else "bullet")
        # 初始位置
        self.rect.y = SCREEN_RECT.h
    
    def throw_supply(self):
        """投放道具"""
        self.rect.bottom = 0
        self.rect.x = random.randint(0,SCREEN_RECT.w - self.rect.w)
    def update(self, *args):
        """更新位置,在屏幕下方移动"""
        if self.rect.h > SCREEN_RECT.h:
            return
        # 调用父类方法,沿垂直方向移动位置
        super().update(*args)
        

game_hud.py

import pygame
from game_items import *

class HudPanel(object):
    """指示器面板类"""
    margin = 10             # 精灵之间的间距
    white = (255,255,255)               # 白色
    gray = (64,64,64)               # 灰色

    # 设置奖励分值与等级分值
    reward_score = 100000               # 奖励分值
    level2_score = 10000                # 级别 2 分值
    level3_score = 50000                # 级别 3 分值

    record_filename = "record.txt"          # 最好成绩文件名

    def __init__(self,display_group):
        """初始化方法
        :param display_group: 面板中的精灵要被添加到的显示精灵组
        """
        # 游戏属性
        self.score = 0              # 游戏得分
        self.lives_count = 3        # 生命计数
        self.level = 1              # 游戏级别
        self.best_score = 0             # 最好成绩

        # 通过self指代对象本身来调用自身函数实现最好成绩加载
        self.load_best_score()

        # 创建图像精灵
        # 状态精灵
        self.status_sprite = StatusButton(("pause.png","resume.png"),display_group)
        self.status_sprite.rect.topleft = (self.margin,self.margin)

        # 炸弹精灵
        self.bomb_sprite = GameSprite("bomb.png",0,display_group)
        self.bomb_sprite.rect.x = self.margin
        self.bomb_sprite.rect.bottom = SCREEN_RECT.bottom - self.margin

        # 生命计数精灵
        self.lives_sprite = GameSprite("life.png",0,display_group)
        self.lives_sprite.rect.right = SCREEN_RECT.right - self.margin
        self.lives_sprite.rect.bottom = SCREEN_RECT.bottom - self.margin

        # 创建标签精灵
        # 分数标签
        self.score_label = Label("%d" % self.score, 32, self.gray, display_group)
        self.score_label.rect.midleft = (self.status_sprite.rect.right + self.margin,
                                        self.status_sprite.rect.centery)
        # 炸弹标签
        self.bomb_label = Label("X 3", 32, self.gray, display_group)
        self.bomb_label.rect.midleft = (self.bomb_sprite.rect.right + self.margin,
                                        self.bomb_sprite.rect.centery)

        # 生命计数标签
        self.lives_label = Label("X %d" % self.lives_count, 32, self.gray, display_group)
        self.lives_label.rect.midright = (SCREEN_RECT.right - self.margin,
                                        self.bomb_label.rect.centery)

        # 调整生命计数精灵位置
        self.lives_sprite.rect.right = self.lives_label.rect.left - self.margin

        # 最好成绩标签
        self.best_label = Label('Best: %d' % self.best_score, 36, self.white)

        # 状态标签
        self.status_label = Label('Game Over!', 48, self.white)

        # 提示标签
        self.tip_label = Label('Press spacebar to play again.', 22, self.white)

    def show_bomb(self,count):
        """显示炸弹数量
        :param count: 要显示的炸弹数量
        """
        # 设置炸弹标签的位置
        self.bomb_label.set_text("X %d" % count)

        # 设置炸弹标签位置
        self.bomb_label.rect.midleft = (self.bomb_sprite.rect.right + self.margin,
                                        self.bomb_sprite.rect.centery)

    def show_lives(self):
        """显示生命计数"""
        # 设置生命计数标签文字
        self.lives_label.set_text("X %d" % self.lives_count)

        # 设置生命计数标签位置
        self.lives_label.rect.midright = (SCREEN_RECT.right - self.margin,
                                            self.bomb_label.rect.centery)

        # 调整生命计数精灵位置
        self.lives_sprite.rect.right = self.lives_label.rect.left - self.margin

    def increase_score(self,enemy_score):
        """增加游戏得分
        :param enemy_score: 摧毁敌机的分值
        :return: 增加 enemy_score 后,游戏级别是否提升
        """
        # 游戏得分
        score = self.score + enemy_score
        # 判断是否奖励生命
        if score // self.reward_score != self.score // self.reward_score:
            self.lives_count += 1
            self.show_lives()
        self.score = score
        # 最好成绩
        self.best_score = score if score > self.best_score else self.best_score
        # 游戏级别
        if score < self.level2_score:
            level = 1
        elif score < self.level3_score:
            level = 2
        else:
            level = 3
        is_upgrade = level != self.level
        self.level = level
        # 修改得分标签内容和位置
        self.score_label.set_text("%d" % self.score)
        self.score_label.rect.midleft = (self.status_sprite.rect.right + self.margin,
                                            self.status_sprite.rect.centery)
        return is_upgrade

    def save_best_score(self):
        """将最好成绩写入 record.txt"""
        # 打开文件流
        file = open(self.record_filename,"w")
        # 写入分数
        file.write("%d" % self.best_score)
        # 关闭文件
        file.close()

    def load_best_score(self):
        """从 record.txt 加载最好成绩"""
        try:
            file = open(self.record_filename)           # 打开文件流
            txt = file.readline()               # 读取文件内容
            file.close()                # 关闭文件
            self.best_score = int(txt)          # 保存文件内容到实例属性best_score中
        except (FileNotFoundError,ValueError):
            print("文件不存在或者类型转换错误")

    def panel_pause(self,is_game_over,display_group):
        """面板暂停
        :param is_game_over: 是否因为游戏结束需要暂停
        :param display_group: 显示精灵组
        """
        # 判断是否已经添加了精灵,如果是直接返回
        if display_group.has(self.status_label,self.tip_label,self.best_label):
            return
        # 根据是否结束游戏决定要显示的文字
        text = "Game Over!" if is_game_over else "Game Paused!"
        tip = "Press spacebar to "
        tip += "play again." if is_game_over else "continue."
        # 设置标签文字
        self.best_label.set_text("Best: %d" % self.best_score)
        self.status_label.set_text(text)
        self.tip_label.set_text(tip)
        # 设置标签位置,将之前位置代码复制到此处
        self.best_label.rect.center = SCREEN_RECT.center
        best_rect = self.best_label.rect
        self.status_label.rect.midbottom = (best_rect.centerx,
                                            best_rect.y - 2 * self.margin)
        self.tip_label.rect.midtop = (best_rect.centerx,
                                        best_rect.bottom + 8 * self.margin)
        # 添加到精灵组
        display_group.add(self.best_label,self.status_label,self.tip_label)
        # 切换状态精灵状态
        self.status_sprite.switch_status(True)

    def panel_resume(self,display_group):
        """面板恢复
        :param display_group: 显示精灵组
        """
        # 从精灵组移除 3 个标签精灵
        display_group.remove(self.status_label,self.tip_label,self.best_label)
        # 切换状态精灵状态
        self.status_sprite.switch_status(False)

    def reset_panel(self):
        """重置面板"""
        # 游戏属性
        self.score = 0              # 游戏得分
        self.lives_count = 3            # 生命计数
        # 标签显示
        self.increase_score(0)          # 增加 0 分
        self.show_bomb(3)               # 炸弹数量
        self.show_lives()               # 生命计数标签

game_music.py

import os
import pygame

class MusicPlayer(object):
    """音乐播放器类"""
    res_path = "D:/intelligent-data-analysis/飞机大战/res/sound/"
    def __init__(self,music_file):
        """初始化方法"""
        # 加载背景音乐
        pygame.mixer.music.load(self.res_path + music_file)
        pygame.mixer.music.set_volume(0.5)
        
        self.sound_dict = {}

        files = os.listdir(self.res_path)

        for file_name in files:
            if file_name == music_file:
                continue

            sound = pygame.mixer.Sound(self.res_path + file_name)
            self.sound_dict[file_name] = sound

    @staticmethod
    def play_music():
        pygame.mixer.music.play(-1)
    
    @staticmethod
    def pause_music(is_pause):
        if is_pause:
            pygame.mixer.music.pause()
        else:
            pygame.mixer.music.unpause()    

    def play_sound(self,wav_name):
        self.sound_dict[wav_name].play()

标签:group,working,No,self,def,score,pygame,background,rect
From: https://www.cnblogs.com/beizhe/p/16921664.html

相关文章