我在 python 中找不到这个圆反弹计算有什么问题

I can't find what's wrong with this circle bounce calculation in python

我有一个程序可以让圆圈相互反弹。我按照此处的说明旋转矢量并根据碰撞角度缩放幅度:http://www.vobarian.com/collisions/2dcollisions2.pdf

我在python中写了这段代码(0索引表示x坐标):

norm_vect = [(object2.pos[0] - object1.pos[0]), (object2.pos[1] - object1.pos[1])]
unit = sqrt((norm_vect[0]**2) + (norm_vect[1]**2))
unit_vect = [float(norm_vect[0]) / unit, float(norm_vect[1]) /unit]
tan_vect = [-unit_vect[1], unit_vect[0]]
vel1 = object1.vel
vel2 = object2.vel
vel1_norm = vel1[0] * unit_vect[0] + vel1[1] * unit_vect[1]
vel1_tan = vel1[0] * tan_vect[0] + vel1[1] * tan_vect[1]
vel2_norm = vel2[0] * unit_vect[0] + vel2[1] * unit_vect[1]
vel2_tan = vel2[0] * tan_vect[0] + vel2[1] * tan_vect[1]
new_vel1_norm = (vel1_norm * (object1.mass - object2.mass) + 2 * object2.mass * vel2_norm) / (object1.mass + object2.mass)
new_vel2_norm = (vel2_norm * (object2.mass - object1.mass) + 2 * object1.mass * vel1_norm) / (object1.mass + object2.mass)
new_norm_vect1 = [new_vel1_norm * float(unit_vect[0]), new_vel1_norm * float(unit_vect[1])]
new_norm_vect2 = [new_vel2_norm * float(unit_vect[0]), new_vel2_norm * float(unit_vect[1])]
new_tan_vect1 = [new_vel1_norm * float(tan_vect[0]), new_vel1_norm * float(tan_vect[1])]
new_tan_vect2 = [new_vel2_norm * float(tan_vect[0]), new_vel2_norm * float(tan_vect[1])]

# Now update the object's velocity
object1.vel = [new_norm_vect1[0] + new_tan_vect1[0], + new_norm_vect1[1] + new_tan_vect1[1]]
object2.vel = [new_norm_vect2[0] + new_tan_vect2[0], + new_norm_vect2[1] + new_tan_vect2[1]]

问题是它有时有效,但有时无效。谁能告诉我为什么?似乎如果球以正确的角度碰撞,那么它们的出口轨迹就会交换或发生其他事情。我在 codeskulptor 浏览器中写了这个:http://www.codeskulptor.org/#user39_8q0Xdp3Y4s_2.py

谁能指出我哪里出错了?

编辑:这可能是我处理碰撞的方式吗?步骤如下:

    1) Draw the balls on the screen
    2) Create set of unique pairs of collidable objects 
    3) For each ball, move the ball's position 1 frame forward according to the velocity:
        ->1) Check to see if the ball is hitting a wall
        ->2) For each pairset, if the ball in question is a member of the pair:
             -->1) If distance between centers is less than sum of radii:
                    -->1)  Calculate rebound trajectories
                    ---2)  Find N such that position + rebound trajectory *N is out of collision zone

在线模拟真爽!我没有详细研究您的完整代码,只是研究了您在问题中发布的片段。快速浏览一下,您可以正确计算切向和法向单位向量、旧法向和切向速度以及新法向速度。但在那之后,你似乎有点迷路了。正如关于碰撞的文档中所解释的那样,切向速度在碰撞过程中不会发生变化,因此无需计算 new_tan_vect1/2。我也不明白你为什么要计算new_norm_vect1,法向量在碰撞过程中不会改变。

其他一些小备注:

  • 为什么在你的代码中使用 float()?这通常不需要。如果这样做的原因是为了获得正确的除法结果,那么您真的应该在代码的顶部添加一个 from __future__ import division,因为您似乎正在使用 Python2。有关详细信息,请参阅 this old question

  • 你说的norm_vect其实就是未归一化的法向量,你说的unit_vect其实就是归一化的法向量。我会同时调用 norm_vect,以使法线和切线之间的区别更加清楚。单位向量是任何长度为 1 的向量,因此将其用于法线向量有点误导。

  • 如果您打算进行更多此类模拟,您应该考虑学习 numpy。这使您可以编写矢量化计算,而不是手写 xy 的所有方程式。例如。 norm_vect = pos2 - pos1; norm_vect /= np.linalg.norm(norm_vect)object1.vel = norm_vect * new_vel1_norm + tang_vect * vel1_tang.

我会写你的代码片段应该或多或少像这样(未经测试的代码):

from __future__ import division  # move this to the top of your program

# calculate normal and tangential unit vectors
norm_vect = [(object2.pos[0] - object1.pos[0]), 
             (object2.pos[1] - object1.pos[1])]  # stil un-normalized!
norm_length = sqrt((norm_vect[0]**2) + (norm_vect[1]**2))
norm_vect = [norm_vect[0] / norm_length, 
             norm_vect[1] / norm_length]  # do normalization
tang_vect = [-norm_vect[1], norm_vect[0]]  # rotate norm_vect by 90 degrees

# normal and tangential velocities before collision
vel1 = object1.vel
vel2 = object2.vel
vel1_norm = vel1[0] * norm_vect[0] + vel1[1] * norm_vect[1]
vel1_tang = vel1[0] * tang_vect[0] + vel1[1] * tang_vect[1]
vel2_norm = vel2[0] * norm_vect[0] + vel2[1] * norm_vect[1]
vel2_tang = vel2[0] * tang_vect[0] + vel2[1] * tang_vect[1]

# calculate velocities after collision
new_vel1_norm = (vel1_norm * (object1.mass - object2.mass) 
    + 2 * object2.mass * vel2_norm) / (object1.mass + object2.mass)
new_vel2_norm = (vel2_norm * (object2.mass - object1.mass) 
    + 2 * object1.mass * vel1_norm) / (object1.mass + object2.mass)
# no need to calculate new_vel_tang, since it does not change

# Now update the object's velocity
object1.vel = [norm_vect[0] * new_vel1_norm + tang_vect[0] * vel1_tang, 
               norm_vect[1] * new_vel1_norm + tang_vect[1] * vel1_tang]
object2.vel = [norm_vect[0] * new_vel2_norm + tang_vect[0] * vel2_tang, 
               norm_vect[1] * new_vel2_norm + tang_vect[1] * vel2_tang]

我重命名了一些变量以使其更清晰。