Python实现水果忍者(开源)

一、整体介绍:

1.1 前言:

游戏代码基于Python制作经典游戏案例-水果忍者做出一些改动,优化并增加了一些功能。作为自己Python阶段学习的结束作品,文章最后有源码链接。

1.2 Python主要知识:

(1)面向对象编程 

类的定义与实例化、封装、继承(使用 pygame.sprite.Sprite 作为基类)

(2)模块与库

导入标准库(time, math, random)、导入第三方库( pygame)

(3)事件处理

事件监听(pygame.event.get() 处理用户输入和游戏事件)、响应事件(根据不同事件,如关闭窗口、定时器事件,执行相应操作)

(4)图形绘制

图像加载( pygame.image.load() 加载图像)、图像绘制(blit() 方法将图像绘制到窗口上)、图像旋转( pygame.transform.rotate() 旋转图像)

(5)随机数生成

(6)计时与帧率控制

使用 pygame.time.Clock() 控制游戏的帧率

(7)文件操作

使用 open() 读取和写入文本文件,保存和读取最佳分数、逐行读取文件内容并解析数据

(8)碰撞检测

(9)Sprite 和 Group

使用 pygame.sprite.Sprite 创建精灵(如水果、刀光、背景)、使用 pygame.sprite.Group 管理和更新多个精灵,方便批量处理

(10)数学运算

使用三角函数,math.sin() 和 math.cos(),计算水果的抛出轨迹

(11)音频处理

使用 pygame.mixer 播放背景音乐和音效,增强游戏体验

(12)逻辑控制

(13)字体与文本渲染

使用 pygame.font.Font() 创建字体对象,并使用 render() 方法渲染文本以显示分数和信息

(14)参数传递与返回值

1.3 游戏素材

二、完善功能:

(1)优化游戏参数

例如:首页旋转圆环速度,水果上抛高度等,使游戏体验更加平滑。

(2)禅宗模式倒计时

禅宗模式在游戏右上方增加了时间倒计时的图形化界面。

(3)增加额外音效

由于pygame同时播放音乐,会有覆盖现象。即后播放音乐会覆盖之前播放音乐,导致原版游戏结束,bgm.play_over被bgm.play_menu覆盖,播放不出来。使用独立线程对代码要求较高,取巧,利用睡眠(time.sleep)。玩家切到炸弹结束游戏,暂停0.3s画面,而不是原版的突然重新开始。

(4)游戏历史最高分数

利用IO流逐行读取txt文件,和原版分数一样的window.blit函数绘制在游戏界面,不过分数的更新要在结束程序后会执行。

Bug:

游戏的局部和实例变量较多,有些资源可能会被程序占用而无法释放。目前主要bug,在游戏碰撞检测的时候,偶尔会出现分数停止更新的情况。本人才疏学浅,至今没有有效解决,希望大佬们多多包涵,最好能够帮助解决,完善游戏。

三、代码设计:

import time
import math
import random
import pygame
from pygame.constants import *

pygame.init()

""" 背景图片 """
class Background(pygame.sprite.Sprite):

    def __init__(self, window, x, y, image_path):
        pygame.sprite.Sprite.__init__(self)
        self.window = window
        self.image = pygame.image.load(image_path)
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y

    def update(self):
        self.window.blit(self.image, self.rect)


