微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

方块之间的碰撞

如何解决方块之间的碰撞

我正在尝试编写一个简单的弹性碰撞模拟器(在单个维度上,沿 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 = []

这些函数的问题在于,即使结果适用于大多数情况,它还是有点小问题和错误

  1. 让屏幕上有两个方块,一个的质量比另一个一个数量级。当较小的方块恰好位于一堵墙和另一个移动到同一堵墙的方块之间时,由于大量的反弹,较小的方块似乎闪烁并与墙壁和方块重叠(物理结果仍然可以接受,但整体表现似乎不准确)。

  2. 让更大的块比另一个一个数量级以上。在上述情况下,较大的块没有及时停下来,将较小的块挤压在墙上(墙与较大块之间的距离变得小于较小块的一侧)。然而,即使在这种情况下,物理结果也是可以接受的,因为问题是图形化的,而不是方法论的。

  3. 让速度变高 (>= 20m/s = 20 * (50px / 60frames) = 16.7 px/frame,50px = 1m,60frames = 1s) 并且质量之间的差异很大 (m1 / m2 > = 100 iff m1 > m2),考虑到一个指向另一个的块,它们倾向于重叠,因此较小的块以某种方式设法穿透较大的块。在这个尴尬的事件之后,继续检测到碰撞,因此较小的块被困在另一个块中。

有人了解我遇到的这些问题并知道如何解决吗?或者有没有人知道检查碰撞的更好更精确的方法

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。