Python碰撞模拟调用collide方法触发Numpy数据类型不识别报错
问题排查与修复方案
核心报错原因
报错TypeError: data type not understood的直接原因是np.array调用语法错误:np.array(-1*other.vel[0], other.vel[1])的写法不符合numpy数组构造规则,np.array第一个参数接收包含数组元素的序列,第二个可选参数为指定的数据类型。你将两个坐标作为独立参数传入,numpy会把第二个坐标other.vel[1]解析为数据类型参数,自然无法识别。
其他隐性问题修复
除了核心语法错误,你的代码还存在几处逻辑问题会导致后续运行异常:
Container类collide方法的判断逻辑错误:需求是「x分量大于1且y分量小于1才翻转x」,你写的or逻辑会触发大量不符合预期的翻转,需改为and。- 第二个判断条件的对象写错:
self.vel[0] < 1中的self是Container实例,静止容器的速度默认是[0,0],这个判断永远成立,实际需要判断的是球的x分量,应改为other.vel[0] < 1。 Ball类的move方法没有返回值:你用self._pos = self._ball.move(xxx)接收返回值,最终self._pos会被赋值为None,要么直接读取self._ball.pos获取更新后的位置,要么给move方法补充return self.pos。Container类的time_to_collision方法直接访问未初始化的属性:self.posdif、self.veldif、self.raddif三个属性只有父类Ball的time_to_collision被调用时才会赋值,子类重写方法直接使用会报属性不存在,需要在方法开头先计算这三个值。- 碰撞后的新速度没有写回球对象:你计算得到新速度赋值给
self._vel后,没有更新到self._ball.vel,球下次移动还是会用原速度。
修复后核心代码示例
Container类collide方法
def collide(self, other): self.other = other if other.vel[0] > 1 and other.vel[1] < 1: # 坐标打包为列表传入np.array,修复核心报错 return np.array([-1*other.vel[0], other.vel[1]]) if other.vel[0] < 1 and other.vel[1] > 1: return np.array([other.vel[0], -1*other.vel[1]]) # 补充边界情况返回,避免无返回值问题 return other.vel
Container类time_to_collision方法
def time_to_collision(self, other): self.other = other # 补充属性计算,避免属性不存在报错 self.posdif = np.subtract(self.pos, other.pos) self.veldif = np.subtract(self.vel, other.vel) self.raddif = self.radius - other.radius return (-2*np.dot(self.posdif, self.veldif) + np.sqrt(4*(np.dot(self.posdif, self.veldif)**2)-4*np.dot(self.veldif, self.veldif)*(np.dot(self.posdif, self.posdif)-np.dot(self.raddif, self.raddif))))/(2*np.dot(self.veldif, self.veldif))
Simulation类next_collision方法
def next_collision(self): dt = self._container.time_to_collision(self._ball) self._ball.move(dt) # 直接读取球对象更新后的位置 self._pos = self._ball.pos self._vel = self._container.collide(self._ball) # 把新速度写回球对象 self._ball.vel = self._vel print('new pos at', self._pos, 'new vel at', self._vel)
内容的提问来源于stack exchange,提问作者sid2001
相关产品推荐
相关产品推荐

