A veces la pelota no rebota en la paleta en el juego de pong.
Tengo un juego de pong sencillo que en general funciona bien. Pero a veces ocurre que la pelota no rebota en la pala. La pelota se tambalea y se desliza a lo largo de la paleta y la paleta parece tirar magnéticamente de la pelota como se muestra en la animación:
Cada vez que el rectángulo que rodea la pelota choca con el rectángulo de la paleta, la dirección de la pelota cambia:
if ball.colliderect(paddleLeft):
move_x *=-1
if ball.colliderect(paddleRight):
move_x *=-1
¿Qué causa el comportamiento?
El problema se puede reproducir con el siguiente ejemplo completo, mínimo y verificable. La posición de la pelota está configurada de modo que el comportamiento incorrecto ocurra inmediatamente si no se mueve la paleta derecha:
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()
El comportamiento ocurre cuando la pelota no golpea la paleta en el frente, sino en la parte superior o inferior. En realidad se detecta la colisión entre la pala y la pelota y se cambia la dirección. Pero la pelota penetró tan profundamente en la pala que en el siguiente paso no puede abandonar la zona de colisión con la pala. Esto provoca que se vuelva a detectar una colisión en el siguiente fotograma y se vuelva a cambiar la dirección de la bola. Ahora la pelota se mueve en la misma dirección que antes de la primera colisión. Este proceso continúa hasta que la pelota sale de la paleta por el fondo. Esto provoca un movimiento en zig zag a lo largo del lado frontal de la paleta.
Hay diferentes soluciones. Una opción es no invertir la dirección, sino establecer la dirección hacia la izquierda cuando se golpea la paleta derecha y establecer la dirección hacia la derecha cuando se golpea la paleta izquierda:
if ball.colliderect(paddleLeft):
move_x = abs(move_x)
if ball.colliderect(paddleRight):
move_x = -abs(move_x)
Otra opción es ajustar la posición a la pelota. Si se golpea la paleta derecha, el lado derecho de la pelota debe colocarse a la izquierda de la paleta. Si se golpea la paleta izquierda, entonces el lado izquierdo de la pelota debe colocarse a la derecha de la paleta:
if ball.colliderect(paddleLeft):
move_x *= -1
ball.left = paddleLeft.right
if ball.colliderect(paddleRight):
move_x *= -1
ball.right = paddleRight.left