""" 被抛出的水果类 """
class ThrowFruit(pygame.sprite.Sprite):

    def __init__(self, window, image_path, speed, turn_angel, flag):
        pygame.sprite.Sprite.__init__(self)

        # 游戏窗口
        self.window = window

        # 导入水果图像并获取其矩形区域
        self.image = pygame.image.load(image_path)
        self.rect = self.image.get_rect()

        # 水果抛出时x坐标取随机数
        self.rect.x = random.randint(0, Manager.WIDTH - 10)

        # 水果初始y坐标
        self.rect.y = Manager.HEIGHT

        # 抛出时速度
        self.speed = speed

        # 旋转速度
        self.turn_angel = turn_angel

        # 水果抛出时与窗口下水平线的夹角弧度,因为要用到随机函数, 所以取整数, 使用时除以100
        self.throw_angel = 157

        # 水果抛出后所经历的时间, 初始化为0
        self.fruit_t = 0

        # 旋转的总角度
        self.v_angel = 0

        # 水果抛出时的初速度
        self.v0 = 6

        # 水果标记
        self.flag = flag

    def update(self):
        """ 水果运动状态更新 """

        # 在弧度制中,一个完整的圆周对应的角度是360度,对应的弧度是2π(即360度 = 2π弧度)。
        # 因此,可以通过以下公式将角度转换为弧度: 弧度 = 角度 × π / 180
        # 当角度为90度时,根据上述公式,可以计算出对应的弧度为: 90度 × π / 180 = 0.5π = 1.57(约)

        # 如果水果的初始X坐标位于窗口左边区域, 取抛出时弧度在70度至90度之间
        if self.rect.x <= Manager.WIDTH / 2:
            self.throw_angel = random.randint(140, 157)

        # 如果水果的初始X坐标位于窗口右侧区域, 取抛出时弧度在90度至110度之间
        elif self.rect.x >= Manager.WIDTH / 2:
            self.throw_angel = random.randint(157, 175)

        # 水果旋转后的新图像
        new_fruit = pygame.transform.rotate(self.image, self.v_angel)

        self.window.blit(new_fruit, (self.rect.x + self.rect.width / 2 - new_fruit.get_width() / 2,
                                     self.rect.y + self.rect.height / 2 - new_fruit.get_height() / 2))

        # 如果水果落出屏幕,没有被切,经典模式 X 加一,并销毁水果对象
        if self.rect.y >= Manager.HEIGHT + self.rect.height:
            if self.flag != 5:
                Manager.classic_miss += 1
            self.kill()

        # 水果抛出后的运动时水平匀速运动以及竖直向上的变速运动到达最高点时下落, 所以可以判断水果做的是斜上抛运动
        # 可以利用重力加速度来求出每隔一段时间水果运动后的y坐标
        # 公式: v0 * t * sin(α) - g * t^2 / 2
        self.rect.y -= self.v0 * self.fruit_t * math.sin(self.throw_angel / 100) - (Manager.G *
                                                                                    self.fruit_t ** 2 / 10) / 2

        # 计算水果在水平方向的匀速运动位移之后的X坐标
        # 公式: v0 * t * cos(α)
        self.rect.x += self.v0 * self.fruit_t * math.cos(self.throw_angel / 100)

        # 累加经过的时间
        self.fruit_t += 0.1

        # 累加旋转总角度
        self.v_angel += self.turn_angel


""" 水果切片类 """
class HalfFruit(pygame.sprite.Sprite):

    def __init__(self, window, image_path, x, y, turn_angel, v_angel, v0):
        pygame.sprite.Sprite.__init__(self)
        self.window = window
        self.image = pygame.image.load(image_path)
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
        self.turn_angel = turn_angel
        self.fruit_t = 0
        self.v_angel = v_angel
        self.v0 = v0

    def update(self):
        """ 水果运动状态更新 """

        # 水果旋转后的新图像
        new_fruit = pygame.transform.rotate(self.image, self.v_angel)

        # 将旋转后的新图像贴入游戏窗口, 注意, 旋转后的图像尺寸以及像素都不一样了(尺寸变大了), 所以坐标需要进行适当处理
        #                               在原先图片矩形的中心位置绘制
        self.window.blit(new_fruit, (self.rect.x + self.rect.width / 2 - new_fruit.get_width() / 2,
                                     self.rect.y + self.rect.height / 2 - new_fruit.get_height() / 2))

        if self.rect.y >= Manager.HEIGHT:
            self.kill()
        self.rect.y += Manager.G * self.fruit_t ** 2 / 2

        self.rect.x += self.v0 * self.fruit_t

        self.fruit_t += 0.01

        self.v_angel += self.turn_angel


""" 水果刀光类 """
class Knife(object):

    def __init__(self, window):
        self.window = window
        self.apple_flash = pygame.image.load("./images/apple_flash.png")
        self.banana_flash = pygame.image.load("./images/banana_flash.png")
        self.peach_flash = pygame.image.load("./images/peach_flash.png")
        self.watermelon_flash = pygame.image.load("./images/watermelon_flash.png")
        self.strawberry_flash = pygame.image.load("./images/strawberry_flash.png")

    def show_apple_flash(self, x, y):
        self.window.blit(self.apple_flash, (x, y))

    def show_banana_flash(self, x, y):
        self.window.blit(self.banana_flash, (x, y))

    def show_peach_flash(self, x, y):
        self.window.blit(self.peach_flash, (x, y))

    def show_watermelon_flash(self, x, y):
        self.window.blit(self.watermelon_flash, (x, y))

    def show_strawberry_flash(self, x, y):
        self.window.blit(self.strawberry_flash, (x, y))


