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

Detecting collision between many turtle objects in python

我是维基百科的一名医学编辑(python 经验几乎为零),我们正在尝试模拟社交距离的影响。我试图让一堆圆圈在正方形中弹跳 space。我让它们从墙上弹起,但我不确定如何检测球之间的碰撞。我创建了一个定义 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()

问题出在这一行:

if is_collided_with(ball, ball):

您两次传入同一个 ball 对象,将其视为分开的球。基本上,对于您的球列表中的每个球,if 语句都在说 "is this ball colliding with itself?" - 这对于模拟的每一帧都始终为真。因此,您总是进入 if 语句的主体,并翻转当前球的 x 和 y 方向向量,这导致每个球都在原地摆动。

天真的解决方案涉及将当前球与模拟中的所有其他球进行比较。我说 "naive" 是因为,虽然这确实有效,但对于更多的球来说,它变得非常低效和缓慢。一个更复杂的解决方案是使用某种 space 分区技术,如四叉树来显着提高性能(这通过只比较有可能接近的球,而所有其他远离的球被剔除和不考虑比较)。

在你的情况下,只要球的数量少,天真的解决方案应该可以。它看起来像这样(注意嵌套的 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)都需要/应该翻转。想象这样一种情况,两个球以相同的方向但速度略有不同,前面的球比后面的球慢(正在追赶)——一旦它们碰撞,翻转两个方向是不正确的-向量分量。