问题
某飞机大战代码弄好之后在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