""" 模式选项类 """
class OptionMode(pygame.sprite.Sprite):

    def __init__(self, window, x, y, image_path, turn_angel, flag):
        pygame.sprite.Sprite.__init__(self)
        self.window = window
        self.image = pygame.image.load(image_path)
        self.rect = self.image.get_rect()
        self.rect.x = x
        self.rect.y = y
        self.turn_angel = turn_angel
        self.v_angel = 0
        self.flag = flag

    def update(self):
        new_image = pygame.transform.rotate(self.image, -self.v_angel)
        self.window.blit(new_image, (self.rect.x + self.rect.width / 2 - new_image.get_width() / 2,
                                     self.rect.y + self.rect.height / 2 - new_image.get_height() / 2))
        self.v_angel += self.turn_angel


""" 游戏音乐类 """
class Bgm(object):

    def __init__(self):
        pygame.mixer.init()

    def play_menu(self):
        pygame.mixer.music.load("./sound/menu.mp3")
        pygame.mixer.music.play(-1, 0)

    def play_classic(self):
        pygame.mixer.music.load("./sound/start.mp3")
        pygame.mixer.music.play(1, 0)

    def play_throw(self):
        pygame.mixer.music.load("./sound/throw.mp3")
        pygame.mixer.music.play(1, 0)

    def play_splatter(self):
        pygame.mixer.music.load("./sound/splatter.mp3")
        pygame.mixer.music.play(1, 0)

    def play_over(self):
        pygame.mixer.music.load("./sound/over.mp3")
        pygame.mixer.music.play(1, 0)

    def play_boom(self):
        pygame.mixer.music.load("./sound/boom.mp3")
        pygame.mixer.music.play(1, 0)


