7

我为三个沙滩球在屏幕上弹跳编写了一个动画(在 python 中)。我现在希望它们全部碰撞并能够相互反弹。我真的很感激可以提供的任何帮助。

import pygame
import random
import sys
class Ball:


    def __init__(self,X,Y):

        self.velocity = [1,1]
        self.ball_image = pygame.image.load ('Beachball.jpg'). convert()
        self.ball_boundary = self.ball_image.get_rect (center=(X,Y))
        self.sound = pygame.mixer.Sound ('Thump.wav')
        self.rect = self.ball_image.get_rect (center=(X,Y))

if __name__ =='__main__':

    width = 800
    height = 600
    background_colour = 0,0,0
    pygame.init()
    window = pygame.display.set_mode((width, height))
    pygame.display.set_caption("Bouncing Ball animation")
    num_balls = 3
    ball_list = []
    for number in range(num_balls):
        ball_list.append( Ball(random.randint(10, (width - 10)),random.randint(10, (height - 10))) )
    while True:
        for event in pygame.event.get():
                print event 
                if event.type == pygame.QUIT:
                        sys.exit(0)
        window.fill (background_colour)

        for ball in ball_list:
                if ball.ball_boundary.left < 0 or ball.ball_boundary.right > width:
                        ball.sound.play()
                        ball.velocity[0] = -1 * ball.velocity[0]
                if ball.ball_boundary.top < 0 or ball.ball_boundary.bottom > height:
                        ball.sound.play()
                        ball.velocity[1] = -1 * ball.velocity[1]

                ball.ball_boundary = ball.ball_boundary.move (ball.velocity)
                window.blit (ball.ball_image, ball.ball_boundary)
        pygame.display.flip()
4

7 回答 7

10

任意形状的碰撞检测通常非常棘手,因为您必须确定是否有任何像素发生碰撞。

这实际上更容易使用圆圈。如果您有两个半径分别为 r1 和 r2 的圆,如果中心之间的距离小于 r1+r2,则会发生碰撞。

两个中心 (x1,y1) 和 (x2,y2) 之间的距离可以计算和比较为:

d = sqrt((y2-y1) * (y2-y1) + (x2-x1) * (x2-x1));
if (d < r1 + r2) { ... bang ... }

或者,正如 jfclavette 指出的那样,平方根很昂贵,因此最好只使用简单的操作来计算:

dsqrd = (y2-y1) * (y2-y1) + (x2-x1) * (x2-x1);
if (dsqrd < (r1+r2)*(r1+r2)) { ... bang ... }

棘手的一点在于计算新的运动矢量(给定对象的 (x,y) 随时间变化的速率),因为您需要考虑当前的运动矢量和接触点。

我认为作为第一次切割,您应该只反转运动矢量以测试碰撞检测是否首先起作用。

然后问另一个问题 - 最好保持个别问题具体,以便有针对性地回答。

于 2009-04-23T03:29:34.587 回答
3

检测碰撞只是第一步。让我们分解一下。

最快的做法是计算它们的方形边界框,看看它们是否发生碰撞。两个边需要交叉(1 的顶部和底部或 2,1 的左侧和 2 的右侧,反之亦然)以使边界框重叠。没有重叠,没有碰撞。

现在,当它们重叠时,您需要计算它们之间的距离。如果该距离大于球半径的总和,则不会发生碰撞。

好的!我们有两个球相撞。现在呢?好吧,他们必须互相反弹。他们反弹的方式取决于几个因素。

首先是它们的弹性。两个相互弹跳的橡胶球与两个玻璃球的反弹方式不同。

第二个是它们的初始速度。Inertia 表示,他们将希望继续朝着他们开始时的方向前进。

第三是球的质量。质量较小的球会以更高的速度从更大的质量反弹。

让我们先处理第二个和第三个因素,因为它们是相互交织的。

两个球很少会完全命中。扫视的可能性要大得多。在任何情况下,冲击都会沿着球碰撞的切线法线发生。给定它们的初始速度,您需要计算两者沿此法线的矢量分量。这将导致两个球都会带来一对正常速度的碰撞。将总和相加并将其存储在方便的地方。

现在我们必须弄清楚每个球会从中带走什么。每个球的最终法向速度与给定球的质量成反比。也就是说,取每个球质量的倒数,将两个质量加在一起,然后根据球的质量与两个球质量的倒数之和的比值,将合成的法向速度从碰撞中分离出来。然后将切向速度添加到此,得到球的合成速度。

弹性几乎是相同的,除了它需要一些基本的微积分,因为即使球在压缩时仍然在移动。我会留给你找到相关的数学。

于 2009-04-23T03:49:51.933 回答
1

Pax 的回答很好地涵盖了检测碰撞。关于让物体相互反弹,我建议查看以下有关弹性碰撞非弹性碰撞恢复系数的链接。

编辑:我刚刚注意到这在另一个 SO question中有所涉及,尽管不是专门针对 Python 的。您还应该在那里查看一些好的链接。

于 2009-04-23T03:44:19.293 回答
1

我认为考虑到他正在使用 pygame,你们特别想念一些更简单的东西。

调用该get_rect函数可以为图像设置大概的边界,Rect创建的边界用于计算图像的位置,如果动画中有多个对象,则可以用于检测碰撞。

colliderect&rect可以使用,问题是我不知道你将如何实现它,特别是对于未知数量的球。

请记住它是python。

于 2009-04-23T04:30:17.797 回答
0

首先你需要检查碰撞rect.colliderect(other_rect)

之后,如果它们发生碰撞,您可以检查像素完美碰撞。所以你不会弄乱对象的半径或形状。

对于像素完美碰撞检查,我使用遮罩:使用 制作两个遮罩对象mask.from_surface,然后让它们发挥Mask.overlap作用。

于 2009-07-17T00:31:55.250 回答
0

回到过去,当 CPU 周期非常重要时,编码人员使用一个简单的技巧来检测碰撞:他们使用的颜色可以从像素颜色中分辨出它是背景还是物体。至少在一些 C64 游戏中是这样做的。

不知道你是否愿意走这条路,虽然..

于 2009-04-23T17:08:29.990 回答
0

我做了一个python碰撞检测if语句,这里是:

if beach ball 1 x < beach ball 2 x + beach ball 1 width and beach ball 1 x + beach ball 2 width > beach ball 2 x and beach ball 1 y < beach ball 2 y + beach ball 1 height and beach ball 2 height + beach ball 1 y > beach ball 2 y:
    #put needed code here

在您的情况下,使用 3 个弹跳球,您必须为每个球制作 2 个这种格式的 if 语句,以确保碰撞检测完美无缺。我希望这有帮助。

于 2016-08-21T02:02:06.707 回答