问题描述
我正在尝试编写一个简单的弹性碰撞模拟器(在单个维度上,沿 x 轴移动直线运动)。经过多次测试,我设法编写了这个函数来检查碰撞:
def block_collisions(self,block1,block2):
""" check whether the two passed block objects happen to collide """
# calculating a collision tollerance threshold under which the potential collision is considered to happen
collision_tolerance = 2*round(abs(block1.v) + abs(block2.v),0) + 5
# storing initial veLocities of the two blocks (since the new veLocities od the blocks are to be
# calculated independently and at the same time)
block1_initialV = block1.v
block2_initialV = block2.v
if block1.block.colliderect(block2.block):
if ([block1,block2] not in self.collisions) and ([block2,block1] not in self.collisions):
self.collisions.append([block1,block2])
# the collision can happn only on the left and right side of the blocks since it is a rectilinear motion
if abs(block2.block.right - block1.block.left) < collision_tolerance:
self.collision_sound.play()
# calculating new veLocities
if self.is_elastic:
block1.v = (2*block2.m*block2_initialV + (block1.m - block2.m)*block1_initialV) / (block1.m + block2.m)
block2.v = (2*block1.m*block1_initialV + (block2.m - block1.m)*block2_initialV) / (block1.m + block2.m)
if abs(block2.block.left - block1.block.right) < collision_tolerance:
self.collision_sound.play()
# calculating new veLocities
if self.is_elastic:
block1.v = (2*block2.m*block2_initialV + (block1.m - block2.m)*block1_initialV) / (block1.m + block2.m)
block2.v = (2*block1.m*block1_initialV + (block2.m - block1.m)*block2_initialV) / (block1.m + block2.m)
if block1.x <= block2.x:
block1.x = block2.x
if block1.x <= block2.x:
block1.x = block2.x
该函数将两个 Block 类(我编写的)对象作为参数。它的主要属性是区块当前和初始位置:block.x,block.x0;当前和初始速度:block.v,block.v0;以及用于在屏幕上表示实际矩形的 Pygame rect 对象:block.block。变量 self.collisions 是一个列表,其中包含在主循环的单次迭代期间检测到的所有碰撞对(因此每个循环都会清空)。为了确保只检测到一次碰撞,检查 [block1,block2] 或 [block2,block1] 对是否已经在此列表中。另一种碰撞检测功能是检测墙壁碰撞的功能。:
def wall_collisions(self,block):
""" check whether the a block happens to collide with a particular wall """
# the wall is assumed to have an ideal infinite mass,hence,the new veLocity of the wall is 0,while the veLocity of
# the block is the same,opposite in direction
if self.l_wall:
if block.block.left <= self.l_wall:
self.collision_sound.play()
block.v *= -1
if self.r_wall:
if block.block.right >= self.r_wall:
self.collision_sound.play()
block.v *= -1
其中 self.l_wall,self.r_wall 是两个设置墙位置的值,例如 self.l_wall = 20,self.r_wall = window_width - 20。这两个函数都放在主循环中,在一个块中具有以下语法:
while self.__running:
...
for b_ in self.blocks:
# check block collisions
for b__ in self.blocks:
if not b_ == b__:
block_collisions(b_,b__)
# check wall collisions
wall_collisions(b_)
self.collisions = []
这些函数的问题在于,即使结果适用于大多数情况,它还是有点小问题和错误:
-
让屏幕上有两个方块,一个的质量比另一个大一个数量级。当较小的方块恰好位于一堵墙和另一个移动到同一堵墙的方块之间时,由于大量的反弹,较小的方块似乎闪烁并与墙壁和方块重叠(物理结果仍然可以接受,但整体表现似乎不准确)。
-
让更大的块比另一个大一个数量级以上。在上述情况下,较大的块没有及时停下来,将较小的块挤压在墙上(墙与较大块之间的距离变得小于较小块的一侧)。然而,即使在这种情况下,物理结果也是可以接受的,因为问题是图形化的,而不是方法论的。
-
让速度变高 (>= 20m/s = 20 * (50px / 60frames) = 16.7 px/frame,50px = 1m,60frames = 1s) 并且质量之间的差异很大 (m1 / m2 > = 100 iff m1 > m2),考虑到一个指向另一个的块,它们倾向于重叠,因此较小的块以某种方式设法穿透较大的块。在这个尴尬的事件之后,继续检测到碰撞,因此较小的块被困在另一个块中。
有人了解我遇到的这些问题并知道如何解决吗?或者有没有人知道检查碰撞的更好更精确的方法?
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)