""" 游戏逻辑类 """
class Manager(object):
    # 窗口尺寸
    WIDTH = 640
    HEIGHT = 480

    # 游戏中的定时器常量
    THROWFRUITTIME = pygame.USEREVENT
    pygame.time.set_timer(THROWFRUITTIME, 3000)

    # 根据窗口大小,选取随机整数重力加速度, 水果下落更有层次感,使用时除以10
    G = random.randint(19, 21)

    # 经典模式miss掉的水果数
    classic_miss = 0

    # 打开文本文件
    with open('best.txt', 'r') as file:
        # 逐行读取文件内容
        for line in file:
            if 'zen_mode' in line:
                zen_best = int(line.split(':')[-1].strip())
            if 'classic_mode' in line:
                classic_best = int(line.split(':')[-1].strip())

    def __init__(self):
        # 生成游戏窗口
        self.window = pygame.display.set_mode((Manager.WIDTH, Manager.HEIGHT))
        self.window_icon = pygame.image.load("./images/score.png")
        pygame.display.set_icon(self.window_icon)
        pygame.display.set_caption("FruitNinja")

        # 创建游戏中用到的的精灵组
        self.background_list = pygame.sprite.Group()
        self.circle_option = pygame.sprite.Group()
        self.option_fruit_list = pygame.sprite.Group()
        self.fruit_half_list = pygame.sprite.Group()
        self.throw_fruit_list = pygame.sprite.Group()

        # 导入背景图像并添加入背景精灵组
        self.background = Background(self.window, 0, 0, "./images/background.jpg")
        self.home_mask = Background(self.window, 0, 0, "./images/home-mask.png")
        self.logo = Background(self.window, 20, 10, "./images/logo.png")
        self.ninja = Background(self.window, Manager.WIDTH - 320, 45, "./images/ninja.png")
        self.home_desc = Background(self.window, 20, 135, "./images/home-desc.png")
        self.zen_new = Background(self.window, 175, 215, "./images/new.png")

        self.background_list.add(self.background)
        self.background_list.add(self.home_mask)
        self.background_list.add(self.logo)
        self.background_list.add(self.ninja)
        self.background_list.add(self.home_desc)
        self.background_list.add(self.zen_new)

        # 创建旋转的圈并添加进精灵组
        self.dojo = OptionMode(self.window, Manager.WIDTH - 600, Manager.HEIGHT - 250,
                               "./images/dojo.png", 1, None)
        self.new_game = OptionMode(self.window, Manager.WIDTH - 405, Manager.HEIGHT - 250,
                                   "./images/new-game.png", 1, None)
        self.game_quit = OptionMode(self.window, Manager.WIDTH - 160, Manager.HEIGHT - 150,
                                    "./images/quit.png", -1, None)
        self.circle_option.add(self.dojo)
        self.circle_option.add(self.new_game)
        self.circle_option.add(self.game_quit)

        # 创建主菜单界面旋转的水果并添加进精灵组
        self.home_peach = OptionMode(self.window, Manager.WIDTH - 600 + self.dojo.rect.width / 2 - 31,
                                     Manager.HEIGHT - 250 + self.dojo.rect.height / 2 - 59 / 2,
                                     "./images/peach.png", -1, "option_peach")
        self.home_watermelon = OptionMode(self.window, Manager.WIDTH - 405 + self.new_game.rect.width / 2 - 49,
                                          Manager.HEIGHT - 250 + self.new_game.rect.height / 2 - 85 / 2,
                                          "./images/watermelon.png", -1, "option_watermelon")
        self.home_boom = OptionMode(self.window, Manager.WIDTH - 160 + self.game_quit.rect.width / 2 - 66 / 2,
                                    Manager.HEIGHT - 150 + self.game_quit.rect.height / 2 - 68 / 2,
                                    "./images/boom.png", 1, "option_boom")
        self.option_fruit_list.add(self.home_peach)
        self.option_fruit_list.add(self.home_watermelon)
        self.option_fruit_list.add(self.home_boom)

        # 设置定时器
        self.clock = pygame.time.Clock()

        # 模式标记
        self.mode_flag = 0

        # 音效
        self.bgm = Bgm()

        # 刀光
        self.knife = Knife(self.window)

        # 游戏分数
        self.classic_score = 0
        self.zen_score = 0

    def create_fruit(self):
        """ 创建水果 """
        if self.mode_flag == 1:
            boom_prob = random.randint(4, 6)
            if boom_prob == 5:
                self.bgm.play_throw()
                boom = ThrowFruit(self.window, "./images/boom.png", None, 5, 5)
                self.throw_fruit_list.add(boom)

        fruit_image_path = ["./images/apple.png", "./images/banana.png", "./images/peach.png",
                            "./images/watermelon.png", "./images/strawberry.png"]
        fruit_number = random.randint(1, 4)
        for n in range(fruit_number):
            rand_fruit_index = random.randint(0, len(fruit_image_path) - 1)
            self.bgm.play_throw()
            fruit = ThrowFruit(self.window, fruit_image_path[rand_fruit_index], None, 5,
                               rand_fruit_index)
            self.throw_fruit_list.add(fruit)

    def create_fruit_half(self, fruit_flag, fruit_x, fruit_y, turn_angel, v_angel):
        if fruit_flag == "option_peach":
            """ 禅宗模式的桃子被切开 """
            fruit_left = HalfFruit(self.window, "./images/peach-1.png", fruit_x - 50,
                                   fruit_y, turn_angel, v_angel, -5)
            fruit_right = HalfFruit(self.window, "./images/peach-2.png", fruit_x + 50,
                                    fruit_y, -turn_angel, v_angel, 5)
            self.fruit_half_list.add(fruit_left)
            self.fruit_half_list.add(fruit_right)

        if fruit_flag == "option_watermelon":
            """ 经典模式西瓜被切开 """
            fruit_left = HalfFruit(self.window, "./images/watermelon-1.png", fruit_x - 50,
                                   fruit_y, turn_angel, v_angel, -5)
            fruit_right = HalfFruit(self.window, "./images/watermelon-2.png", fruit_x + 50,
                                    fruit_y, -turn_angel, v_angel, 5)
            self.fruit_half_list.add(fruit_left)
            self.fruit_half_list.add(fruit_right)

        if fruit_flag == 0:
            """ 苹果被切开 """
            fruit_left = HalfFruit(self.window, "./images/apple-1.png", fruit_x - 50,
                                   fruit_y, turn_angel, v_angel, -5)
            fruit_right = HalfFruit(self.window, "./images/apple-2.png", fruit_x + 50,
                                    fruit_y, -turn_angel, v_angel, 5)
            self.fruit_half_list.add(fruit_left)
            self.fruit_half_list.add(fruit_right)

        if fruit_flag == 1:
            """ 香蕉被切开 """
            fruit_left = HalfFruit(self.window, "./images/banana-1.png", fruit_x - 50,
                                   fruit_y, turn_angel, v_angel, -5)
            fruit_right = HalfFruit(self.window, "./images/banana-2.png", fruit_x + 50,
                                    fruit_y, -turn_angel, v_angel, 5)
            self.fruit_half_list.add(fruit_left)
            self.fruit_half_list.add(fruit_right)

        if fruit_flag == 2:
            """ 梨被切开 """
            fruit_left = HalfFruit(self.window, "./images/peach-1.png", fruit_x - 50,
                                   fruit_y, turn_angel, v_angel, -5)
            fruit_right = HalfFruit(self.window, "./images/peach-2.png", fruit_x + 50,
                                    fruit_y, -turn_angel, v_angel, 5)
            self.fruit_half_list.add(fruit_left)
            self.fruit_half_list.add(fruit_right)

        if fruit_flag == 3:
            """ 西瓜被切开 """
            fruit_left = HalfFruit(self.window, "./images/watermelon-1.png", fruit_x - 50,
                                   fruit_y, turn_angel, v_angel, -5)
            fruit_right = HalfFruit(self.window, "./images/watermelon-2.png", fruit_x + 50,
                                    fruit_y, -turn_angel, v_angel, 5)
            self.fruit_half_list.add(fruit_left)
            self.fruit_half_list.add(fruit_right)

        if fruit_flag == 4:
            """ 草莓被切开 """
            fruit_left = HalfFruit(self.window, "./images/strawberry-1.png", fruit_x - 50,
                                   fruit_y, turn_angel, v_angel, -5)
            fruit_right = HalfFruit(self.window, "./images/strawberry-2.png", fruit_x + 50,
                                    fruit_y, -turn_angel, v_angel, 5)
            self.fruit_half_list.add(fruit_left)
            self.fruit_half_list.add(fruit_right)

    def impact_check(self):
        """ 碰撞检测 """
        for item in self.option_fruit_list:
            """ 主页的模式选择 """
            mouse_pos = pygame.mouse.get_pos()
            if mouse_pos[0] > item.rect.left and mouse_pos[0] < item.rect.right \
                    and mouse_pos[1] > item.rect.top and mouse_pos[1] < item.rect.bottom:
                self.bgm.play_splatter()
                self.create_fruit_half(item.flag, item.rect.x, item.rect.y, item.turn_angel, item.v_angel)
                self.option_fruit_list.remove_internal(item)
                if item.flag == "option_peach":
                    self.mode_flag = 1
                    return 1
                elif item.flag == "option_watermelon":
                    self.mode_flag = 2
                    return 2
                elif item.flag == "option_boom":
                    return 0

        for item in self.throw_fruit_list:
            """ 游戏开始后判断水果是否被切到 """
            mouse_pos = pygame.mouse.get_pos()
            if mouse_pos[0] > item.rect.left and mouse_pos[0] < item.rect.right \
                    and mouse_pos[1] > item.rect.top and mouse_pos[1] < item.rect.bottom:
                if item.flag == 0:
                    self.knife.show_apple_flash(item.rect.x, item.rect.y)
                if item.flag == 1:
                    self.knife.show_banana_flash(item.rect.x, item.rect.y)
                if item.flag == 2:
                    self.knife.show_peach_flash(item.rect.x, item.rect.y)
                if item.flag == 3:
                    self.knife.show_watermelon_flash(item.rect.x, item.rect.y)
                if item.flag == 4:
                    self.knife.show_strawberry_flash(item.rect.x, item.rect.y)

                if self.mode_flag == 1:
                    self.zen_score += 2
                if self.mode_flag == 2:
                    self.classic_score += 2
                if item.flag != 5:
                    self.bgm.play_splatter()

                self.create_fruit_half(item.flag, item.rect.x, item.rect.y, item.turn_angel, item.v_angel)
                self.throw_fruit_list.remove_internal(item)
                if item.flag == 5:
                    self.bgm.play_boom()
                    time.sleep(0.4)
                    return 3

    def check_key(self):
        """ 监听事件 """
        for event in pygame.event.get():
            if event.type == QUIT:
                pygame.quit()
                exit()
            elif event.type == Manager.THROWFRUITTIME and self.mode_flag == 1:
                self.create_fruit()
            elif event.type == Manager.THROWFRUITTIME and self.mode_flag == 2:
                self.create_fruit()

    def zen_mode(self):
        """ 禅宗模式 """
        self.bgm.play_classic()
        score_image = Background(self.window, 10, 5, "./images/score.png")
        text = pygame.font.Font("./images/simhei.ttf", 30)  # 设置分数显示的字体
        best = pygame.font.Font("./images/simhei.ttf", 20)  # 设置历史最好分数显示的字体

        # 禅宗模式游戏时间
        record_time = 3600

        while True:
            # 设置游戏帧率
            self.clock.tick(60)
            self.check_key()
            self.background_list.sprites()[0].update()
            score_image.update()

            text_score = text.render("%d" % self.zen_score, 1, (255, 213, 156))
            self.window.blit(text_score, (50, 8))
            best_score = best.render("BEST %d" % self.zen_best, 1, (255, 179, 78))
            self.window.blit(best_score, (10, 40))

            game_time = text.render("Time:%d" % (record_time / 60), 1, (178, 34, 34))
            self.window.blit(game_time, (510, 12))

            temp_flag = self.impact_check()

            self.throw_fruit_list.update()
            self.fruit_half_list.update()
            pygame.display.update()

            record_time -= 1

            # 禅宗模式更新最高历史记录
            if record_time == 0 or temp_flag == 3:
                if self.zen_score > self.zen_best:
                    file_path = 'best.txt'
                    with open(file_path, 'r') as file:
                        content = file.read()
                        content = content.replace(str(self.zen_best), str(self.zen_score))
                        with open(file_path, 'w') as file:
                            file.write(content)
                return

    def classic_mode(self):
        """ 经典模式 """
        pygame.font.init()
        self.bgm.play_classic()
        score_image = Background(self.window, 10, 5, "./images/score.png")
        text = pygame.font.Font("./images/simhei.ttf", 30)  # 设置分数显示的字体
        best = pygame.font.Font("./images/simhei.ttf", 20)  # 设置历史最好分数显示的字体

        x_nums = pygame.sprite.Group()
        miss_times = pygame.sprite.Group()
        xxx = Background(self.window, Manager.WIDTH - 30, 5, "./images/xxx.png")
        xx = Background(self.window, Manager.WIDTH - 60, 5, "./images/xx.png")
        x = Background(self.window, Manager.WIDTH - 90, 5, "./images/x.png")
        x_nums.add(xxx)
        x_nums.add(xx)
        x_nums.add(x)

        while True:
            # 设置游戏帧率
            self.clock.tick(60)
            pygame.display.update()
            self.check_key()
            self.background_list.sprites()[0].update()
            score_image.update()

            text_score = text.render("%d" % self.classic_score, 1, (255, 213, 156))
            self.window.blit(text_score, (50, 8))
            best_score = best.render("BEST %d" % self.classic_best, 1, (255, 179, 78))
            self.window.blit(best_score, (10, 40))

            x_nums.update()
            miss_times.update()
            temp_flag = self.impact_check()
            if temp_flag == 3:
                # 经典模式炸弹结束游戏更新历史最高记录
                if self.classic_score > self.classic_best:
                    file_path = 'best.txt'
                    with open(file_path, 'r') as file:
                        content = file.read()
                        content = content.replace(str(self.classic_best), str(self.classic_score))
                        with open(file_path, 'w') as file:
                            file.write(content)
                self.bgm.play_boom()
                time.sleep(0.4)
                return

            self.throw_fruit_list.update()
            self.fruit_half_list.update()
            if Manager.classic_miss == 1:
                xf = Background(self.window, Manager.WIDTH - 90, 5, "./images/xf.png")
                miss_times.add(xf)
            elif Manager.classic_miss == 2:
                xf = Background(self.window, Manager.WIDTH - 90, 5, "./images/xf.png")
                miss_times.add(xf)
                xxf = Background(self.window, Manager.WIDTH - 60, 5, "./images/xxf.png")
                miss_times.add(xxf)
            elif Manager.classic_miss >= 3:
                # 经典模式正常结束更新历史最高记录
                if self.classic_score > self.classic_best:
                    file_path = 'best.txt'
                    with open(file_path, 'r') as file:
                        content = file.read()
                        content = content.replace(str(self.classic_best), str(self.classic_score))
                        with open(file_path, 'w') as file:
                            file.write(content)
                self.bgm.play_over()
                time.sleep(0.4)
                Manager.classic_miss = 0
                return

    def main(self):
        """ 主页 """
        self.bgm.play_menu()
        while True:
            # 设置游戏帧率
            self.clock.tick(60)
            self.background_list.update()
            self.circle_option.update()
            self.option_fruit_list.update()
            self.fruit_half_list.update()
            temp_flag = self.impact_check()
            pygame.display.update()

            if temp_flag == 1:
                self.zen_mode()
                self.__init__()
                self.bgm.play_over()
                self.bgm.play_menu()

            if temp_flag == 2:
                self.classic_mode()
                self.__init__()
                self.bgm.play_over()
                self.bgm.play_menu()

            elif temp_flag == 0:
                self.bgm.play_over()
                time.sleep(0.3)
                pygame.quit()
                exit()
            elif temp_flag == 3:
                self.__init__()
                self.bgm.play_menu()
            self.check_key()


