如何在Pygame中批量检测关卡按钮图片的点击事件?
问题:Pygame中批量实现关卡按钮的点击检测
我在Pygame的关卡界面里用图片作为关卡按钮,每页15个,已经通过迭代和计算用5×3的布局绘制到屏幕上了,绘制代码如下:
for i, lvl in enumerate(self.levels_p1, start=1): x = ((WIDTH - 100) * (i % 5) // 6) + 17 y = HEIGHT // 10 + ((i // 5) * 125) if i % 5 == 0: x = ((WIDTH - 100) * 5 // 6) + 17 y = HEIGHT // 10 + (((i // 5) - 1) * 125) self.screen.blit(lvl, (x, y)) if self.level_unlocked < i: self.screen.blit(self.level_shade, (x, y))
其中self.levels_p1是包含15张关卡图片的列表。
目前我是手动定义每个按钮的rect来检测点击,但不想重复15次var = get_rect操作。现有的点击检测代码片段如下:
mousepos = pg.mouse.get_pos() for event in pg.event.get(): if event.type == pg.QUIT: pg.quit() if event.type == pg.MOUSEBUTTONDOWN: # 返回菜单 if self.back_rect.collidepoint(*mousepos): on_levels = False self.swipe.play() self.start() # 跳转到第二页关卡 if self.arrow_rect.collidepoint(*mousepos): on_levels = False self.swipe.play() self.levels_page2() # 进入关卡1 if self.l1_rect.collidepoint(*mousepos): on_levels = False self.swipe.play() self.load_level(1)
我希望能像批量绘制按钮那样,实现批量的点击检测,请问有什么合适的方法?
解决方案:批量管理关卡按钮的Rect与点击逻辑
这个问题很好解决,核心思路就是把每个关卡的位置信息(Rect)和对应的关卡编号绑定起来,统一存储和遍历,就能实现和绘制逻辑同步的批量检测了,具体步骤如下:
1. 同步存储关卡的Rect与编号
在绘制关卡按钮的循环里,顺便计算每个按钮的rect,并把rect和对应的关卡编号一起存入一个列表。这样就不用手动一个个定义l1_rect、l2_rect这类变量了:
# 先初始化一个空列表,用来存储每个关卡的(rect, 关卡编号) self.level_rects = [] for i, lvl in enumerate(self.levels_p1, start=1): x = ((WIDTH - 100) * (i % 5) // 6) + 17 y = HEIGHT // 10 + ((i // 5) * 125) if i % 5 == 0: x = ((WIDTH - 100) * 5 // 6) + 17 y = HEIGHT // 10 + (((i // 5) - 1) * 125) # 计算当前关卡图片的rect,用topleft定位更准确 lvl_rect = lvl.get_rect(topleft=(x, y)) # 将rect和关卡编号存入列表 self.level_rects.append( (lvl_rect, i) ) # 绘制关卡按钮 self.screen.blit(lvl, lvl_rect) # 绘制锁层遮罩(直接用lvl_rect,不用再传x,y) if self.level_unlocked < i: self.screen.blit(self.level_shade, lvl_rect)
2. 批量检测关卡点击事件
在点击检测的逻辑里,遍历刚才存储的level_rects列表,就能批量判断点击是否命中某个关卡按钮了,还能顺便判断关卡是否解锁:
mousepos = pg.mouse.get_pos() for event in pg.event.get(): if event.type == pg.QUIT: pg.quit() if event.type == pg.MOUSEBUTTONDOWN: # 保留原有返回菜单、翻页的逻辑 if self.back_rect.collidepoint(*mousepos): on_levels = False self.swipe.play() self.start() if self.arrow_rect.collidepoint(*mousepos): on_levels = False self.swipe.play() self.levels_page2() # 批量检测关卡按钮点击 for lvl_rect, level_num in self.level_rects: # 先判断关卡是否解锁,再判断是否点击命中 if self.level_unlocked >= level_num and lvl_rect.collidepoint(*mousepos): on_levels = False self.swipe.play() self.load_level(level_num) break # 一次点击只触发一个关卡,找到后就退出循环,避免重复触发
额外小优化
- 绘制遮罩时直接用
lvl_rect代替(x,y),代码更简洁,也避免坐标不一致的问题; - 遍历检测时加上
break,因为点击位置只会命中一个按钮,找到后就停止遍历,提升一点效率。
内容的提问来源于stack exchange,提问作者Grave
相关产品推荐
相关产品推荐

