代码存在一些bug,感兴趣可自行修改,游戏运行后玩法与吃金币游戏类似。(代码及结果比较粗糙,仅供参考)
注:(图片、音乐、音效文件老是上传上传不上,想要可私,也可以自己找【自己找喜欢的图和音乐就行】)
1.运行效果图:
开始界面:
游戏中:
游戏结束:
2.完整代码:
import os.path
import pickle
import random
import time
import pygame
WIDTH, HEIGHT = 800, 600
FOOD_BORN = pygame.USEREVENT + 3000
PROTECT_BORN = pygame.USEREVENT + 100
BOMB_BORN = pygame.USEREVENT + 1200
TOTAL_TIME = 60
n = 1
# 背景音乐
class AudioManage:
@staticmethod
def play_bg_music():
pygame.mixer.music.load("./tu/1/bjm/ayd.mp3")
pygame.mixer.music.set_volume(0.2)
pygame.mixer.music.play(-1)
# 音效
@staticmethod
def play_sound(name):
sound = pygame.mixer.Sound(name)
sound.play()
# 引入精灵父类 所有子类都有image(外观)和rect(位置)
class BaseSprite(pygame.sprite.Sprite):
def __init__(self, image_name):
super().__init__()
self.image = pygame.image.load(image_name)
self.rect = self.image.get_rect()
# 炸弹精灵类
class BombSprite(BaseSprite):
def __init__(self, image_name, start_x, gm, speed=6):
super().__init__(image_name)
self.rect.bottom = 0
self.rect.left = start_x
self.speed = speed
self.gm = gm
# 炸弹移动及消亡
def update(self):
self.rect.top += self.speed
if self.rect.top > HEIGHT:
self.kill()
# 炸弹管理类
class BombManage:
def __init__(self, gm):
self.gm = gm
self.bomb_group = pygame.sprite.Group()
# 炸弹生成
def born(self):
for center in range(n):
center = random.randint(0, WIDTH - 100)
self.bomb = BombSprite("./tu/1/xwz/11.png", center, self.gm)
self.bomb.add(self.bomb_group)
# 炸弹清空
def clear(self):
self.bomb_group.empty()
# 更新
def update(self):
self.bomb_group.draw(self.gm.screen)
self.bomb_group.update()
# 食物精灵类
class FoodSprite(BaseSprite):
def __init__(self, image_name, start_x, gm, speed=6):
super().__init__(image_name)
self.rect.bottom = 0
self.rect.left = start_x
self.speed = speed
self.gm = gm
# 食物移动
def update(self):
self.rect.top += self.speed
if self.rect.top > HEIGHT:
self.kill()
# 食物管理类
class FoodManage:
def __init__(self, gm):
self.gm = gm
self.food_group = pygame.sprite.Group()
# 食物随机生成
def born(self):
image_name = random.choice(
["./tu/1/xwz/2.png", "./tu/1/xwz/3.png", "./tu/1/xwz/4.png"])
start_x = random.randint(0, WIDTH - 100)
self.food = FoodSprite(image_name, start_x, self.gm)
self.food.add(self.food_group)
# 食物清空
def clear(self):
self.food_group.empty()
# 更新
def update(self):
self.food_group.draw(self.gm.screen)
self.food_group.update()
# 护盾精灵类(保护玩家, 生成保护罩)
class ShieldSprite(BaseSprite):
def __init__(self, image_name):
super().__init__(image_name)
# 保护罩精灵类(生成护盾的食物类)
class ProtectSprite(BaseSprite):
def __init__(self, image_name, gm, start_x, speed=7):
super().__init__(image_name)
self.rect.bottom = 0
self.rect.left = start_x
self.gm = gm
self.speed = speed
# 移动
def update(self):
self.rect.top += self.speed
if self.rect.top > HEIGHT:
self.kill()
# 保护罩管理类
class ProtectManage:
def __init__(self, gm):
self.gm = gm
self.protect_group = pygame.sprite.Group()
# 生成可产生护盾的食物
def born(self):
start_x = random.randint(0, WIDTH - 100)
self.protect = ProtectSprite("./tu/1/xwz/5.png", self.gm, start_x)
self.protect.add(self.protect_group)
# 清空
def clear(self):
self.protect_group.empty()
# 更新
def update(self):
self.protect_group.draw(self.gm.screen)
self.protect_group.update()
# 玩家精灵类
class PlayerSprite(BaseSprite):
def __init__(self, player_names, speed=12):
super().__init__(player_names[0])
self.rect.center = (WIDTH / 2, HEIGHT - 50)
self.current_index = 0
self.images = [pygame.image.load(player_image) for player_image in player_names]
self.speed = speed
self.shield = None
# 玩家移动
def update(self):
# gif图片速度控制
self.current_index += 1
if self.current_index >= len(self.images) * 5:
self.current_index = 0
self.image = self.images[self.current_index // 5]
key_pressed = pygame.key.get_pressed()
# 左移
if key_pressed[pygame.K_LEFT] or key_pressed[pygame.K_a]:
self.rect.left -= self.speed
if self.rect.left < 0:
self.rect.left = 0
# 右移
elif key_pressed[pygame.K_RIGHT] or key_pressed[pygame.K_d]:
self.rect.right += self.speed
if self.rect.right > WIDTH:
self.rect.right = WIDTH
# 上移
elif key_pressed[pygame.K_UP] or key_pressed[pygame.K_w]:
self.rect.top -= self.speed
if self.rect.top < 0:
self.rect.top = 0
# 下移
elif key_pressed[pygame.K_DOWN] or key_pressed[pygame.K_s]:
self.rect.bottom += self.speed
if self.rect.bottom > HEIGHT:
self.rect.bottom = HEIGHT
# 保护罩跟随玩家移动(更新中心坐标)
if self.shield:
self.shield.rect.center = self.rect.center
# 玩家管理类
class PlayerManage:
def __init__(self, gm):
self.gm = gm
self.player_group = pygame.sprite.Group()
self.shield_group = pygame.sprite.Group()
# 保护罩
def create_shield(self):
# 玩家没有保护罩则生成
if not self.player.shield:
# 创建保护罩精灵
shield = ShieldSprite("./tu/1/xwz/10.png")
# 保护罩中心与玩家中心重合包裹住玩家
shield.rect.center = self.player.rect.center
# 将保护罩精灵添加到保护罩组
self.shield_group.add(shield)
# 关联玩家与保护罩精灵
self.player.shield = shield
# 玩家有护盾则不再生成
def clear_shield(self):
# 玩家有保护罩
if self.player.shield:
# 将保护罩精灵移除保护罩精灵族
self.shield_group.remove(self.player.shield)
# 保护罩破碎
self.player.shield.kill()
self.player.shield = None
# 清空
def clear(self):
self.shield_group.empty()
# 玩家生成
def born(self):
self.player = PlayerSprite([f"./tu/1/gif1/{i}.png" for i in range(1, 10)])
# self.player = PlayerSprite("./tu/1/xwz/1.png")
self.player.add(self.player_group)
# 玩家死亡清空
def die(self):
self.player_group.empty()
# 玩家及保护罩更新
def update(self):
# 玩家
self.player_group.draw(self.gm.screen)
self.player_group.update()
# 保护罩
self.shield_group.draw(self.gm.screen)
self.shield_group.update()
# 背景精灵类
class BgSprite(BaseSprite):
def __init__(self, image_name, start_y, speed=5):
super().__init__(image_name)
self.rect.top = start_y
self.speed = speed
# 背景移动
def update(self):
self.rect.top += self.speed
if self.rect.top >= HEIGHT:
self.rect.top = -HEIGHT
# GIF图片精灵类
class GIFSprite(BaseSprite):
def __init__(self, bg_images):
super().__init__(bg_images[0])
self.bg_images = [pygame.image.load(bg_image) for bg_image in bg_images]
self.current_index = 0
# 图片改变规则,生成动态图
def update(self):
self.current_index += 1
if self.current_index == len(self.bg_images * 25):
self.current_index = 0
self.image = self.bg_images[self.current_index // 25]
# 背景管理类
class BgManage:
def __init__(self, gm):
self.gm = gm
# 游戏开始背景图(gif图片)
self.ready_group = pygame.sprite.Group()
# self.bg0 = GIFSprite([f"./tu/1/gif/{i}.jpg" for i in range(1, 32)])
self.bg0 = GIFSprite([f"./tu/1/gif3/{i}.jpg" for i in range(1, 3)])
self.bg0.add(self.ready_group)
self.gaming_group = pygame.sprite.Group()
# 游戏中背景图(滚动)
# self.bg1 = BgSprite("./tu/1/xwz/3.jpg", 0, 5)
# self.bg1.add(self.gaming_group)
# self.bg2 = BgSprite("./tu/1/xwz/4.jpg", -HEIGHT, 5)
# self.bg2.add(self.gaming_group)
# gif背景图
self.bg1 = GIFSprite([f"./tu/1/gif3/{i}.jpg" for i in range(3, 5)])
self.bg1.add(self.gaming_group)
# 游戏结束背景图(静态)
self.end_group = pygame.sprite.Group()
self.bg3 = BgSprite("./tu/1/xwz/30.jpg", 0, 0)
self.bg3.add(self.end_group)
# 背景音乐播放
AudioManage.play_bg_music()
# 绘制并更新
def update(self):
# 游戏开始准备阶段
if self.gm.game_state == "ready":
# 绘制并更新准备阶段元素
self.ready_group.draw(self.gm.screen)
self.ready_group.update()
# 游戏开始阶段
elif self.gm.game_state == "gaming":
# 绘制并更新游戏中的游戏元素
self.gaming_group.draw(self.gm.screen)
self.gaming_group.update()
# 游戏结束阶段
elif self.gm.game_state == "end":
# 绘制并更新结束阶段游戏元素
self.end_group.draw(self.gm.screen)
self.end_group.update()
# UI精灵类
class UISprite(BaseSprite):
def __init__(self, image_name, center):
super().__init__(image_name)
self.rect.center = center
# 鼠标点击检测
def is_collide(self):
# 获取当前鼠标位置
mouse_pos = pygame.mouse.get_pos()
# 检测鼠标位置是否与对象的矩形区域发生碰撞
if self.rect.collidepoint(mouse_pos):
# 如果发生碰撞 返回True
return True
# UI管理类
class UIManage:
def __init__(self, gm):
self.gm = gm
# 准备阶段UI元素初始化(游戏开始界面开始按钮图片)
self.ready_group = pygame.sprite.Group()
self.start_btn = UISprite("./tu/1/xwz/7.png", (WIDTH / 2, HEIGHT - 50))
self.start_btn.add(self.ready_group)
self.title_btn = UISprite("./tu/1/xwz/12.png", (WIDTH / 2, HEIGHT - 500))
self.title_btn.add(self.ready_group)
# 分数显示初始化(定义初始值为0、字体、字号、颜色)
self.score_value = 0
self.font = pygame.font.Font("./tu/1/字体/2.ttf", size=32)
self.score_label = self.font.render(f"Score: {self.score_value}", True, "red")
# 时间显示初始化(定义时间、字体、字号、颜色)
self.total_time = TOTAL_TIME
self.timer = self.font.render(f"time:{self.total_time}", True, "gold")
# 结束阶段UI元素初始化(结束界面重新开始按钮图)
self.end_group = pygame.sprite.Group()
self.restart_btn = UISprite("./tu/1/xwz/9.png", (WIDTH / 2, HEIGHT - 100))
self.restart_btn.add(self.end_group)
# 初始化最高分
self.high_score = 0
# 序列化
def save_score(self, score):
"""
保存分数到文件并更新最高分
score:要保存的分数
如果给定的分数高于当前记录的最高分数,更新最高分数并保存到文件中。
"""
if score > self.high_score:
self.high_score = score
with open("./princeling.txt", "wb") as f:
pickle.dump(self.high_score, f)
# 反序列化
def load_score(self):
"""
加载之前保存的最高分数。
int: 加载的最高分数值,如果文件不存在则返回默认值0。
如果保存分数的文件存在,从文件中加载并返回最高分数值;否则返回默认值0。
"""
if os.path.exists("./princeling.txt"):
with open("./princeling.txt", "rb") as f:
return pickle.load(f)
# 增加分数并更新显示
def add_score(self):
# 将当前分数增加1并更新显示文本和保存最高分数
self.score_value += 1
self.score_label = self.font.render(f"Score: {self.score_value}", True, "gold")
self.save_score(self.score_value)
# 减少剩余时间并更新显示
def reduce_time(self):
# 如果时间大于0 时间减少1 更新显示文本
if self.total_time > 0:
self.total_time -= 1
self.timer = self.font.render(f"time:{self.total_time}", True, "gold")
# 重置游戏状态和显示
def reset_game(self):
# 将分数重置为0
self.score_value = 0
# 将时间重置为指定时间
self.total_time = TOTAL_TIME
# 更新显示文本
self.score_label = self.font.render(f"score:{self.score_value}", True, "gold")
self.time_label = self.font.render(f"time:{self.total_time}", True, "gold")
self.gm.player_manage.die()
self.gm.player_manage.clear()
self.gm.food_manage.clear()
self.gm.protec_manage.clear()
self.gm.bomb_manage.clear()
# 根据游戏状态更新屏幕内容(更新屏幕显示内容)
def update(self):
# 游戏准备阶段
if self.gm.game_state == "ready":
# 显示准备界面和开始按钮
self.ready_group.draw(self.gm.screen)
self.ready_group.update()
# 重置总时间
self.total_time = TOTAL_TIME
# 在开始按钮图片上显示start
# 显示字体、字号
self.font2 = pygame.font.Font("./tu/1/字体/2.ttf", size=40)
# 显示内容
self.start = self.font2.render("start", True, "gold")
# 显示位置、颜色
self.gm.screen.blit(self.start, (WIDTH / 2 - 50, HEIGHT - 100))
# 游戏进行阶段
elif self.gm.game_state == "gaming":
# 显示游戏进行中的计时器和分数
self.gm.screen.blit(self.timer, (WIDTH // 2 - 350, 30))
self.gm.screen.blit(self.score_label, (WIDTH - 150, 30))
# 游戏结束阶段
elif self.gm.game_state == "end":
# 游戏结束时间为0 显示victory
if self.total_time == 0:
self.font2 = pygame.font.Font("./tu/1/字体/2.ttf", size=52)
self.start = self.font2.render("victory", True, "gold")
self.gm.screen.blit(self.start, (WIDTH / 2 - 100, HEIGHT / 2))
# 游戏结束时间不为0 显示lose out
else:
self.font2 = pygame.font.Font("./tu/1/字体/2.ttf", size=52)
self.start = self.font2.render("lose out", True, "red")
self.gm.screen.blit(self.start, (WIDTH / 2 - 100, HEIGHT / 2))
# 显示最高分
self.high = self.font.render(f"hight score:{self.high_score}", True, "gold")
self.gm.screen.blit(self.high, (WIDTH / 2 - 100, HEIGHT - 600))
# 显示结束界面组件
self.end_group.draw(self.gm.screen)
self.end_group.update()
self.gm.screen.blit(self.score_label, (WIDTH / 2 - 65, HEIGHT - 200))
# 处理游戏中鼠标点击事件
def check_click(self):
# 游戏准备阶段
if self.gm.game_state == "ready":
# 点击了开始按钮
if self.start_btn.is_collide():
self.gm.game_state = "gaming"
# 设置炸弹出现计时器
pygame.time.set_timer(BOMB_BORN, 3000)
# 生成玩家
self.gm.player_manage.born()
# 设置食物出现计时器
pygame.time.set_timer(FOOD_BORN, 1000)
# 设置总时间计时器
pygame.time.set_timer(TOTAL_TIME, 1000)
# 设置保护罩出现计时器
pygame.time.set_timer(PROTECT_BORN, 5000)
# 游戏结束状态
elif self.gm.game_state == "end":
self.gm.player_manage.die()
self.gm.player_manage.die()
self.gm.food_manage.clear()
self.gm.protec_manage.clear()
self.gm.bomb_manage.clear()
# 点击重新开始按钮进入游戏准备阶段
if self.restart_btn.is_collide():
self.gm.game_state = "ready"
# 重置游戏状态
self.reset_game()
# 游戏管理类
class GameManage:
def __init__(self):
# 初始化模块
pygame.init()
# 设置窗口标题
pygame.display.set_caption("princeling")
# 创建窗体大小
self.screen = pygame.display.set_mode((WIDTH, HEIGHT))
# 创建时钟对象
self.clock = pygame.time.Clock()
# 初始化游戏状态为准备状态
self.game_state = "ready"
# 初始化各管理类对象
self.ui_manage = UIManage(self)
self.bg_manage = BgManage(self)
self.food_manage = FoodManage(self)
self.player_manage = PlayerManage(self)
self.bomb_manage = BombManage(self)
self.protec_manage = ProtectManage(self)
# 初始化保护罩生成的时间戳
self.protec_last_time = time.time()
# 检查和处理pygame事件
def check_event(self):
# 循环检查所有的pygame事件
for event in pygame.event.get():
# 检测到窗口关闭事件 调用pygame.quit() 关闭pygame 退出程序
if event.type == pygame.QUIT:
pygame.quit()
exit()
# 处理鼠标按钮释放事件
if event.type == pygame.MOUSEBUTTONUP:
# 左键释放
if event.button == 1:
# 调用UI管理器的点击检查方法
self.ui_manage.check_click()
# 处理总时间事件(假设 TOTAL_TIME 是自定义的事件类型)
if event.type == TOTAL_TIME:
# 调用 UI 管理器的减少时间方法
self.ui_manage.reduce_time()
# 如果总时间减少到0
if self.ui_manage.total_time == 0:
# 设置游戏状态为结束
self.game_state = "end"
# 调用玩家管理器的死亡方法
# 处理食物生成事件
if event.type == FOOD_BORN:
# 调用食物管理器的生成方法
self.food_manage.born()
# 处理炸弹生成事件
elif event.type == BOMB_BORN:
# 调用炸弹管理器的生成方法
self.bomb_manage.born()
# 处理保护生成事件
elif event.type == PROTECT_BORN:
# 调用保护管理器的生成方法
self.protec_manage.born()
def update_draw(self):
# 更新背景管理类
self.bg_manage.update()
# 更新ui管理类
self.ui_manage.update()
if self.game_state == "gaming":
# 更新食物管理类
self.food_manage.update()
# 更新炸弹管理类
self.bomb_manage.update()
# 更新保护罩管理类
self.protec_manage.update()
# 更新玩家管理类
self.player_manage.update()
# 更新ui管理类(使文字显示在最上层)
self.ui_manage.update()
# 更新绘制
pygame.display.flip()
def check_collide(self):
# 玩家与食物碰撞检测
r0 = pygame.sprite.groupcollide(self.player_manage.player_group, self.food_manage.food_group, False, False)
if r0:
# 两者碰撞时播放音效
AudioManage.play_sound("./tu/1/bjm/lx.mp3")
# 食物被碰到消失玩家得分
for foods in r0.values():
for food in foods:
food.kill()
self.ui_manage.add_score()
# 玩家与保护罩碰撞检测
r1 = pygame.sprite.spritecollide(self.player_manage.player, self.protec_manage.protect_group, True)
# 碰撞
if r1:
# 记录两者相碰时的初始时间
self.protec_last_time = time.time()
# 碰撞后生成保护罩
self.player_manage.create_shield()
# 未碰撞
elif not r1:
# (有保护罩状态下)未再碰倒可生成保护罩的食物则保护罩在5秒后消失
if self.player_manage.player.shield:
current_time = time.time()
if current_time - self.protec_last_time > 5:
self.player_manage.clear_shield()
# 玩家与炸弹碰撞检测
r2 = pygame.sprite.spritecollide(self.player_manage.player, self.bomb_manage.bomb_group, True)
if r2:
# 有保护罩则玩家存活保护罩破碎
if self.player_manage.player.shield:
# 两者碰撞时播放音效
AudioManage.play_sound("./tu/1/bjm/pz.mp3")
self.player_manage.clear_shield()
# 没有保护罩玩家死亡
elif not self.player_manage.player.shield:
# 两者碰撞时播放音效
AudioManage.play_sound("./tu/1/bjm/zq.mp3")
# 游戏结束 玩家死亡 食物、炸弹、保护罩清空
self.game_state = "end"
self.player_manage.die()
self.food_manage.clear()
self.protec_manage.clear()
self.bomb_manage.clear()
pygame.time.set_timer(BOMB_BORN, 0)
def run(self):
# 反序列化分数
self.ui_manage.load_score()
while True:
self.clock.tick(20)
self.check_event()
self.update_draw()
if self.game_state == "gaming":
self.check_collide()
gm = GameManage()
gm.run()