if __name__ == '__main__':
    manager = Manager()
    manager.main()

源码:

链接:https://pan.baidu.com/s/11YM7GzqzFz1QkcGbJHnDCQ 
提取码:daz5

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/870755.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

网络安全-防火墙初步认识。

文章目录 1. 防火墙是什么&#xff1f;2. 防火墙的工作原理是什么&#xff1f;3. 防火墙的分类有哪些&#xff1f;4. 实战4.1 防火墙管理和实验介绍4.2 防火墙命令行初体验实验目标&#xff1a;实验步骤&#xff1a; 4.3 防火墙Web初体验实验目标&#xff1a;实验步骤&#xff…

canvas实现图片矩形截图,矩形旋转后的截图,旋转后的截图摆正显示

一、效果图 二、主要代码 获取矩形框中地方的截图数据 1、先获取矩形四点在画布上的实际坐标值&#xff1b; 2、计算矩形此时实际的宽和高&#xff0c;便于设置后期临时矩形的宽和高&#xff1b; 3、可能矩形旋转了一定的角度&#xff0c;我们新建一个临时的画布tempCanvas&am…

mkv怎么改成mp4?3种mkv转mp4格式方法的介绍

mkv怎么改成mp4&#xff1f;将MKV格式视频转换为MP4格式&#xff0c;能显著提升兼容性&#xff0c;让视频在更多设备、平台上流畅播放。无论是智能手机、平板电脑、智能电视还是网页浏览器&#xff0c;MP4格式都具备广泛的支持&#xff0c;从而扩大视频的传播范围和受众群体。这…

