Pygame地图点击重复触发问题求助:clicked变量失效
Grid Wars INDEV点击事件重复触发问题修复
问题根源
- 主循环每帧调用
isClicked(),而pygame.mouse.get_pressed()在鼠标按住时会持续返回True,导致每帧都触发点击逻辑,出现重复注册。 isClicked()遍历所有tile时,每个碰撞的tile都会修改self.clicked和self.action,逻辑混乱;且最后返回的tile[2]是遍历的最后一个tile类型,并非实际点击的tile。- 没有利用Pygame的事件系统处理单次点击,而是用状态轮询,这是重复触发的核心原因。
修复方案
1. 修改主代码,用事件系统处理点击
把点击检测移到事件循环里,利用MOUSEBUTTONDOWN事件确保每次点击只触发一次:
import pygame from world import World pygame.init() screen_width = 1500 screen_height = 650 screen = pygame.display.set_mode((screen_width, screen_height)) pygame.display.set_caption('Grid Wars INDEV') world = World(screen) tile_size = 50 lineAmount = 1300/50 def draw_grid(): for line in range(1,25): pygame.draw.line(screen, (218,165,32), (200, line * tile_size), (1350, line * tile_size), 2) keyline = line + 3 pygame.draw.line(screen, (218,165,32), (keyline * tile_size, 0), (keyline * tile_size, 650), 2) run = True while run: screen.fill("red") world.draw() draw_grid() pygame.draw.line(screen, (218,165,32), (200,5), (1350,5), 10) pygame.draw.line(screen, (218,165,32), (200,645), (1350, 645), 10) pygame.draw.line(screen, (218,165,32), (200,0), (200, 650), 10) pygame.draw.line(screen, (218,165,32), (1350,0), (1350, 650), 10) for event in pygame.event.get(): if event.type == pygame.QUIT: run = False # 处理鼠标左键点击事件 if event.type == pygame.MOUSEBUTTONDOWN and event.button == 1: tile_type = world.check_clicked_tile(event.pos) if tile_type: print('Hello World') print(tile_type) pygame.display.update() pygame.quit()
2. 修改World类,添加单次点击检测方法
移除原来的isClicked(),替换为check_clicked_tile(),仅在点击事件触发时调用,返回被点击的tile类型:
import pygame from button import Button class World: def __init__(self, screen) -> None: self.name_list = [] self.screen = screen map_data = [ [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1], [1,1,1,1,1,1,1,1,1,1,1,0,0,0,0,0,0,0,0,1,1,1,1], [1,0,0,0,0,1,0,1,1,1,0,1,1,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,1,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,1], [1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,1,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [1,1,1,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0], [1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1], [0,1,1,1,1,1,0,0,0,1,1,0,0,1,1,1,1,0,0,0,0,0,1], [1,1,1,1,1,1,1,0,1,1,1,0,0,1,1,1,1,1,1,1,0,1,1] ] ocean_img = pygame.image.load('ocean.png') grass_img = pygame.image.load('grass.png') row_count = 0 for row in map_data: column_count = 0 for tile in row: if tile == 1: img = pygame.transform.scale(ocean_img, (50,50)) img_rect = img.get_rect() img_rect.x = column_count * 50 + 200 img_rect.y = row_count * 50 tile_data = (img, img_rect,'ocean') self.name_list.append(tile_data) if tile == 0: img = pygame.transform.scale(grass_img, (50,50)) img_rect = img.get_rect() img_rect.x = column_count * 50 + 200 img_rect.y = row_count * 50 tile_data = (img, img_rect,'grass') self.name_list.append(tile_data) column_count += 1 row_count += 1 def draw(self): for tile in self.name_list: self.screen.blit(tile[0], tile[1]) def check_clicked_tile(self, pos): # 遍历所有tile,检测点击位置是否碰撞 for tile in self.name_list: if tile[1].collidepoint(pos): return tile[2] # 没点击到任何tile返回None return None
关键修改说明
- 改用
MOUSEBUTTONDOWN事件:该事件仅在鼠标按键按下的瞬间触发一次,彻底解决重复注册问题。 - 移除冗余状态变量:不再需要维护
clicked和action,事件驱动逻辑更可靠。 - 修复tile类型返回错误:现在返回的是实际被点击的tile类型,而非遍历的最后一个。
- 分离点击检测逻辑:将点击检测放在事件处理流程中,避免每帧轮询导致的重复触发。
内容的提问来源于stack exchange,提问作者Aditya Bhadra
相关产品推荐
相关产品推荐

