Я считаю, что это проблема:
[is_collided_with(ball) for ball in balls]
def is_collided_with(a):
for ball in balls:
if abs(a.xcor() - ball.xcor()) < 3 and abs(a.ycor() - ball.ycor()) < 3:
a.dx *= -1
ball.dx *= -1
a.dy *= -1
ball.dy *= -1
Вы проверяете каждый мяч против каждого другого. И только умножая dx
и dy
на -1, если они столкнулись. Но если A столкнулся с B, то B столкнулся с A, поэтому ваша логика запускает дважды , фактически уничтожая себя! И вы не проверяете, являются ли A и B одним и тем же шаром, что всегда является столкновением!
Ниже приведена моя переделка и упрощение вашего кода. Это не идеально, но я верю, что вы получите больше эффектов столкновения и отскока мяча, которые вы ищете:
from turtle import Screen, Turtle
from random import choice, randint
BALL_DIAMETER = 40
WIDTH, HEIGHT = 600, 600
COLORS = ['yellow', 'gold', 'orange', 'red', 'maroon', 'violet', 'magenta', 'purple', 'navy', 'blue', 'skyblue', 'cyan', 'turquoise', 'lightgreen', 'green', 'darkgreen', 'chocolate', 'brown', 'gray', 'white']
INITIAL_BALLS = 8
GRAVITY = 0.1
CURSOR_SIZE = 20
def addBall():
ball = Turtle('circle')
ball.shapesize(BALL_DIAMETER / CURSOR_SIZE)
ball.color(choice(COLORS))
ball.penup()
ball.speed('fastest')
x, y = randint(BALL_DIAMETER - WIDTH/2, WIDTH/2 - BALL_DIAMETER), randint(BALL_DIAMETER - HEIGHT/2, HEIGHT/2 - BALL_DIAMETER)
ball.goto(x, y)
ball.dy = 0
ball.dx = randint(-3, 3)
balls.append(ball)
numOfBalls = len(balls)
if numOfBalls == 1:
screen.title(str(numOfBalls) + " Bouncing Ball")
else:
screen.title(str(numOfBalls) + " Bouncing Balls")
def removeBall():
balls.pop().hideturtle()
numOfBalls = len(balls)
if numOfBalls == 0 or numOfBalls > 1:
screen.title(str(numOfBalls) + " Bouncing Balls")
else:
screen.title(str(numOfBalls) + " Bouncing Ball")
def reload():
for ball in balls:
ball.color(choice(COLORS))
ball.penup()
x, y = randint(BALL_DIAMETER - WIDTH/2, WIDTH/2 - BALL_DIAMETER), randint(BALL_DIAMETER - HEIGHT/2, HEIGHT/2 - BALL_DIAMETER)
ball.goto(x, y)
ball.dy = 0
ball.dx = randint(-3, 3)
def is_collided_with(other):
for ball in balls:
if ball != other and ball.distance(other) < BALL_DIAMETER:
other.dx *= -1
ball.dx *= -1
other.dy *= -1
ball.dy *= -1
screen = Screen()
screen.setup(WIDTH, HEIGHT)
screen.bgcolor('black')
screen.tracer(False)
balls = []
for _ in range(INITIAL_BALLS):
addBall()
screen.onkey(addBall, 'a')
screen.onkey(removeBall, 'p')
screen.onkey(reload, 'r')
screen.onkey(screen.bye, 'q')
screen.listen()
def tick():
for ball in balls:
ball.dy -= GRAVITY
ball.sety(ball.ycor() + ball.dy)
ball.setx(ball.xcor() + ball.dx)
if ball.ycor() < -HEIGHT/2:
ball.sety(-HEIGHT/2)
ball.dy *= -1
if ball.xcor() > WIDTH/2 or ball.xcor() < -WIDTH/2:
ball.dx *= -1
is_collided_with(ball)
screen.update()
screen.ontimer(tick, 60)
tick()
screen.mainloop()
Надеюсь, это даст вам достаточно рабочей среды, чтобы усовершенствовать детали шаров, соприкасающихся друг с другом.