【Hadoop】核心组件深度剖析:HDFS、YARN与MapReduce的奥秘

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《大数据前沿&#xff1a;技术与应用并进》&#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、引言 1、Hadoop简介 2、Hadoop生态系统概览 二、Hadoo…

人工智能和机器学习 3(复旦大学计算机科学与技术实践工作站)python机器学习、Pytorch库入门、d2l学习+<机器学习、神经网络————原理、理论>

前言 安装 — 动手学深度学习 2.0.0 documentation (d2l.ai)https://zh.d2l.ai/chapter_installation/index.html 安装 我们需要配置一个环境来运行 Python、Jupyter Notebook、相关库以及运行本书所需的代码&#xff0c;以快速入门并获得动手学习经验。 安装 Miniconda 最…

建造者模式 和 外观模式

这两种模式很像, 都是将一个复杂的流程统一用一个方法进行包装, 方便外界使用. 建造者模式更像是 外观模式的一种特里, 只对一个类的复杂初始化流程进行包装 建造者模式 简介: 就是一个类的构造方法可能很复杂, 由于系统的限制等原因, 可能很多初始化逻辑不能放在构造函数里,…

Redis大显身手:实时用户活跃排行榜

文章目录 场景说明方案设计数据结构 Redis使用方案排行榜实现更新用户活跃积分幂等策略榜单评分更新触发活跃度更新排行榜查询 技术派项目源码地址 : Gitee :技术派 - https://gitee.com/itwanger/paicodingGithub :技术派 - https://github.com/itwanger/paicoding 效果如图 …

