python 如何为我的弹跳球创建碰撞检测?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/780169/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 20:51:09  来源:igfitidea点击:

How do I create collision detections for my bouncing balls?

pythoncollision-detection

提问by paxdiablo

I have coded an animation (in python) for three beach balls to bounce around a screen. I now wish to have them all collide and be able to bounce off each other. I would really appreciate any help that can be offered.

我已经为三个沙滩球编写了一个动画(在 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()

回答by paxdiablo

Collision detection for arbitrary shapes is usually quite tricky since you have to figure out if any pixel collides.

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

This is actually easier with circles. If you have two circles of radius r1 and r2, a collision has occurred if the distance between the centers is less than r1+r2.

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

The distance between the two centers (x1,y1) and (x2,y2) can be calculated and compared as:

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

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

Or, as jfclavette points out, square roots are expensive so it may be better to calculate using just simple operations:

或者,正如 jfclavette 指出的那样,平方根很昂贵,因此使用简单的运算进行计算可能会更好:

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

The tricky bit comes in calculating the new movement vectors (the rate at which (x,y) changes over time for a given object) since you need to take into account the current movement vectors and the point of contact.

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

I think as a first cut, you should just reverse the movement vectors to test if the collision detection works first.

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

Then ask another question - it's better to keep individual questions specific so answers can be targeted.

然后再问一个问题 - 最好让个别问题具体化,以便可以有针对性地回答。

回答by Ignacio Vazquez-Abrams

Detecting a collision is only the first step. Let's break that down.

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

The fastest thing to do is calculate their square bounding boxes and see if those collide. Two of the sides need to cross (top of 1 and bottom or 2, and left of 1 and right of 2, or vice versa) in order for the bounding boxes to overlap. No overlap, no collision.

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

Now, when they dooverlap, you need to calculate the distance between them. If this distance is more than the sums of the radii of the balls, then no collision.

现在,当他们这样做的重叠,你需要计算它们之间的距离。如果这个距离大于球的半径之和,则不会发生碰撞。

Okay! We have two balls colliding. Nowwhat? Well, they have to bounce off each other. Which way they bounce depends on a few factors.

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

The first is their elasticity. Two rubber balls bouncing off each other rebound differently than two glass balls.

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

The second is their initial velocity. Inertia states that they'll want to keep going in mostly the same direction they started in.

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

The third is the mass of the balls. A ball with smaller mass will rebound off a much larger mass with a higher velocity.

第三个是球的质量。质量较小的球将以较高的速度从质量大得多的球上反弹。

Let's deal with the second and third factors first, since they are intertwined.

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

Two balls will rarely hit exactly dead on. Glancing blows are far more likely. In any case, the impact will happen along the normal of the tangent where the balls collide. You need to calculate the vector component of both along this normal given their initial velocities. This will result in a pair of normal velocities that both balls will bring to the collision. Add up the sum and store it somewhere handy.

两个球很少会完全击中。扫视打击的可能性要大得多。在任何情况下,冲击都将沿着球碰撞的切线的法线发生。给定它们的初始速度,您需要计算它们沿该法线的矢量分量。这将导致两个球碰撞时产生一对法向速度。把总和存起来放在方便的地方。

Now we have to figure out what each ball will take away from it. The resulting normal velocity of each ball is inversely proportional to the given ball's mass. That is to say, take the reciprocal of each ball's mass, add both masses together, and then parcel out the resultant normal velocity away from the collision based on the ratio of the ball's mass to the sum of the reciprocal of both ball's masses. Then add the tangential velocity to this, and you get the resultant velocity of the ball.

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

Elasticity is mostly the same, except it requires some basic calculus due to the fact that the balls are still moving even as they compress. I'll leave it to you to find the relevant math.

弹性基本相同,但由于球在压缩时仍在移动,因此需要一些基本的计算。我会让你找到相关的数学。

回答by savannah

I think there is somehthing simpler that you guys are missing espeically considering he's using pygame.

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

Calling the get_rectfunction can set probably boundraies for the images and Rectthat is created, is used for calculating the position of the image and if there are more than one object in the animation, it can be used for detecting collisions.

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

colliderect& rectcan be used, problem is i have no idea how you would implement it especially for an unkown number of balls.

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

Keeping in mind it's python.

记住它是python。

回答by gnovice

Detecting collisions was covered well by Pax's answer. With respect to having objects bounce off one another, I suggest checking out the following links concerning elastic collisions, inelastic collisions, and coefficients of restitution.

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

EDIT:I just noticed that this was covered in another SO question, albeit not specifically for Python. You should also check there for some good links.

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

回答by Makis

Back in the good old times when CPU cycles were a premium coders used a simple trick to detect collision: they used such colours that they could tell from the pixel colour if it was background or an object. This was done on at least some C64 games.

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

Don't know if you are willing to go this route, though..

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

回答by dhalsim

First you need to check collision with rect.colliderect(other_rect)

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

after that if they are colliding, you can check pixel perfect collision. So you don't mess with object's radius or shape.

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

For pixel perfect collision checking, I use Masks: Make both mask objects with mask.from_surface, then put them to Mask.overlapfunction.

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

回答by pi guy

I made a python collision detection if statement, here it is:

我做了一个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

In your case, with 3 bouncing balls, you will have to make 2 if statements of this format for each ball to make sure that the collision detection is flawless. I hope this helps.

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