pygame小游戏

         代码存在一些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()
  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值