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

如何深度复制含Pygame Surface的棋子类列表?遇pickle错误

问题:Pygame国际象棋游戏添加图像后,deepcopy棋子列表报错

在重写国际象棋游戏并添加Pygame图像资源后,尝试复制存储棋子的列表时出现以下错误:

TypeError: cannot pickle 'pygame.surface.Surface' object

原本用黑白圆圈加首字母表示棋子,现在为每个棋子对象关联了Pygame加载的Surface图像(如W_KING = pygame.transform.scale(pygame.image.load('assets/w_king.png'), (60, 60))),在Board类的draw_board方法中,为了翻转棋盘显示,使用copy.deepcopy(self.board)复制棋盘时触发了上述错误。

相关核心代码如下:

Piece父类

class Piece():
    
    def __init__(self, color):
        self.row = 0
        self.col = 0
        self.color = color
        self.x = 0
        self.y = 0
        self.calculate_position()

    def calculate_position(self):
        self.x = SQUARE_SIZE * self.col + SQUARE_SIZE // 2 + PADDING
        self.y = SQUARE_SIZE * self.row + SQUARE_SIZE // 2 + PADDING
        
    def assign_location(self, row, col):
        self.row = row
        self.col = col
        self.calculate_position()

    def draw_piece(self, win):
        x = self.x - self.image.get_width()//2
        y = self.y - self.image.get_height()//2
        if self.initial == "P":
            y = self.y - 21
        if self.initial == "R":
            y = self.y - 26
        win.blit(self.image, (x, y))

King子类示例

class King(Piece):
    def __init__(self, color):
        super().__init__(color)
        
        self.row = 0
        self.col = 0
        self.initial = "K"
        self.value = 0
        self.moves_made = 0

        if self.color == WHITE:
            self.image = W_KING
        else:
            self.image = B_KING

报错的draw_board片段

# Draw pieces to squares on board
if self.flipped_board == True:
    board_copy = copy.deepcopy(self.board)
    for row in board_copy:
        row.reverse()
    board_copy.reverse()
    board = board_copy
    # iterate through board_copy assigning pieces their row and column location 
    for row in range(ROWS):
        for col in range(COLS):
            square = board[row][col]
            if square != 0:
                square.assign_location(row, col)
else:
    board = self.board

错误原因

copy.deepcopy的工作原理是通过pickle序列化对象来创建完全独立的副本,但Pygame的pygame.surface.Surface对象是和底层图形硬件绑定的资源,无法被pickle序列化。当deepcopy尝试复制包含Surface属性的Piece对象时,就会抛出这个错误。

你的需求是翻转棋盘显示,完全不需要复制整个棋子对象——复制棋子不仅浪费性能,还会导致原对象的位置被意外修改(浅拷贝会直接修改原对象,深拷贝又因Surface无法序列化报错)。


解决方案

不需要复制棋盘和棋子,只需要在绘制时计算翻转后的坐标即可,直接复用原有的棋子对象,修改绘制逻辑:

# 替换原有的绘制棋子循环
for row in range(ROWS):
    for col in range(COLS):
        square = self.board[row][col]
        if square != 0:
            # 计算翻转后的坐标
            if self.flipped_board:
                # 翻转行和列:原row对应7-row,原col对应7-col
                flipped_row = 7 - row
                flipped_col = 7 - col
                # 计算翻转后的绘制位置
                x = SQUARE_SIZE * flipped_col + SQUARE_SIZE // 2 + PADDING
                y = SQUARE_SIZE * flipped_row + SQUARE_SIZE // 2 + PADDING
            else:
                x = square.x
                y = square.y
            
            # 调整图像偏移(保持原有的偏移逻辑)
            draw_x = x - square.image.get_width()//2
            draw_y = y - square.image.get_height()//2
            if square.initial == "P":
                draw_y = y - 21
            if square.initial == "R":
                draw_y = y - 26
            win.blit(square.image, (draw_x, draw_y))

移除原来的deepcopy相关代码,这样既避免了序列化错误,又节省了内存和性能。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.21 17:42:07