在阿里云上部署 Docker并通过 Docker 安装 Dify

目录 一、在服务器上安装docker和docker compose 1.1 首先关闭防火墙 1.2 安装docker依赖包 1.3 设置阿里云镜像源并安装docker-ce社区版 1.4 开启docker服务并设置开机自启动 1.5 查看docker版本信息 1.6 设置镜像加速 1.7 将docker compose环境复制到系统的bin目录下…

DM8守护集群部署、数据同步验证、主备切换

1. 环境描述 实例详情 端口详情 2. 部署步骤 2.1 数据准备 2.1.1主库初始化 [dmdbaray1 ~]$ cd /dmdba/dmdbms/bin [dmdbaray1 bin]$ ./dminit path/dmdba/data PAGE_SIZE32 EXTENT_SIZE32 CASE_SENSITIVEy CHARSET1 DB_NAMEGRP1_RT_01 INSTANCE_NAMEGRP1_RT_01 PORT_NU…

C++——入门基础(上)

目录 一、C参考文档 二、C在工作领域的应用 三、C学习书籍 四、C的第一个程序 五、命名空间 &#xff08;1&#xff09;namespace的定义 (2)命名空间的使用 六、C的输入和输出 七、缺省函数 八、函数重载 九、写在最后 一、C参考文档 &#xff08;1&#xff09;虽…

