Вопрос-Ответ

Sometimes the ball doesn't bounce off the paddle in pong game

Иногда мяч не отскакивает от ракетки в игре pong

У меня есть простая игра в понг, которая в основном работает хорошо. Но иногда случается так, что мяч не отскакивает от ракетки. Мяч качается и скользит по ракетке, а ракетка, кажется, притягивает мяч магнитным полем, как показано на анимации:

Каждый раз, когда прямоугольник, окружающий мяч, сталкивается с прямоугольником ракетки, направление полета мяча меняется:

if ball.colliderect(paddleLeft):
move_x *=-1
if ball.colliderect(paddleRight):
move_x *=-1

Что вызывает такое поведение?

Проблему можно воспроизвести на следующем полном, минимальном и поддающемся проверке примере. Положение мяча установлено таким образом, что неправильное поведение возникает немедленно, если правая ракетка не перемещается:

import pygame

pygame.init()
width, height = 600, 400
window = pygame.display.set_mode((width, height))
clock = pygame.time.Clock()
radius, move_x, move_y = 10, 3, 3
ball = pygame.Rect(width//2+125, 20, radius*2, radius)
paddleHeight = 80
paddleLeft = pygame.Rect(20, (height-paddleHeight)//2, 10, paddleHeight)
paddleRight = pygame.Rect(width-30, (height-paddleHeight)//2, 10, paddleHeight)

run = True
while run:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT: run = False

keys = pygame.key.get_pressed()
if keys[pygame.K_w] and paddleLeft.top > 0: paddleLeft.y -= 5
if keys[pygame.K_s] and paddleLeft.bottom < height: paddleLeft.y += 5
if keys[pygame.K_UP] and paddleRight.top > 0: paddleRight.y -= 5
if keys[pygame.K_DOWN] and paddleRight.bottom < height: paddleRight.y += 5
ball.x += move_x
ball.y += move_y
if ball.left <= 0 or ball.right >= width: move_x *=-1
if ball.top <= 0 or ball.bottom >= height: move_y *=-1

if ball.colliderect(paddleLeft): move_x *=-1
if ball.colliderect(paddleRight): move_x *=-1

window.fill(0)
pygame.draw.rect(window, (255, 255, 255), paddleLeft)
pygame.draw.rect(window, (255, 255, 255), paddleRight)
pygame.draw.circle(window, (255, 255, 255), ball.center, radius)
pygame.display.flip()
Переведено автоматически
Ответ 1

Такое поведение возникает, когда мяч ударяется о ракетку не спереди, а сверху или снизу. На самом деле обнаруживается столкновение ракетки с мячом и меняется направление. Но мяч так глубоко вошел в ракетку, что мяч не может покинуть зону столкновения с ракеткой на следующем шаге. Это приводит к тому, что в следующем кадре снова обнаруживается столкновение и направление полета мяча снова меняется. Теперь мяч движется в том же направлении, что и до первого столкновения. Этот процесс продолжается до тех пор, пока мяч не покинет лопатку снизу. Это вызывает зигзагообразное движение вдоль передней стороны лопатки.

Существуют разные решения. Один из вариантов - не менять направление, а задать направление влево при ударе правой ракеткой или задать направление вправо при ударе левой ракеткой.:

if ball.colliderect(paddleLeft):
move_x = abs(move_x)
if ball.colliderect(paddleRight):
move_x = -abs(move_x)

Другой вариант - подстроить положение мяча под мяч. При ударе правой ракеткой правая сторона мяча должна располагаться слева от ракетки. Если удар нанесен левой ракеткой, то левая сторона мяча должна располагаться справа от ракетки:

if ball.colliderect(paddleLeft):
move_x *= -1
ball.left = paddleLeft.right
if ball.colliderect(paddleRight):
move_x *= -1
ball.right = paddleRight.left

python pygame