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

Pygame相邻Tile点击时Sprite消失的Bug修复咨询

问题与解决方案:Pygame Tile点击Bug修复

问题现象

  • 点击相邻两个Tile的中间位置时,一个Tile正常响应,另一个会莫名从屏幕消失
  • tileGroup中的Sprite数量从3变为2,但记录占用位置的taken列表仍显示有3个位置被占用
  • 点击消失Tile对应的空位,可重新触发该Tile显示

问题根源

核心问题出在cursor.destroyTile()方法里的pygame.sprite.spritecollide调用:

  • 当鼠标点击相邻Tile中间时,光标Sprite的矩形会同时和两个Tile的矩形发生碰撞
  • spritecollide的第三个参数设为True,会删除所有碰撞到的Sprite,导致误删了未被点击的Tile
  • 后续handleTiles()只从taken列表移除了一个位置,造成taken计数和实际Sprite数量不匹配

修复方案

  1. 替换碰撞检测逻辑:不再用光标Sprite做碰撞判断,直接根据鼠标点击位置计算对应的Tile坐标,精准删除目标Tile
  2. 确保taken列表和tileGroup的状态完全同步

修改后的完整代码

import pygame
import random
import sys

# 所有Tile的可能位置
grid = [[0,0],  [0,150],  [0,300],  [0,450],  [0,600],
        [150,0],[150,150],[150,300],[150,450],[150,600],
        [300,0],[300,150],[300,300],[300,450],[300,600],
        [450,0],[450,150],[450,300],[450,450],[450,600],
        [600,0],[600,150],[600,300],[600,450],[600,600]]
taken = []

# 类定义
class Cursor(pygame.sprite.Sprite):
    def __init__(self, pic):
        super().__init__()
        self.image = pygame.image.load(pic).convert_alpha()
        self.image = pygame.transform.scale(self.image, (50,50))
        self.rect = self.image.get_rect()

    def update(self):
        self.rect.topleft = pygame.mouse.get_pos()  

class Tiles(pygame.sprite.Sprite):
    def __init__(self, tileSize, color, x, y):
        super().__init__()
        self.image = pygame.Surface((tileSize, tileSize))
        self.image.fill(color)
        self.rect = self.image.get_rect()
        self.rect.topleft = (x, y)
        # 记录Tile的坐标,方便后续精准匹配
        self.pos = (x, y)

def drawTiles():
    while len(taken) != 3:
        m = random.randint(0,24)
        pos = grid[m]
        if pos not in taken:
            blackTile = Tiles(150, black, pos[0], pos[1])
            blackTile.add(tileGroup)   
            taken.append(pos)
        
def handleTiles(clicked_pos):
    taken.remove(clicked_pos)
    drawTiles()   

# 颜色定义
white = (255, 255, 255)
black = (0, 0, 0)
red = (255, 0, 0)
blue = (0, 0, 255)
grey = (46, 46, 46)

# 初始化Pygame
pygame.init()
clock = pygame.time.Clock()

# 屏幕设置
screenWidth = 750
screenHeight = 900
screen = pygame.display.set_mode((screenWidth, screenHeight))
pygame.display.set_caption("Tiles Game")
whiteSurface = pygame.Surface((750, 750))
whiteSurface.fill(white)
pygame.mouse.set_visible(False)

# 蓝色分隔线
line = pygame.Surface((750, 10))
line.fill(blue)

# 精灵组
tileGroup = pygame.sprite.Group()
cursor = Cursor("cursor.png")
cursorGroup = pygame.sprite.Group()
cursorGroup.add(cursor)

score = 0

drawTiles()
while True:
    clock.tick(60)

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        if event.type == pygame.MOUSEBUTTONDOWN:
            score += 1
            print(score)
            print(taken)
            print(tileGroup) 
            
            # 计算点击的Tile坐标(仅处理网格内的点击)
            mx, my = pygame.mouse.get_pos()
            if mx < 750 and my <750:
                x = (mx // 150) * 150
                y = (my // 150) * 150
                clicked_pos = [x, y]
                
                # 精准删除对应位置的Tile
                for tile in tileGroup:
                    if tile.pos == tuple(clicked_pos):
                        tile.kill()
                        break
                
                handleTiles(clicked_pos)
        

    # 绘制背景
    screen.fill(grey)
    screen.blit(whiteSurface, (0,0))
    screen.blit(line, (0,750))
    
    tileGroup.draw(screen)
    cursorGroup.draw(screen)
    cursorGroup.update()

    pygame.display.update()

关键修改说明

  • 给Tiles类添加self.pos属性,存储Tile的坐标,用于后续精准匹配
  • 删除了Cursor类中的destroyTile方法,改用点击坐标直接定位目标Tile
  • 点击事件中用整数除法//计算网格坐标,避免取模带来的边界判断问题
  • 遍历tileGroup找到对应坐标的Tile并删除,确保只移除被点击的那个Tile
  • 简化drawTiles函数的逻辑,直接用len(taken)判断是否需要生成新Tile

内容的提问来源于stack exchange,提问作者fev31

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 05:30:47