第46课 Scratch入门篇:狙击望远镜

无限画中画 故事背景: 手拿一把狙击枪,第一次按下空格键的时候瞄准镜放大一倍,再按一次再放大一倍。开枪设计,瞬间击毁! 程序原理: 1、瞄准的物品放大,其实是角色的变化,我们把背景设置成角色,原始的角色是 480360,第一次放大的图为 14401080,放大了 3 倍。第二级…

【Java 并发编程】(二) 从对象内存布局开始聊 synchronized

对象的内存布局 首先抛出一个经典面试题: 一个 Object 对象占多大? 这里我用工具打印了出来, 发现是 “16bytes”, 也就是 16B; 为什么? 请继续往下看; 普通对象(除了数组), 由markword, 类型指针, 实例数据(就是对象里的成员), 对齐填充(整个对象大小要能被8B整数, 方便6…

思科OSPF动态路由配置8

#路由协议实现# #任务八OSPF动态路由配置8# 开放式最短路径优先&#xff08;Open Shortest Path First,OSPF&#xff09;协议是目前网络中应用最广泛的动态路由协议之一。它也属于内部网关路由协议&#xff0c;能够适应各种规模的网络环境&#xff0c;是典型的链路状态路由协…

ZooKeeper 集群的详细部署

ZooKeeper 集群部署 一、ZooKeeper 简介1.1 什么是 ZooKeeper1.2 ZooKeeper 特点 二 ZooKeeper 的架构和设计4.1 ZooKeeper 数据模型4.1.1 Znode 节点特性 三、ZooKeeper 的集群安装前准备工作3.1 需要的准备工作3.2 Linux 系统 3 个节点准备3.2.1 克隆3.2.2 配置另外两台服务器…

【RabbitMQ】 相关概念 + 工作模式

本文将介绍一些MQ中常见的概念&#xff0c;同时也会简单实现一下RabbitMQ的工作流程。 MQ概念 Message Queue消息队列。是用来存储消息的队列&#xff0c;多用于分布式系统之间的通信。 系统间调用通常有&#xff1a;同步通信和异步通信。MQ就是在异步通信的时候使用的。 同…

高考志愿智能推荐系统-计算机毕设Java|springboot实战项目

&#x1f34a;作者&#xff1a;计算机毕设匠心工作室 &#x1f34a;简介&#xff1a;毕业后就一直专业从事计算机软件程序开发&#xff0c;至今也有8年工作经验。擅长Java、Python、微信小程序、安卓、大数据、PHP、.NET|C#、Golang等。 擅长&#xff1a;按照需求定制化开发项目…

第三方软件测评中心分享:软件系统测试内容和作用

近年来&#xff0c;随着信息技术的迅猛发展&#xff0c;软件系统的应用范围不断扩大。保证软件质量的关键措施之一就是软件系统测试。软件系统测试是指在软件开发生命周期中&#xff0c;通过一系列特定的测试活动来验证和确认软件系统的性能、功能及安全性&#xff0c;确保软件…

优优嗨聚集团:餐饮合作新未来引领美食产业新风尚

在快速变化的21世纪&#xff0c;餐饮行业作为民生消费的重要组成部分&#xff0c;正经历着前所未有的变革与挑战。随着消费者需求的多元化、个性化以及科技的不断进步&#xff0c;餐饮合作的新模式正悄然兴起&#xff0c;为行业带来了前所未有的发展机遇与活力。本文将探讨餐饮…

【Redis】Redis 数据类型与结构—(二)

Redis 数据类型与结构 一、值的数据类型二、键值对数据结构三、集合数据操作效率 一、值的数据类型 Redis “快”取决于两方面&#xff0c;一方面&#xff0c;它是内存数据库&#xff0c;另一方面&#xff0c;则是高效的数据结构。 Redis 键值对中值的数据类型&#xff0c;也…

网页版IntelliJ IDEA部署

在服务器部署网页 IntelliJ IDEA 引言 大家好&#xff0c;我是小阳&#xff0c;今天要为大家带来一个黑科技——如何在云端部署和使用WEB版的IntelliJ IDEA&#xff0c;让你在任何地方都可以随心所欲地进行Java开发。这个方法特别适合那些用着老旧Windows电脑&#xff0c;部署…