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

Pygame开发国际象棋GUI报错:pygame.Surface对象不可下标

报错根源

TypeError: 'pygame.Surface' object is not subscriptable的核心原因是图片加载逻辑错误,覆盖了原本用来存所有棋子图的字典变量:
你初始化images为存储棋子图片的空字典,但循环加载图片时,每次都直接给images变量整体赋值为缩放后的单个图片Surface,循环结束后images根本不是字典,只是最后一张加载的图片对象,后续用images[key]的字典下标方式取值,自然会触发Surface对象不支持下标访问的错误。

除了这个直接触发报错的问题,代码里还有3个会导致功能异常的连带bug:

  1. 取图片时拼接的key多写了.png后缀,和字典里存储的key不匹配
  2. 棋子绘制代码写在主循环外,主循环启动后第一帧就会用screen.fill()把之前画的棋子全部覆盖,棋子根本显示不出来
  3. 主循环写了两个独立的事件捕获逻辑,会导致事件队列被重复消费,窗口关闭、鼠标点击的响应可能异常;同时棋子绘制的坐标行列计算颠倒,棋子会错位。

修复步骤
  • 修正图片加载逻辑,把每张缩放后的棋子图按对应名称作为key存入字典,不要直接覆盖整个images变量:
    images = {}
    for piece in image_names:
        images[piece] = p.transform.scale(p.image.load(piece + ".png"), (64, 64))
    
  • 修正取图的key值,去掉多余的.png后缀,和存储时的key保持一致:
    current_key = color_for_dict + piece_for_dict
    
  • 把棋子绘制逻辑挪到主循环内、棋盘格子绘制完成之后,同时修正坐标计算,对齐格子左上角,保证棋子不偏移、不被背景覆盖
  • 合并主循环里重复的事件捕获代码,避免事件丢失

修复后可运行完整代码
import pygame as p

p.init()
board = [
    [['rook', 'white', False], ['knight', 'white'], ['bishop', 'white'], ['king', 'white', False], ['queen', 'white'],
     ['bishop', 'white'], ['knight', 'white'], ['rook', 'white', False]],
    [['pawn', 'white'], ['pawn', 'white'], ['pawn', 'white'], ['pawn', 'white'], ['pawn', 'white'],
     ['pawn', 'white'], ['pawn', 'white'], ['pawn', 'white']],
    ['_____', '_____', '_____', '_____', '_____', '_____', '_____', '_____'],
    ['_____', '_____', '_____', '_____', '_____', '_____', '_____', '_____'],
    ['_____', '_____', '_____', '_____', '_____', '_____', '_____', '_____'],
    ['_____', '_____', '_____', '_____', '_____', '_____', '_____', '_____'],
    [['pawn', 'black'], ['pawn', 'black'], ['pawn', 'black'], ['pawn', 'black'], ['pawn', 'black'],
     ['pawn', 'black'], ['pawn', 'black'], ['pawn', 'black']],
    [['rook', 'black', False], ['knight', 'black'], ['bishop', 'black'], ['king', 'black', False],
     ['queen', 'black'],
     ['bishop', 'black'], ['knight', 'black'], ['rook', 'black', False]]
]
dict_colors = {"white": "w", "black": "b"}
dict_pieces = {"rook": "R", "knight": "N", "bishop": "B", "king": "K", "queen": "Q", "pawn": "p"}
image_names = ['wp', 'wN', 'wB', 'wR', 'wQ', 'wK', 'bp', 'bN', 'bB', 'bR', 'bQ', 'bK']
images = {}
for piece in image_names:
    images[piece] = p.transform.scale(p.image.load(piece + ".png"), (64, 64))


def position_square(position):
    row_p = position[0]
    column_p = position[1]
    row = 0
    column = 0
    for i in range(8):
        if 100 + i * 64 <= row_p < 100 + (i + 1) * 64:
            column = 7 - i
        if 100 + i * 64 <= column_p < 100 + (i + 1) * 64:
            row = 7 - i
    square = [row, column]
    return square


screen = p.display.set_mode((712, 712))
square_side = 512 / 8
running = True
while running:
    # 合并事件捕获逻辑
    for event in p.event.get():
        if event.type == p.QUIT:
            running = False
        if event.type == p.MOUSEBUTTONUP:
            position = p.mouse.get_pos()
            square = position_square(position)
            print(square)
            
    screen.fill((0, 0, 0))
    color_1 = p.Color(131, 145, 240)
    color_2 = p.Color(225, 229, 250)
    # 先绘制棋盘格子
    for i in range(len(board)):
        for v in range(len(board[i])):
            if (i + v) % 2 == 0:
                p.draw.rect(screen, color_2, p.Rect(100 + (v * square_side), 100 + (i * square_side), square_side,
                                                    square_side))
            else:
                p.draw.rect(screen, color_1, p.Rect(100 + (v * square_side), 100 + (i * square_side), square_side,
                                                    square_side))
    # 再绘制棋子,保证不被背景覆盖
    for i in range(8):
        for v in range(8):
            current_piece = board[i][v]
            if current_piece != '_____':
                color_for_dict = dict_colors.get(current_piece[1])
                piece_for_dict = dict_pieces.get(current_piece[0])
                current_key = color_for_dict + piece_for_dict
                current_x = 100 + v * square_side
                current_y = 100 + i * square_side
                screen.blit(images[current_key], (current_x, current_y))
    p.display.update()

p.quit()

运行前确保所有棋子png图片和脚本文件放在同一目录下,文件名和image_names列表里的命名完全一致。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 16:51:17