如何深度复制含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
相关产品推荐
相关产品推荐

