版本一和素材看另外一篇博客:
https://blog.csdn.net/qq_39236499/article/details/107848795
版本二
6个模块版本
main.py, game_functions.py, all_events.py, glass.py, ball.py, settings.py
main.py
import pygame import traceback # 运行那里用到了 """自建模块""" from glass import Glass # 摩擦板和摩擦手模块 from settings import Settings # 设置模块 import game_functions as gf # 功能模块 import all_events # 事件模块 ai_settings = Settings() # 导入设置 motion = 0 # 2、创建一个motion 变量来记录每一秒钟产生事件数量 def main(): # 主函数,把一群东西封装起来了 pygame.init() # 初始化 ai_settings.play_bg_music() # 播放背景音乐 screen = pygame.display.set_mode(ai_settings.bg_size) # 绘制窗口 pygame.display.set_caption("小游戏") # 窗口名 background = ai_settings.bg_image.convert_alpha() # 加载背景图片 """set_endevent是什么""" pygame.mixer.music.set_endevent(ai_settings.GAMEOVER) # 音乐结束游戏结束 """group是什么""" group = pygame.sprite.Group() # 精灵组合吗 clock = pygame.time.Clock() # 设置帧率需要 """这是什么""" msgs = [] balls = [] # 用来存放小球对象的列表 gf.set_five_ball(ai_settings, balls, group) # 创建五个小球,位置随机,速度随机 glass = Glass(ai_settings.bg_size) # 实例化摩擦板 pygame.time.set_timer(ai_settings.MYTIMER, 1000) # 定时器,1秒一次 """这是什么""" pygame.key.set_repeat(100, 100) while True: # 主循环 all_events.check_all_events(ai_settings, group, balls, msgs) # 根据事件作出响应 gf.blit_all(screen, background, glass, balls, group, msgs, clock) # 绘制所有 """运行""" if __name__ == "__main__": # 运行 try: main() except SystemExit: # 这是按下 × 的异常,直接忽略 pass except: traceback.print_exc() # 不知道什么意思 pygame.quit() input()
game_functions.py
import pygame from random import * # 随机生成数需要 """"自建""" from ball import Ball def set_five_ball(ai_settings, balls, group): """创建5个小球,位置随机,速度随机""" for i in range(5): # 遍历5 position = randint(0, ai_settings.width - 100), \ randint(0, ai_settings.height - 100) # 随机生成位置,赋值position speed = [randint(1, 10), randint(1, 10)] # 随机生成速度,赋值speed ball = Ball(position, speed, ai_settings.bg_size, 5 * (i+1)) # 实例化一个球 while pygame.sprite.spritecollide(ball, group, False, pygame.sprite.collide_circle): # 如果一生成就碰撞 """ 小球 group 不删除 圆形属性""" ball.rect.left, ball.rect.top = \ randint(0, ai_settings.width - 100), \ randint(0, ai_settings.height - 100) # 再次随机位置 balls.append(ball) # 列表用append添加 group.add(ball) # 集合用add ######################################################################################################################## def blit_all(screen, background, glass, balls, group, msgs, clock): """绘制所有到屏幕上""" screen.blit(background, (0, 0)) # 绘制背景图像 screen.blit(glass.glass_image, glass.glass_rect) # 绘制摩擦板 glass.mouse_rect.left, glass.mouse_rect.top = pygame.mouse.get_pos() # 获得鼠标当前位置 keep_place(glass) # 设置摩擦手位置在摩擦板上 screen.blit(glass.mouse_image, glass.mouse_rect) # 绘制鼠标手 collision_detection(balls, screen, group) # 按是否碰撞绘制球的颜色 for msg in msgs: # 打印消息 screen.blit(msg[0], msg[1]) pygame.display.flip() # 刷新界面 clock.tick(30) # 数越大越快 def keep_place(glass): # 始终保持鼠标手在摩擦板内 """使得鼠标手在摩擦板内移动""" if glass.mouse_rect.left < glass.glass_rect.left: # 鼠标左边<摩擦板左边,即从左边出去了 glass.mouse_rect.left = glass.glass_rect.left # 让鼠标手保持在左边界 if glass.mouse_rect.left > glass.glass_rect.right - glass.mouse_rect.width: glass.mouse_rect.left = glass.glass_rect.right - glass.mouse_rect.width if glass.mouse_rect.top < glass.glass_rect.top: glass.mouse_rect.top = glass.glass_rect.top if glass.mouse_rect.top > glass.glass_rect.bottom - glass.mouse_rect.height: glass.mouse_rect.top = glass.glass_rect.bottom - glass.mouse_rect.height def collision_detection(balls, screen, group): # 看碰撞情况绘制不同颜色小球 for each in balls: # 遍历小球 each.move() # 移动小球 if each.collide: # 碰撞 each.speed = [randint(1, 10), randint(1, 10)] # 随机生成速度 each.collide = False # 碰撞状态改为False if each.control: # 如果小球被控制 screen.blit(each.greenball_image, each.rect) # 绘制绿色小球 else: # 如果不控制 screen.blit(each.grayball_image, each.rect) # 绘制灰色小球 for each in group: group.remove(each) # 把自身拿出来 if pygame.sprite.spritecollide(each, group, False, pygame.sprite.collide_circle): # 如果自己和别的球碰撞 each.side[0] = -each.side[0] each.side[1] = -each.side[1] # 碰撞后移动方向相反 each.collide = True # 碰撞状态为True if each.control: # 如果是在控制状态下 each.side[0] = -1 each.side[1] = -1 # 移动方向反向 each.control = False # 失去控制,False group.add(each) # 还要把自己放进去
all_events.py
import pygame import sys # 退出需要 from pygame.locals import * # 把pygame的常量名导进去 from temp import motion # 其实这里用到了 def check_all_events(ai_settings, group, balls, msgs): """所有事件""" global motion # 全局变量 for event in pygame.event.get(): # 遍历事件 if event.type == QUIT: # ×掉窗口 pygame.quit() sys.exit() # 退出游戏 elif event.type == ai_settings.GAMEOVER: # 判断事件是否为我们自定义的GAMEOVER事件 fail(ai_settings) # 失败的操作,成功的操作在空格键里面 elif event.type == ai_settings.MYTIMER: # 自定义事件 if motion: # motion不为零 for each in group: # 遍历group if each.check(motion): # 控制住小球 each.speed = [0, 0] # 速度为0 each.control = True # 控制状态为True motion = 0 # motion置零 elif event.type == MOUSEMOTION: # 鼠标事件 motion += 1 # motion+1 elif event.type == KEYDOWN: # 按键事件 check_keydown_events(event, group, ai_settings, balls, msgs) # 按键事件的响应 def fail(ai_settings): # 时间到了,游戏失败 """游戏失败的响应事件""" ai_settings.loser_sound.play() # 失败的声音播放 pygame.time.delay(2000) # 播放2秒暂停 ai_settings.laugh_sound.play() # 笑声播放 pygame.time.delay(2000) # 播放2秒暂停 pygame.quit() sys.exit() # 退出游戏 def check_keydown_events(event, group, ai_settings, balls, msgs): """键盘按下的事件""" check_w_s_a_d_events(event, group) # 按下wsad check_k_space_event(event, group, ai_settings, balls, msgs) # 按下空格键 def check_w_s_a_d_events(event, group): """按下wsad的响应""" if event.key == K_w: # 按下w键 for each in group: # 遍历球 if each.control: # 如果球被控制 each.speed[1] -= 1 # 上移 if event.key == K_s: # 按下s键 for each in group: # 下移 if each.control: each.speed[1] += 1 if event.key == K_a: # 按下a键 for each in group: # 左移 if each.control: each.speed[0] -= 1 if event.key == K_d: # 按下d键 for each in group: # 右移 if each.control: each.speed[0] += 1 def check_k_space_event(event, group, ai_settings, balls, msgs): """按下空格的响应""" if event.key == K_SPACE: # 按下空格键 for each in group: if each.control: for i in ai_settings.hole: # 遍历5个洞 if i[0] <= each.rect.left <= i[1] and \ i[2] <= each.rect.top <= i[3]: # 如果球在其中一个洞里 ai_settings.hole_sound.play() # 进洞声音播放 each.speed = [0, 0] # 固定该小球 group.remove(each) # 删除这个小球 """ 下面两行语句就是完成该小球第一个绘制, 然后其它小球就在该小球上边了 """ temp = balls.pop(balls.index(each)) # 先从temp 中弹出 balls.insert(0, temp) # 然后插入到第一个的位置,就会第一个画了 ai_settings.hole.remove(i) # 删除这个黑洞 if not ai_settings.hole: # 如果洞都满了 win(ai_settings, msgs) # 游戏胜利的事件 def win(ai_settings, msgs): # 胜利的事件 """游戏胜利的事件响应""" pygame.mixer.music.stop() # 停止背景音乐 ai_settings.winner_sound.play() # 播放胜利音效 pygame.time.delay(3000) # 播放音效需要时间,延迟3秒 msgs.append((ai_settings.win_picture.convert_alpha(), ai_settings.win_picture_pos)) # 在指定地址绘制胜利图片 ai_settings.laugh_sound.play() # 播放笑声
glass.py
import pygame class Glass(pygame.sprite.Sprite): # 摩擦板类 def __init__(self, bg_size): # 这两行代码跟前面的一样 pygame.sprite.Sprite.__init__(self) # 初始化动画精灵 """摩擦板""" self.glass_image = pygame.image.load("glass.png").convert_alpha() # 加载摩擦板图像 self.glass_rect = self.glass_image.get_rect() # 获取摩擦板的矩形 self.glass_rect.left, self.glass_rect.top = \ (bg_size[0] - self.glass_rect.width) // 2, \ bg_size[1] - self.glass_rect.height # 矩形位置所在 """鼠标手""" self.mouse_image = pygame.image.load("hand.png").convert_alpha() # 加载手图像 self.mouse_rect = self.mouse_image.get_rect() # 获取手的矩形 self.mouse_rect.left, self.mouse_rect.top = \ self.glass_rect.left, self.glass_rect.top # 矩形位置所在 """设置鼠标不可见""" pygame.mouse.set_visible(False) # 鼠标不可见
ball.py
import pygame from random import * # 随机生成数需要 class Ball(pygame.sprite.Sprite): # 球类,继承自Spirte类 def __init__(self, position, speed, bg_size, target): pygame.sprite.Sprite.__init__(self) # 初始化动画精灵 """" 使用 .convert_alpha() 可以转换像素格式, 提高 blit 的速度 """ self.grayball_image = pygame.image.load("gray_ball.png").convert_alpha() # 加载灰球图片 self.greenball_image = pygame.image.load("green_ball.png").convert_alpha() # 加载绿球图片 self.rect = self.grayball_image.get_rect() # 获取小球图片矩形 self.rect.left, self.rect.top = position # position赋值给矩形位置 """choice() 方法返回一个列表,元组或字符串的随机项。""" self.side = [choice([-1, 1]), choice([-1, 1])] # 移动方向随机 self.speed = speed # 移动速度 self.collide = False # 默认未碰撞 self.target = target # 为每一个小球设定一个不同的目标 """ 5、小球应该添加一个 control 属性, 用于记录当前的状态(绿色 -> 玩家控制 or 灰色 -> 随机移动) """ self.control = False # 默认未控制 self.width, self.height = bg_size[0], bg_size[1] # 窗口的宽高 self.radius = self.rect.width / 2 # 球半径 def move(self): """" 球的移动方法 如果小球的左侧出了边界,那么将小球左侧的位置改为右侧的边界 这样便实现了从左边进入,右边出来的效果 """ if self.control: # 控制 self.rect = self.rect.move(self.speed) # 移动后的矩形位置 else: # 未控制 self.rect = self.rect.move(self.side[0] * self.speed[0], self.side[1] * self.speed[1]) # 随机移动 if self.rect.right <= 0: # 小球右边界<0,即小球出左边 self.rect.left = self.width # 从右边进来 elif self.rect.left >= self.width: # 小球左边界>窗口宽度,即小球出右边 self.rect.right = 0 # 从左边进来 elif self.rect.bottom <= 0: # 小球下边界<0,即小球出上边 self.rect.top = self.height # 从下边出来 elif self.rect.top >= self.height: # 小球上边界>窗口高度 self.rect.bottom = 0 # 从上边出来 def check(self, motion): """" 3、为小球添加一个 check() 方法, 用于判断鼠标在1秒钟内产生的事件数量是否匹配此目标; """ if self.target < motion < self.target + 5: return True else: return False
settings.py
import pygame from pygame.locals import * # 把pygame的常量名导进去 class Settings(): def __init__(self): pygame.init() # 初始化 """所有图片""" self.bg_image = pygame.image.load("background.png") # 背景图像 self.win_picture = pygame.image.load("win.png") # 胜利的图片 self.bg_size = self.width, self.height = 1024, 681 # 窗口尺寸 self.win_picture_pos = \ (self.width - self.win_picture.get_width()) // 2, \ (self.height - self.win_picture.get_height()) // 2 # 显示胜利图像的位置 """添加音效""" self.loser_sound = pygame.mixer.Sound("fail.ogg") # 失败的时候的声音 self.laugh_sound = pygame.mixer.Sound("laugh.ogg") # 嘲笑的声音 self.winner_sound = pygame.mixer.Sound("win.ogg") # 成功的时候的声音 self.hole_sound = pygame.mixer.Sound("hole.ogg") # 入洞声音 """自定义事件""" self.GAMEOVER = USEREVENT # 音乐播放完时游戏结束 self.MYTIMER = USEREVENT + 1 # 每一秒钟触发一次 self.hole = [(115, 121, 197, 203), (223, 229, 388, 394), (501, 507, 318, 324), (696, 702, 190, 196), (904, 910, 417, 423)] # 黑洞范围(x1, x2, y1, y2) def play_bg_music(self): """添加背景音乐""" pygame.mixer.music.load("bg_music.ogg") # 加载背景音乐 pygame.mixer.music.set_volume(0.2) # 设置音量 pygame.mixer.music.play() # 播放背景音乐