Python Pygame开发NES风格游戏时数组意外同步赋值问题排查
问题描述
用Python结合Pygame开发NES风格游戏,将关卡数据存储在二维数组中。每个关卡包含三个独立数组:
- collisionData:记录所用方块
- tileset:记录方块调色板
- flipmap:记录方块镜像
已实现通过修改数组数值实现方块动画的功能,但执行代码时,本应仅修改目标数组,却意外同时改动了三个数组。怀疑是数组内存引用关联导致,但未找到原因,请求协助排查。
相关代码:
if Datafile["TileAnimations"][self.animList[item][2]][self.animFrames[item]][0] == "Layout": self.collisionData[self.animList[item][1]][self.animList[item][0]] = Datafile["TileAnimations"][self.animList[item][2]][self.animFrames[item]][1] elif Datafile["TileAnimations"][self.animList[item][2]][self.animFrames[item]][0] == "FlipMap": self.flipmap[self.animList[item][1]][self.animList[item][0]] = Datafile["TileAnimations"][self.animList[item][2]][self.animFrames[item]][1] elif Datafile["TileAnimations"][self.animList[item][2]][self.animFrames[item]][0] == "Tileset": self.tileset[self.animList[item][1]][self.animList[item][0]] = Datafile["TileAnimations"][self.animList[item][2]][self.animFrames[item]][1]
排查思路与解决方案
你遇到的问题确实是Python二维数组的内存引用共享导致的,问题根源大概率不在你提供的这段修改代码里,而是出在三个数组的初始化阶段。
常见错误初始化场景
- 用乘法批量创建二维数组
比如这样的写法:
rows, cols = 10, 10 self.collisionData = [[0]*cols]*rows self.tileset = [[0]*cols]*rows self.flipmap = [[0]*cols]*rows
这种方式会让数组的每一行都指向同一个列表对象,修改任意一行的元素会同步影响所有行;如果三个数组用了完全相同的生成逻辑,甚至会让三个数组本身指向同一内存块。
- 直接赋值共享引用
如果初始化时写了类似代码:
self.collisionData = level_source_data self.tileset = self.collisionData self.flipmap = self.collisionData
这会让三个变量指向同一个二维数组对象,修改其中任何一个都会同步改变另外两个。
解决方法
- 正确初始化独立二维数组
用列表推导式创建数组,确保每一行都是全新的列表:
rows, cols = 10, 10 self.collisionData = [[0 for _ in range(cols)] for _ in range(rows)] self.tileset = [[0 for _ in range(cols)] for _ in range(rows)] self.flipmap = [[0 for _ in range(cols)] for _ in range(rows)]
- 深拷贝已有关卡数据
如果是从外部加载关卡数据,必须用深拷贝来避免引用共享:
import copy # 假设level_collision、level_tileset、level_flipmap是原始关卡数据 self.collisionData = copy.deepcopy(level_collision) self.tileset = copy.deepcopy(level_tileset) self.flipmap = copy.deepcopy(level_flipmap)
验证方法
可以在初始化后打印三个数组的内存地址,确认它们不是同一对象:
print(id(self.collisionData)) print(id(self.tileset)) print(id(self.flipmap))
如果三个地址相同,说明确实是数组级别的引用共享;如果地址不同,再检查每一行的地址:
print(id(self.collisionData[0])) print(id(self.tileset[0]))
如果行的地址相同,说明是行级别的引用共享。
内容的提问来源于stack exchange,提问作者Sad Robot
相关产品推荐
相关产品推荐

