You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 23:40:42