💝💝💝欢迎莅临我的博客,很高兴能够在这里和您见面!希望您在这里可以感受到一份轻松愉快的氛围,不仅可以获得有趣的内容和知识,也可以畅所欲言、分享您的想法和见解。
-
推荐:「stormsha的主页」👈,持续学习,不断总结,共同进步,为了踏实,做好当下事儿~
-
专栏导航
- Python系列: Python面试题合集,剑指大厂
- Git系列: Git操作技巧
- GO系列: 记录博主学习GO语言的笔记,该笔记专栏尽量写的试用所有入门GO语言的初学者
- 数据库系列: 详细总结了常用数据库 mysql 技术点,以及工作中遇到的 mysql 问题等
- 运维系列: 总结好用的命令,高效开发
- 算法与数据结构系列: 总结数据结构和算法,不同类型针对性训练,提升编程思维
非常期待和您一起在这个小小的网络世界里共同探索、学习和成长。💝💝💝 ✨✨ 欢迎订阅本专栏 ✨✨
💖The Start💖点点关注,收藏不迷路💖 📒文章目录
- 效果图
- 项目结构
- 程序代码
完整代码:https://gitcode.com/stormsha1/games/overview
效果图
项目结构
程序代码
run.py
import sys import pygame from pygame.locals import KEYDOWN, QUIT, K_q, K_ESCAPE, MOUSEBUTTONDOWN from dissipate.level import Manager from dissipate.level_tree import LevelTreeManager from dissipate.sounds import Sounds class Game: """ 游戏主类,负责初始化和主循环 """ def __init__(self): """ 初始化游戏 """ pygame.init() pygame.mixer.init() pygame.display.set_caption('开心消消乐') # 设置游戏窗口标题 pygame.mouse.set_visible(False) # 隐藏鼠标指针 # 初始化游戏管理器和声音 self.tree = LevelTreeManager() # 树管理器,用于主菜单 self.manager = Manager(0, 0) # 游戏管理器,用于处理游戏逻辑 self.world_bgm = pygame.mixer.Sound(Sounds.WORLD_BGM.value) # 世界背景音乐 self.game_bgm = pygame.mixer.Sound(Sounds.GAME_BGM.value) # 游戏背景音乐 # 提高游戏性能的优化 self.get_events = pygame.event.get # 获取事件的方法 self.update_window = pygame.display.flip # 刷新窗口的方法 self.sound_sign = 0 # 用于控制背景音乐切换的标志 def run(self): """主游戏循环""" while True: self.handle_music() # 处理背景音乐 self.draw() # 绘制游戏界面 self.handle_events() # 处理用户输入事件 self.update() # 更新显示 def handle_music(self): """根据游戏级别管理背景音乐""" if self.manager.level == 0: if self.sound_sign == 0: self.game_bgm.stop() # 停止游戏背景音乐 self.world_bgm.play(-1) # 循环播放世界背景音乐 self.sound_sign = 1 else: if self.sound_sign == 1: self.world_bgm.stop() # 停止世界背景音乐 self.game_bgm.play(-1) # 循环播放游戏背景音乐 self.sound_sign = 0 def draw(self): """根据级别绘制相应的游戏界面""" if self.manager.level == 0: self.tree.draw_tree(self.manager.energy_num, self.manager.money) # 绘制主菜单界面 else: self.manager.set_level_mode(self.manager.level) # 设置当前关卡模式 sprite_group = self.manager.draw() # 绘制游戏关卡界面 if self.manager.type == 0: self.manager.eliminate_animals() # 消除动物 self.manager.death_map() # 更新死亡地图 self.manager.swap(sprite_group) # 处理交换逻辑 self.manager.judge_level() # 判断关卡状态 def handle_events(self): """处理用户输入事件""" for event in self.get_events(): if event.type == KEYDOWN: if event.key in (K_q, K_ESCAPE): sys.exit() # 按下 Q 或 ESC 键退出游戏 elif event.type == QUIT: sys.exit() # 点击关闭按钮退出游戏 elif event.type == MOUSEBUTTONDOWN: mouse_x, mouse_y = event.pos # 获取鼠标点击位置 if self.manager.level == 0: self.tree.mouse_select( self.manager, mouse_x, mouse_y, self.manager.level, self.manager.energy_num, self.manager.money ) # 处理主菜单鼠标选择 self.manager.mouse_select(mouse_x, mouse_y) # 处理游戏内鼠标选择 def update(self): """ 更新鼠标图像并刷新显示 :return: """ self.manager.mouse_image() # 更新鼠标图像 self.update_window() # 刷新显示 if __name__ == '__main__': game = Game() # 创建游戏实例 game.run() # 启动游戏
level.py
import os from random import randint import pygame from pygame.locals import * from pygame.time import delay from dissipate.img import img_basic from dissipate.sounds import Sounds, play_sound from dissipate.sprites import Board, Element class Manager: """Game manager.""" # 游戏屏幕的大小设置为900x600像素 __screen_size = (900, 600) # 使用pygame库设置屏幕模式,DOUBLEBUF是双缓冲,32是位深度 screen = pygame.display.set_mode(__screen_size, DOUBLEBUF, 32) # 砖块的大小设置为50x50像素 __brick_size = 50 # 加载背景图片并转换为优化格式 __bg = pygame.image.load(os.path.join(img_basic, 'bg.png')).convert() # 停止宽度,可能用于游戏结束或暂停的界面 stop_width = 63 # 当前选中的砖块位置,格式为[row, col] selected = [-1, -1] # 交换标志,可能用于交换砖块或游戏逻辑 swap_sign = -1 # 上一次选中的砖块位置,格式为[row, col] last_sel = [-1, -1] # 是否交换的标志,用于判断是否发生了交换 value_swapped = False # 死亡地图的标志,可能用于显示或隐藏死亡相关的游戏元素 death_sign = True # 消除4个砖块时选中的位置,格式为[row, col] boom_sel = [-1, -1] # 当前关卡,0表示树(可能是特殊关卡或菜单) level = 0 # 玩家的金钱数量 money = 100 # 能量点数 energy_num = 30 # 数字标志,可能用于显示或隐藏数字相关的游戏元素 num_sign = True # 游戏类型,0为进行中,1为通过,-1为失败,2为树 type = 2 # 是否重置布局的标志 reset_mode = True # 每个关卡的初始步数 init_step = 15 # 当前游戏剩余的步数 step = init_step # 玩家的得分 score = 0 # 中等得分的两个阈值 min = 20 max = 50 # 已消除动物的数量列表,长度为6,可能代表6种不同的动物 animal_num = [0, 0, 0, 0, 0, 0] # 剩余需要消除的冰块数量 ice_num = 0 # 成功板,继承自Board类,位置在[200, 0] success_board = Board(Board.success, [200, 0]) # 失败板,继承自Board类,位置在[200, 0] fail_board = Board(Board.fail, [200, 0]) # 游戏网格的高度和宽度,都是9 height, width = 9, 9 # 选中的行和列,初始值为5 row, col = 5, 5 # 冰块列表,21x21的二维列表,-1表示无冰块,1表示有冰块 ice_list = [[-1 for _ in range(21)] for _ in range(21)] # 动物列表,21x21的二维列表,-2表示已消除,-1表示无动物,0-4表示不同的动物 animal = [[-1 for _ in range(21)] for _ in range(21)] # 砖块的x和y位置列表,用于确定砖块在屏幕上的位置 list_x, list_y = (__screen_size[0] - 11 * __brick_size) / 2, (__screen_size[1] - 11 * __brick_size) / 2 def __init__(self, width, height): self.height = height self.width = width self.list_x = (Manager.__screen_size[0] - self.width * Manager.__brick_size) / 2 self.list_y = (Manager.__screen_size[1] - self.height * Manager.__brick_size) / 2 self.row, self.col = Manager.xy_rc(self.list_x, self.list_y) self.list_x, self.list_y = Manager.rc_xy(self.row, self.col) self.ice_list = [[-1 for _ in range(21)] for _ in range(21)] self.animal = [[-1 for _ in range(21)] for _ in range(21)] self.reset_animals() def reset_animals(self): """ 用于将游戏板上的动物随机重置为0到5之间的数字, 其中0可能表示没有动物,1到5表示不同类型的动物。 """ # 遍历由self.row和self.col确定的起始行和列,直到高度和宽度决定的结束行和列 for row in range(self.row, self.row + self.height): # 对于每一行row,遍历由self.col和self.col + self.width确定的起始列和结束列 for col in range(self.col, self.col + self.width): # 为当前位置(row, col)随机分配一个动物编号,编号范围从0到5 # randint是random模块中的一个函数,用于生成一个指定范围内的随机整数 self.animal[row][col] = randint(0, 5) @staticmethod def rc_xy(row, col): """(row, col) -> (x, y)""" return int(Manager.list_x + (col - Manager.col) * Manager.__brick_size), int \ (Manager.list_y + (row - Manager.row) * Manager.__brick_size) @staticmethod def xy_rc(x, y): """(x, y) -> (row, col)""" return int((y - Manager.list_y) / Manager.__brick_size + Manager.row), int \ ((x - Manager.list_x) / Manager.__brick_size + Manager.col) @staticmethod def draw_brick(x, y): """Draw a brick at (x, y).""" brick = Element(Element.brick, (x, y)) Manager.screen.blit(brick.image, brick.rect) def draw_task(self, task_animal_num, which_animal, board_position=(400, 90), animal_position=(430, 35), txt_position=(455, 60)): """ 绘制任务板 """ txt_size = 24 txt_color = (0, 0, 0) Board(Board.task_board, board_position).draw(self.screen) if which_animal == 6: task_animal = Element(Element.ice, animal_position) else: task_animal = Element(Element.animals[which_animal], animal_position) task_animal.image = pygame.transform.smoothscale(task_animal.image, (40, 40)) task_animal.draw(self.screen) if which_animal == 6: if task_animal_num - self.ice_num = 16: # L3: 16 只青蛙和 16 头牛 self.type = 1 # 通过第三关 self.num_add() elif self.level == 4: if self.animal_num[5] >= 18 and self.animal_num[2] >= 18: # L4: 18 头牛和 18 只小鸡 self.type = 1 # 通过第四关 self.num_add() elif self.level == 5: if self.animal_num[2] >= 28 and self.animal_num[0] >= 28: # L5: 28 只小鸡和 28 只狐狸 self.type = 1 # 通过第五关 self.num_add() elif self.level == 6: if self.animal_num[4] >= 70: # L6: 70 只青蛙 self.type = 1 # 通过第六关 self.num_add() elif self.level == 7: if self.animal_num[2] >= 36 and self.animal_num[1] >= 36 \ and self.animal_num[0] >= 36: # L7: 36 只小鸡、36 只熊和 36 只狐狸 self.type = 1 # 通过第七关 self.num_add() elif self.level == 8: if self.ice_num >= 15: # L8: 15 冰块 self.type = 1 # 通过第八关 self.num_add() elif self.level == 9: if self.ice_num >= 49: # L9: 49 冰块 self.type = 1 # 通过第九关 self.num_add() else: if self.ice_num >= 39: # L10: 39 冰块 self.type = 1 # 通过第十关 self.num_add() self.judge_next(self.type, self.score)
level_tree.py
import pygame from pygame import DOUBLEBUF from pygame.time import delay from dissipate.sounds import play_sound, Sounds # 导入声音播放功能和声音资源 from dissipate.sprites import Tree # 导入关卡树的类 class LevelTreeManager: """ 关卡树管理器类,用于管理关卡树及其相关功能。 """ __screen_size = (900, 600) # 屏幕尺寸 screen = pygame.display.set_mode(__screen_size, DOUBLEBUF, 32) # 设置屏幕显示模式 fruit_list = [] # 用于存储水果对象的列表 fruit_image = pygame.image.load(Tree.fruit).convert_alpha() # 加载水果图片 fruit_width = fruit_image.get_width() # 获取水果图片宽度 fruit_height = fruit_image.get_height() # 获取水果图片高度 type = 0 # 场景类型,0 表示关卡树场景,1 表示能量场景 energy_full = False # 能量已满标志 money_empty = False # 金钱不足标志 def display_text(self, text, position, txt_size=25, txt_color=(255, 255, 255)): """ 显示指定的文本内容。 参数: text: 要显示的文本 position: 文本位置 txt_size: 文本大小 txt_color: 文本颜色 """ my_font = pygame.font.SysFont(None, txt_size) # 创建字体对象 text_screen = my_font.render(text, True, txt_color) # 渲染文本 self.screen.blit(text_screen, position) # 在屏幕上绘制文本 def draw_tree(self, energy_num, money_num): """ 绘制游戏中的关卡树和相关资源。 参数: energy_num: 当前能量值 money_num: 当前金钱数量 """ Tree(Tree.tree, (0, 600)).draw(self.screen) # 绘制关卡树 Tree(Tree.energy_num, Tree.energy_num_position).draw(self.screen) # 绘制能量数 if energy_num > 30: self.display_text(str(30) + '/30', (22, 55), 21) # 显示最大能量值 else: self.display_text(str(energy_num) + '/30', (22, 55), 21) # 显示当前能量值 Tree(Tree.money, (15, 135)).draw(self.screen) # 绘制金钱 self.display_text(str(money_num), (32, 124), 21) # 显示当前金钱数量 for i in range(0, 10): # 绘制水果 Tree(Tree.fruit, Tree.position[i]).draw(self.screen) self.display_text(str(i + 1), (Tree.position[i][0] + 15, Tree.position[i][1] - 47)) if self.type == 1: Tree(Tree.energy_buy, Tree.energy_buy_position).draw(self.screen) # 绘制购买能量按钮 if self.energy_full: self.display_text('energy is full!', (430, 310), 30, (255, 0, 0)) # 显示能量已满提示 pygame.display.flip() # 更新屏幕显示 delay(500) # 延迟500毫秒 self.energy_full = False # 重置能量已满标志 if self.money_empty: self.display_text('money is not enough!', (410, 310), 30, (255, 0, 0)) # 显示金钱不足提示 pygame.display.flip() # 更新屏幕显示 delay(500) # 延迟500毫秒 self.money_empty = False # 重置金钱不足标志 def mouse_select(self, mgr, mouse_x, mouse_y, level, energy_num, money_num): """ 处理鼠标事件。 参数: mgr: 管理器对象 mouse_x: 鼠标x坐标 mouse_y: 鼠标y坐标 level: 当前等级 energy_num: 当前能量值 money_num: 当前金钱数量 """ if self.type == 0: # 关卡树场景 for i in range(0, 10): if Tree.position[i][0] = 50: energy_num += 5 # 增加能量 money_num -= 50 # 减少金钱 elif 619
sprites.py
import os from pygame.sprite import Sprite from pygame.image import load from dissipate.img import img_basic, img_energy, img_board, img_text, img_level, img_button, img_animal, img_ice, \ img_boom # 基类,GameSprite类定义了所有游戏精灵的基类,包括加载图像、设置位置和绘制方法。 class GameSprite(Sprite): def __init__(self, icon, position): # 初始化GameSprite类,继承自pygame的Sprite类。 super().__init__() # 加载图像并转换为具有透明通道的格式。 self.image = load(icon).convert_alpha() # 获取图像的矩形区域。 self.rect = self.image.get_rect() # 设置精灵的位置。 self.rect.topleft = position self.rect.bottomleft = position def draw(self, screen): # 将精灵绘制到屏幕上。 screen.blit(self.image, self.rect) class Tree(GameSprite): """ 关卡树类,显示关卡树和相关资源。 """ # 树、果实、能量数字、金钱和购买能量按钮的图像路径。 tree = os.path.join(img_basic, 'tree.png') fruit = os.path.join(img_basic, 'fruit.png') energy_num = os.path.join(img_energy, 'num.png') money = os.path.join(img_basic, 'money.png') energy_buy = os.path.join(img_energy, 'buy.png') # 树、果实、能量数字、购买能量按钮的位置定义。 x, y = 340, 510 h = 90 position = ( [x, y], [x + 50, y - 25], [x + 105, y - 45], [x - 5, y - h - 5], [x + 55, y - 25 - h + 10], [x + 105, y - 45 - h], [x, y - h * 2], [x + 50 + 10, y - 25 - h * 2 - 5], [x + 105 + 25, y - 45 - h * 2 - 14], [x + 30, y - h * 3 - 30] ) # 果实位置 energy_num_position = (15, 70) # 能量位置 energy_buy_position = (250, 400) # 购买能量位置 def __init__(self, icon, position): """ 初始化树对象 """ # 重写GameSprite的构造函数,用于初始化树对象。 super().__init__(icon, position) self.image = load(icon).convert_alpha() self.rect = self.image.get_rect() self.rect.bottomleft = position class Board(GameSprite): """ 游戏面板类,显示游戏面板和相关资源。 Board类继承自GameSprite类,用于创建和显示游戏板的精灵,并包含移动逻辑。 """ # 游戏板、数字格式、任务板、成功、失败、下一步、重玩、星星、金钱的图像路径。 step_board = os.path.join(img_board, 'step.png') num_format = os.path.join(img_text, '%d.png') task_board = os.path.join(img_basic, 'task.png') ok = os.path.join(img_basic, 'ok.png') level_format = os.path.join(img_level, '%d.png') success = os.path.join(img_board, 'success.png') fail = os.path.join(img_board, 'fail.png') step_add = os.path.join(img_button, 'step_add.png') next = os.path.join(img_button, 'next.png') replay = os.path.join(img_button, 'replay.png') stars = os.path.join(img_basic, 'star.png') money = os.path.join(img_basic, 'money.png') # 按钮和星星的位置定义。 button_position = [[300, 465], [500, 465]] starts_position = [[330, 340], [413, 340], [495, 340]] def __init__(self, icon, position): """ 初始化板对象 """ super().__init__(icon, position) # 重写GameSprite的构造函数,用于初始化板对象。 self.image = load(icon).convert_alpha() self.speed = [0, 44] # 初始速度 self.rect = self.image.get_rect() self.rect.bottomleft = position def move(self): """ 根据速度移动面板 """ self.rect = self.rect.move(self.speed) if self.rect.bottom >= 543: # 到达底部边界 self.speed = [0, -45] if self.speed == [0, -45] and self.rect.bottom