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

Pygame居中网格点击报错:IndexError列表索引越界问题排查

问题分析与解决方案

核心问题原因

  1. 鼠标坐标未转换为网格相对坐标:当前直接用窗口全局坐标计算行列,但网格是从gridFrameX和gridFrameY位置开始绘制的,导致点击网格区域时,计算出的gridRow/gridCol与实际网格行列不匹配,甚至超出网格尺寸范围。
  2. 未限制点击范围:点击网格外区域时,计算出的行列会超出gridPuzzle的索引范围,直接访问就会触发IndexError。

修改步骤

1. 转换鼠标坐标为网格内部相对坐标

获取鼠标位置后,先减去网格的起始坐标,得到网格内的相对位置,再用这个相对位置计算行列:

x_rel = x - gridFrameX
y_rel = y - gridFrameY
gridCol = x_rel // blockSize
gridRow = y_rel // blockSize

2. 增加点击有效性判断

只有当点击位置确实在网格范围内时,才执行瓦片切换操作,避免越界访问:

if 0 <= x_rel < gridFrame and 0 <= y_rel < gridFrame:
    if 0 <= gridRow < gridSize and 0 <= gridCol < gridSize:
        gridPuzzle[gridRow][gridCol] = 1 - gridPuzzle[gridRow][gridCol]

3. 修复递归重置问题(额外优化)

原代码按R键会递归调用drawGrid(),导致多个循环嵌套,改为直接重置gridPuzzle即可:

if event.key == pygame.K_r:
    gridPuzzle = [[0] * gridSize for _ in range(gridSize)]
    gridPuzzle[0][0] = 1

4. 修正全局变量访问

quit()函数中需要声明running为全局变量,否则无法正确终止主循环:

def quit():
    global running
    running = False
    pygame.quit()

修改后的完整代码

import pygame

pygame.init()
pygame.font.init()

colorBlack = (0, 0, 0); colorWhite = (255, 255, 255); colorRed = (255, 0, 0)

winWidth = 1280; winHeight = 720; FPS = 30
winDisplay = pygame.display.set_mode((winWidth, winHeight))
FPSClock = pygame.time.Clock()
running = True

def drawGrid():
    blockSize = 47 # 单个网格块像素尺寸
    gridSize = 10 # 网格行列数(10x10)
    gridFrame = 479 # 网格框架总像素尺寸
    gridFrameX = 501 # 网格框架X起始坐标
    gridFrameY = 221 # 网格框架Y起始坐标
    gridFrameRect = (gridFrameX, gridFrameY, gridFrame, gridFrame) # 网格框架矩形
    gridSolution = [[0] * gridSize for _ in range(gridSize)] # 网格答案数组
    gridPuzzle = [[0] * gridSize for _ in range(gridSize)] # 网格谜题数组

    gridPuzzle[0][0] = 1 # 初始化第一个单元格为红色

    while running:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                quit()
            
            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    quit()
                if event.key == pygame.K_r:
                    # 重置网格,替代递归调用
                    gridPuzzle = [[0] * gridSize for _ in range(gridSize)]
                    gridPuzzle[0][0] = 1
            
            if event.type == pygame.MOUSEBUTTONDOWN:
                x, y = pygame.mouse.get_pos()
                print("鼠标位置: ", x, y)
                # 转换为网格内部相对坐标
                x_rel = x - gridFrameX
                y_rel = y - gridFrameY
                # 判断点击是否在网格范围内
                if 0 <= x_rel < gridFrame and 0 <= y_rel < gridFrame:
                    gridRow = y_rel // blockSize
                    gridCol = x_rel // blockSize
                    # 确保行列索引有效
                    if 0 <= gridRow < gridSize and 0 <= gridCol < gridSize:
                        gridPuzzle[gridRow][gridCol] = 1 - gridPuzzle[gridRow][gridCol]
                        print("切换网格单元格: ", gridRow, gridCol)
        
        # 绘制左侧和顶部黑色区域
        pygame.draw.rect(winDisplay, colorBlack, (0, 0, 501, winHeight))
        pygame.draw.rect(winDisplay, colorBlack, (501, 0, 772, 221))

        # 绘制网格单元格
        for gameRow in range(gridSize):
            for gameCol in range(gridSize):
                rect = (gridFrameX + gameCol * blockSize, gridFrameY + gameRow * blockSize, blockSize, blockSize)
                pygame.draw.rect(winDisplay, colorBlack, rect, 1) # 绘制单元格边框
                if gridPuzzle[gameRow][gameCol] == 1:
                    pygame.draw.rect(winDisplay, colorRed, rect) # 填充红色
                else:
                    pygame.draw.rect(winDisplay, colorWhite, rect) # 填充白色
        
        # 绘制网格框架边框
        pygame.draw.rect(winDisplay, colorBlack, gridFrameRect, 1)
        pygame.display.update()
        FPSClock.tick(FPS)

def quit():
    global running
    running = False
    pygame.quit()

if __name__ == "__main__":
    drawGrid()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.13 11:10:54