Pygame重叠矩形(卡牌)点击高亮异常问题求助
问题:点击重叠卡牌时所有重叠卡牌都被高亮,如何仅高亮被点击的卡牌?
我是Pygame新手,目前处于实验阶段。我创建了一个简单的显示表面,在上面渲染了多个尺寸为96×144的不同颜色重叠矩形以模拟卡牌。我编写了代码,期望点击卡牌时用黄色高亮该卡牌,但运行代码后发现,点击某张卡牌的可见区域时,其前后所有重叠的卡牌都会被高亮。我无法解决这个问题,希望得到帮助实现仅高亮被点击卡牌的功能。
原代码如下:
import pygame, sys class Card(pygame.sprite.Sprite): def __init__(self, color): super().__init__() self.color = color self.is_highlight = False def show_card(self, x, y): self.rect = pygame.rect.Rect(x, y, 96, 144) pygame.draw.rect(display_surf, self.color, self.rect) def highlight_card(self): pos = pygame.mouse.get_pos() if self.rect.collidepoint(pos): self.is_highlight = True else: self.is_highlight = False def update(self): if self.is_highlight: pygame.draw.rect(display_surf, 'Yellow', self.rect.inflate(5, 5), width=3, border_radius=5) class Deck(pygame.sprite.Sprite): def __init__(self): super().__init__() self.card_deck = [] def build_deck(self): self.card_deck.append(Card('Green')) self.card_deck.append(Card('Red')) self.card_deck.append(Card('Blue')) self.card_deck.append(Card('brown')) self.card_deck.append(Card('cadetblue')) self.card_deck.append(Card('cornsilk')) self.card_deck.append(Card('darkolivegreen')) self.card_deck.append(Card('darkorchid')) self.card_deck.append(Card('darksalmon')) return self.card_deck pygame.init() WINDOW_WIDTH = 1280 WINDOW_HEIGHT = 720 display_surf = pygame.display.set_mode((WINDOW_WIDTH,WINDOW_HEIGHT)) pygame.display.set_caption('Simple Card Game') clock = pygame.time.Clock() card_deck = Deck().build_deck() while True: display_surf.fill((0, 150,0)) distance = 20 for card in card_deck: card.show_card(distance, 20) distance += 20 for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() if event.type == pygame.MOUSEBUTTONDOWN: for card in card_deck: card.highlight_card() for card in card_deck: card.update() pygame.display.update()
解决方案
问题核心是:重叠卡牌的rect都包含点击坐标,遍历所有卡牌时所有符合碰撞条件的都会被设为高亮。我们需要找到最上层的卡牌(最后绘制的那张,因为绘制顺序是后绘制的叠在上方),仅高亮它,其余卡牌取消高亮。
修改后的完整代码:
import pygame, sys class Card(pygame.sprite.Sprite): def __init__(self, color): super().__init__() self.color = color self.is_highlight = False self.rect = None # 初始化rect属性 def show_card(self, x, y): self.rect = pygame.rect.Rect(x, y, 96, 144) pygame.draw.rect(display_surf, self.color, self.rect) # 改为接收鼠标位置与高亮状态参数,逻辑更直接 def set_highlight(self, highlight): self.is_highlight = highlight def update(self): if self.is_highlight: pygame.draw.rect(display_surf, 'Yellow', self.rect.inflate(5, 5), width=3, border_radius=5) # Deck仅作为卡牌容器,无需继承Sprite class Deck: def __init__(self): self.card_deck = [] def build_deck(self): self.card_deck.append(Card('Green')) self.card_deck.append(Card('Red')) self.card_deck.append(Card('Blue')) self.card_deck.append(Card('brown')) self.card_deck.append(Card('cadetblue')) self.card_deck.append(Card('cornsilk')) self.card_deck.append(Card('darkolivegreen')) self.card_deck.append(Card('darkorchid')) self.card_deck.append(Card('darksalmon')) return self.card_deck pygame.init() WINDOW_WIDTH = 1280 WINDOW_HEIGHT = 720 display_surf = pygame.display.set_mode((WINDOW_WIDTH,WINDOW_HEIGHT)) pygame.display.set_caption('Simple Card Game') clock = pygame.time.Clock() card_deck = Deck().build_deck() while True: display_surf.fill((0, 150,0)) distance = 20 for card in card_deck: card.show_card(distance, 20) distance += 20 for event in pygame.event.get(): if event.type == pygame.QUIT: pygame.quit() sys.exit() if event.type == pygame.MOUSEBUTTONDOWN: mouse_pos = pygame.mouse.get_pos() clicked = False # 从最上层卡牌(最后绘制的)开始遍历 for card in reversed(card_deck): if card.rect.collidepoint(mouse_pos): card.set_highlight(True) clicked = True else: card.set_highlight(False) # 找到第一个碰撞的卡牌后停止遍历,避免下层卡牌被误判 if clicked: break for card in card_deck: card.update() pygame.display.update() clock.tick(60) # 添加帧率控制,稳定游戏运行
关键改动说明
- 点击逻辑优化:用
reversed()从最上层卡牌开始遍历,找到第一个碰撞的卡牌后仅高亮它,其余全部取消,找到后立即跳出循环减少无效操作 - 方法简化:将
highlight_card改为set_highlight,直接接收高亮状态,避免重复获取鼠标位置的冗余逻辑 - 冗余继承移除:
Deck仅作为容器,不需要继承pygame.sprite.Sprite,精简代码结构 - 帧率控制:加入
clock.tick(60)稳定游戏帧率,避免不必要的性能消耗
内容的提问来源于stack exchange,提问作者Serban Spirescu
相关产品推荐
相关产品推荐

