Python重力场计算函数异常:仅屏幕底部行有非零值求助
问题:重力场计算函数仅屏幕底部行有值,其余全为0
我是大学编程新手,学编程才几个月,正在做一个基于Pygame的重力场强度可视化程序。基于已验证可用的引力计算器修改了重力场计算函数,用来计算屏幕每个像素点的重力场,但返回的numpy数组里除了屏幕底部行,其他元素全是0,找不到原因。
测试场景:用100x100的屏幕,在(50,50)位置放一个质量为6000000000000的单个质量体,问题依然存在。
当前代码
# 计算屏幕上每个点由所有质量体产生的引力场的函数,质量和位置由列表定义,同时传入屏幕尺寸 def gravfield(mass, x, y, screen_width, screen_height): # 定义屏幕位置点 x_screen = list(range(screen_width)) y_screen = list(range(screen_height)) # 定义存储屏幕每个像素点场强的数组 field = np.zeros((screen_width, screen_height)) # 用向量法计算每个质量体产生的引力场 for i in range(len(x_screen)): for n in range(len(y_screen)): # 存储每个质量体产生的场强分量的列表 x_fields = [] y_fields = [] for j in range(len(mass)): # 计算从质量体到目标点的位置向量 x_distance = x[j] - x_screen[i] y_distance = y[j] - y_screen[n] # 计算质量体和目标点的距离,同时给质量体所在像素赋唯一值以避免除零错误 distance = np.sqrt((x_distance**2) + (y_distance**2)) if distance == 0: x_fields = 0 y_fields = 0 else: # 计算质量体到目标点的单位向量 x_unit_vector = x_distance / distance y_unit_vector = y_distance / distance # 计算场强大小 magnitude = (G * mass[j] * 1) / (distance ** 2) # 计算各方向的场强分量,并添加到存储所有质量体分量的列表中 x_field = (magnitude * x_unit_vector) y_field = (magnitude * y_unit_vector) x_fields.append(x_field) y_fields.append(y_field) # 求和所有方向的场强分量得到合场强,再计算其大小并赋值给对应屏幕像素的数组位置 gx = sum(x_fields) gy = sum(y_fields) g = np.sqrt((gx**2) + (gy**2)) field[n, i] = g return field
问题原因与修复方案
核心问题:缩进错误
你把计算合场强并赋值给field的代码块(gx = sum(...)到field[n,i] = g)放在了外层i循环的末尾,而不是内层n循环的末尾。这意味着:
- 外层
i循环(遍历x方向)执行时,内层n循环(遍历y方向)会完整跑一遍,但只有当n循环结束后(此时n的值固定为screen_height-1,也就是屏幕最后一行的索引),才会执行一次赋值操作。 - 所以整个
field数组里,只有n=screen_height-1对应的那一行(屏幕底部行)会被赋值,其他行都保持初始的0值。
修复后的代码
# 计算屏幕上每个点由所有质量体产生的引力场的函数,质量和位置由列表定义,同时传入屏幕尺寸 def gravfield(mass, x, y, screen_width, screen_height): # 定义屏幕位置点 x_screen = list(range(screen_width)) y_screen = list(range(screen_height)) # 定义存储屏幕每个像素点场强的数组 field = np.zeros((screen_width, screen_height)) # 用向量法计算每个质量体产生的引力场 for i in range(len(x_screen)): for n in range(len(y_screen)): # 存储每个质量体产生的场强分量的列表 x_fields = [] y_fields = [] for j in range(len(mass)): # 计算从质量体到目标点的位置向量 x_distance = x[j] - x_screen[i] y_distance = y[j] - y_screen[n] # 计算质量体和目标点的距离,同时给质量体所在像素赋唯一值以避免除零错误 distance = np.sqrt((x_distance**2) + (y_distance**2)) if distance == 0: x_fields = [0] # 改为列表,避免sum时报错 y_fields = [0] else: # 计算质量体到目标点的单位向量 x_unit_vector = x_distance / distance y_unit_vector = y_distance / distance # 计算场强大小 magnitude = (G * mass[j] * 1) / (distance ** 2) # 计算各方向的场强分量,并添加到存储所有质量体分量的列表中 x_field = (magnitude * x_unit_vector) y_field = (magnitude * y_unit_vector) x_fields.append(x_field) y_fields.append(y_field) # 注意这里的缩进:放到n循环内部,每个像素点都执行一次 # 求和所有方向的场强分量得到合场强,再计算其大小并赋值给对应屏幕像素的数组位置 gx = sum(x_fields) gy = sum(y_fields) g = np.sqrt((gx**2) + (gy**2)) field[n, i] = g return field
额外优化说明
- 当
distance == 0时,原代码把x_fields和y_fields赋值为整数0,后续sum(x_fields)会报错(因为不能对整数用sum),所以改为赋值为[0]这样的列表,保证sum操作正常执行。 - 若后续屏幕尺寸增大,嵌套循环的计算效率会很低,可以尝试用numpy的向量化操作替代循环,不过先把逻辑跑通再优化性能更适合新手阶段。
内容的提问来源于stack exchange,提问作者Valter Somlai
相关产品推荐
相关产品推荐

