在python中检测许多乌龟对象之间的碰撞

时间:2020-03-25 16:54:43

标签: python collision

我是Wikipedia的医学编辑(具有接近零的python经验),并且我们正在尝试模拟社交疏远的影响。我正在尝试使一堆圆圈在正方形空间中反弹。我让它们从墙壁上弹起,但是我不确定如何检测球之间的碰撞。我创建了一个is_collided_with定义,但

if is_collided_with(ball, ball):
            ball.dy *=-1
            ball.dx *=-1

冻结所有内容。如果将其卸下,则可以看到运动(根据我的理解,速度可能会因系统而异)。最终目标是要改变颜色,从健康到传染性,再到治愈,并向人们展示社会隔离是如何与不同人数的人一起工作的。

这是整个代码,

#bouncing balls
import turtle
import random

wn = turtle.Screen()
wn.bgcolor("white")
wn.title("ball simulator")
wn.tracer(0)

balls = []

for _ in range(10):
    balls.append(turtle.Turtle())


for ball in balls:
    ball.shape("circle")
    ball.color("red")
    ball.penup()
    ball.speed(1)
    x = random.randint(-290,290)
    y = random.randint(-290,290)
    ball.goto(x, y)
    ball.dy = (random.randint(-3, 3))/5+.1
    ball.dx = (random.randint(-3, 3))/5+.1

def is_collided_with(a, b):
    return abs(a.xcor() - b.xcor()) < 10 and abs(a.ycor() - b.ycor()) < 10

while True:
    wn.update()
    for ball in balls:
        ball.sety(ball.ycor() + ball.dy)
        ball.setx(ball.xcor() + ball.dx)


    #check for a bounce
        if is_collided_with(ball, ball):
            ball.dy *=-1
            ball.dx *=-1
        if ball.ycor() <-300:
            ball.dy *=-1
        if ball.ycor() >+300:
            ball.dy *=-1
        if ball.xcor() >+300:
            ball.dx *=-1
        if ball.xcor() <-300:
            ball.dx *=-1


wn.mainloop()

1 个答案:

答案 0 :(得分:1)

问题是这一行:

if is_collided_with(ball, ball):

您要传递两次相同的ball对象,就好像将球分开一样对待它。基本上,对于您的球列表中的每个球,if语句都说“此球是否与自身发生碰撞?” -对于模拟的每一帧总是如此。因此,您始终要输入if语句的主体,并翻转当前球的x和y方向向量,从而使每个球都在某种程度上摆动。

幼稚的解决方案涉及将当前球与模拟中的所有其他球进行比较。我之所以说“天真”,是因为尽管这样做确实有效,但是对于更多数量的球来说,它却变得非常低效而缓慢。更为复杂的解决方案将使用诸如四叉树之类的空间划分技术来显着提高性能(此方法仅通过比较可能靠近的球来进行工作,而所有其他距离较远的球都被剔除,因此不考虑使用比较)。

在您的情况下,只要球的数量很小,那么幼稚的解决方案就可以正常工作。看起来像这样(注意嵌套的for循环):

while True:
    wn.update()
    for ball in balls:
        ball.sety(ball.ycor() + ball.dy)
        ball.setx(ball.xcor() + ball.dx)
        for other_ball in balls:
            if other_ball is ball:
                # We are not interested in balls colliding with themselves.
                # Skip the current iteration of the inner for-loop, and move on to the next ball
                continue
            if is_collided_with(ball, other_ball):
                ball.dx *= -1
                ball.dy *= -1

        if ball.ycor() <-300:
            ball.dy *=-1
        if ball.ycor() >+300:
            ball.dy *=-1
        if ball.xcor() >+300:
            ball.dx *=-1
        if ball.xcor() <-300:
            ball.dx *=-1

最后一件事,请记住,从技术上讲,仅因为两个球发生碰撞并不意味着它们的两个方向矢量分量(x和y)都需要/应该翻转。想象一下这样一个场景,两个球以相同的方向行进,但速度稍有不同,前面的球比后面的球慢(正在追赶)-一旦发生碰撞,将两个方向都翻转是不正确的-vector组件。