Angle Shots
Lesson 36 of 40 in Coddy's Make Games with Pygame course.
In Pong, where the ball hits the paddle decides where it goes. Near the top end it flies up, near the bottom end down, and in the middle straight across.
Measure how far the ball's middle is from the paddle's middle, and make that the new vy:
if ball.colliderect(right):
vx = -abs(vx)
vy = (ball.centery - right.centery) // 6Above the middle the difference is negative, so the ball goes up; below, positive. Dividing by 6 keeps it from getting too fast: a hit at the very end gives a vy of about 7.
This turns Pong into a game of skill: you aim with your paddle.
Challenge
HardIn both paddle collisions, after setting vx, set vy to the ball's middle minus that paddle's middle, divided by 6 with //.
Try it yourself
import pygame
pygame.init()
screen = pygame.display.set_mode((600, 400))
pygame.display.set_caption("Pong")
clock = pygame.time.Clock()
font = pygame.font.Font(None, 36)
ball = pygame.Rect(293, 193, 14, 14)
vx, vy = 5, 4
left = pygame.Rect(20, 160, 12, 80)
right = pygame.Rect(568, 160, 12, 80)
left_score = 0
right_score = 0
waiting = False
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
waiting = False
keys = pygame.key.get_pressed()
if keys[pygame.K_w]:
left.y -= 6
if keys[pygame.K_s]:
left.y += 6
if keys[pygame.K_UP]:
right.y -= 6
if keys[pygame.K_DOWN]:
right.y += 6
left.clamp_ip(screen.get_rect())
right.clamp_ip(screen.get_rect())
if not waiting:
ball.x += vx
ball.y += vy
if ball.top <= 0 or ball.bottom >= 400:
vy = -vy
if ball.colliderect(left):
vx = abs(vx)
if ball.colliderect(right):
vx = -abs(vx)
if ball.left > 600:
left_score += 1
ball.center = (300, 200)
vx = -vx
waiting = True
if ball.right < 0:
right_score += 1
ball.center = (300, 200)
vx = -vx
waiting = True
screen.fill((30, 30, 46))
pygame.draw.rect(screen, (80, 160, 255), left)
pygame.draw.rect(screen, (235, 80, 80), right)
pygame.draw.rect(screen, (255, 196, 0), ball)
score = font.render(f"{left_score} : {right_score}", True, (240, 240, 240))
screen.blit(score, score.get_rect(center=(300, 30)))
if waiting:
message = font.render("Press Space to serve", True, (240, 240, 240))
screen.blit(message, message.get_rect(center=(300, 360)))
pygame.display.flip()
clock.tick(60)
pygame.quit()
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
All lessons in Make Games with Pygame
1The Game Loop
Open a WindowFill the Background4Two Players and a Ball
The BallBouncePractice on your own: Pygame playground