Pygame开发国际象棋GUI报错:pygame.Surface对象不可下标
报错根源
TypeError: 'pygame.Surface' object is not subscriptable的核心原因是图片加载逻辑错误,覆盖了原本用来存所有棋子图的字典变量:
你初始化images为存储棋子图片的空字典,但循环加载图片时,每次都直接给images变量整体赋值为缩放后的单个图片Surface,循环结束后images根本不是字典,只是最后一张加载的图片对象,后续用images[key]的字典下标方式取值,自然会触发Surface对象不支持下标访问的错误。
除了这个直接触发报错的问题,代码里还有3个会导致功能异常的连带bug:
- 取图片时拼接的key多写了
.png后缀,和字典里存储的key不匹配 - 棋子绘制代码写在主循环外,主循环启动后第一帧就会用
screen.fill()把之前画的棋子全部覆盖,棋子根本显示不出来 - 主循环写了两个独立的事件捕获逻辑,会导致事件队列被重复消费,窗口关闭、鼠标点击的响应可能异常;同时棋子绘制的坐标行列计算颠倒,棋子会错位。
修复步骤
- 修正图片加载逻辑,把每张缩放后的棋子图按对应名称作为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
相关产品推荐
相关产品推荐

