I am trying to program a ping pong game in python, and I am able to make the ball bounce off the side of the pad. However, I am unable to make the ball bounce off the top and bottom of the pad. I am currently only doing the left pad (pad1). Here is my code:
import sys, pygame, random, math
pygame.init()
width, height = 1200, 675
screen = pygame.display.set_mode((width, height), pygame.RESIZABLE)
clock = pygame.time.Clock()
FPS = 120
xmb1 = False
xmf1 = False
ymb1 = False
ymf1 = False
xmb2 = False
xmf2 = False
ymb2 = False
ymf2 = False
squareh = 275
squarew = 35
squares = 3
x1 = 100
y1 = (height / 2) - (squareh / 2)
x2 = width - 100 - squarew
y2 = (height / 2) - (squareh / 2)
BLACK = (0,0,0)
WHITE = (255,255,255)
font = pygame.font.SysFont("arial", 30)
text = font.render("Press Space to start", True, WHITE)
text3 = font.render("3", True, WHITE)
text2 = font.render("2", True, WHITE)
text1 = font.render("1", True, WHITE)
startt = font.render("Start!", True, WHITE)
text3b = False
text2b = False
text1b = False
starttb = False
start = False
startballmove = False
bx = width / 2
by = height / 2
br = 40
bms = 6
bxm = random.randint(-bms, bms)
bym = random.randint(-bms, bms)
btc = by
blc = bx
bbc = by + br + br
brc = bx + br + br
circle=pygame.Surface((br * 2, br * 2))
circle.fill((0, 0, 0))
pygame.draw.circle(circle, WHITE , (br, br), br, 0)
circle.set_colorkey((0, 0, 0))
pad1 = pygame.Rect(x1, y1, squarew, squareh)
pad2 = pygame.Rect(x2, y2, squarew, squareh)
while 1:
if start and not text1b and not text2b and not text3b and not starttb and not startballmove:
text3b = True
pygame.time.set_timer(pygame.USEREVENT, 1000)
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.display.quit()
sys.exit()
elif event.type == pygame.KEYDOWN:
# pad 2 check if key is down
if event.key == pygame.K_UP:
ymb2 = True
if event.key == pygame.K_DOWN:
ymf2 = True
# pad 1 check if key is down
if event.key == pygame.K_w:
ymb1 = True
if event.key == pygame.K_s:
ymf1 = True
if event.key == pygame.K_SPACE:
start = True
elif event.type == pygame.KEYUP:
#pad 2 check if key goes up
if event.key == pygame.K_UP:
ymb2 = False
if event.key == pygame.K_DOWN:
ymf2 = False
# pad 1 check if key goes up
if event.key == pygame.K_w:
ymb1 = False
if event.key == pygame.K_s:
ymf1 = False
# check if window has been resized
if event.type == pygame.VIDEORESIZE:
width = event.dict['size'][0]
height = event.dict['size'][1]
screen = pygame.display.set_mode((width, height), pygame.RESIZABLE)
if event.type == pygame.USEREVENT:
# check if start should be hidden
if starttb:
starttb = False
startballmove = True
# check if start should be showed
if text1b and not text2b and not text3b:
text1b = False
text2b = False
text3b = False
starttb = True
# check if 1 should be showed
if text2b and not text3b and not text1b:
text3b = False
text2b = False
text1b = True
# check if 2 should be showed
if text3b and not text2b and not text1b:
text3b = False
text2b = True
text1b = False
# check if pad 1 is out of bounds and move it
if ymb1 and not (y1 <= 0): y1 -= squares
if ymf1 and not (y1 + squareh >= height): y1 += squares
if y1 > (height - squareh) + 1: y1 -= squares
# check if pad 2 is out of bounds and move it
if ymb2 and not (y2 <= 0): y2 -= squares
if ymf2 and not (y2 + squareh >= height): y2 += squares
if y2 > (height - squareh) + 1: y2 -= squares
# put pads in center if game has not started
if not start:
# pad 1
x1 = 75
y1 = (height / 2) - (squareh / 2)
# pad 2
x2 = width - 75 - squarew
y2 = (height / 2) - (squareh / 2)
#ball
bx = width / 2 - br
by = height / 2 - br
# put pads in center in x if game has started
else:
# pad 1
x1 = 75
# pad 2
x2 = width - 75 - squarew
# if ball has not started moving center it
if not startballmove:
bx = width / 2 - br
by = height / 2 - br
# check if movement variables are 0
while bxm == 0 or bym == 0:
if bxm == 0:
bxm = random.randint(-6, 6)
if bym == 0:
bym = random.randint(-6, 6)
screen.fill(BLACK)
# draw starting text if game has not started
if not start:
screen.blit(text,((width / 2) - text.get_width() // 2, (height / 4) - text.get_height() // 2))
# put 3 on screen
if start and text3b:
screen.blit(text3,((width / 2) - 15, (height / 4) - (text.get_height() / 2)))
# put 2 on screen
if start and text2b:
screen.blit(text2,((width / 2) - 15, (height / 4) - (text.get_height() / 2)))
# put 1 on screen
if start and text1b:
screen.blit(text1,((width / 2) - 15, (height / 4) - (text.get_height() / 2)))
# put start on screen
if start and starttb:
screen.blit(startt,((width / 2) - (text.get_width() / 8), (height / 4) - (text.get_height() / 2)))
# check if ball is out of bounds
btc = by
blc = bx
bbc = by + br + br
brc = bx + br + br
if start and startballmove:
# screen
if btc <= 0:
bym = bym * -1
print("top side")
if bbc >= height:
bym = bym * -1
print("bottom side")
if blc <= 0:
bxm = bxm * -1
print("left side")
if brc >= width:
bxm = bxm * -1
print("right side")
# left pad
pad1 = pygame.Rect(x1, y1, squarew, squareh)
if pad1.collidepoint(int(bx), int(by)):
bxm = bxm * -1
bx += abs(bxm)
print("Collision")
# move ball
if start and startballmove:
bx += bxm
by += bym
# draw circle if game start
if start:
screen.blit(circle, (int(bx), int(by)))
# draw pad 1
pad1 = pygame.Rect(x1, y1, squarew, squareh)
pygame.draw.rect(screen, WHITE, pad1, 0)
# draw pad 2
pad2 = pygame.Rect(x2, y2, squarew, squareh)
pygame.draw.rect(screen, WHITE, pad2, 0)
pygame.display.flip()
clock.tick(FPS)
Does anyone know how to do this? I have only recently learned to program in python and pygame.
You have to split move and cheking collision on two steps. First move only in X and then you can recognize front collision. Later move in Y and you can recogize side collision.
Your code is big mess so it may need a lot changes. You should organize code and use better names for variables to make it more readable.
And you could use elif
and nested if
so it will be cleaner.
import sys
import pygame
import random
import math
# --- constants --- (UPPER_CASE_NAMES)
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
FPS = 60
SQUARE_HEIGHT = 275
SQUARE_WIDTH = 35
SQUARE_SPEED = 3
BALL_R = 40
# --- main ---
window_width = 1200
window_height = 675
# - init -
pygame.init()
screen = pygame.display.set_mode((window_width, window_height), pygame.RESIZABLE)
screen_rect = screen.get_rect()
# - text -
font = pygame.font.SysFont("arial", 30)
# - text - press space -
text_press_space = font.render("Press Space to start", True, WHITE)
text_press_space_rect = text_press_space.get_rect()
text_press_space_rect.centerx = screen_rect.centerx
text_press_space_rect.centery = screen_rect.height // 4
# - text - count down -
text_1 = font.render("1", True, WHITE)
text_1_rect = text_1.get_rect()
text_1_rect.centerx = screen_rect.centerx
text_1_rect.centery = screen_rect.height // 4
text_2 = font.render("2", True, WHITE)
text_2_rect = text_2.get_rect()
text_2_rect.centerx = screen_rect.centerx
text_2_rect.centery = screen_rect.height // 4
text_3 = font.render("3", True, WHITE)
text_3_rect = text_3.get_rect()
text_3_rect.centerx = screen_rect.centerx
text_3_rect.centery = screen_rect.height // 4
text_start = font.render("Start!", True, WHITE)
text_start_rect = text_start.get_rect()
text_start_rect.centerx = screen_rect.centerx
text_start_rect.centery = screen_rect.height // 4
display_text_3 = False
display_text_2 = False
display_text_1 = False
display_text_start = False
# - ball -
ball = pygame.Surface((BALL_R * 2, BALL_R * 2))
# circle.fill(BLACK) # not need it because surface is black as default
ball.set_colorkey(BLACK)
pygame.draw.circle(ball, WHITE , (BALL_R, BALL_R), BALL_R, 0)
ball_rect = ball.get_rect()
ball_rect.center = screen_rect.center
ball_speed = 6
ball_speed_x = ball_speed * random.choice([1, -1])
ball_speed_y = ball_speed * random.choice([1, -1])
ball_move = False
# - pads -
pad1_rect = pygame.Rect(0, 0, SQUARE_WIDTH, SQUARE_HEIGHT)
pad1_rect.left = 100
pad1_rect.centery = screen_rect.centery
pad1_move_up = False
pad1_move_down = False
pad2_rect = pygame.Rect(0, 0, SQUARE_WIDTH, SQUARE_HEIGHT)
pad2_rect.right = screen_rect.right - 100
pad2_rect.centery = screen_rect.centery
pad2_move_up = False
pad2_move_down = False
# --- mainloop ---
play_start = False
clock = pygame.time.Clock()
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
elif event.type == pygame.KEYDOWN:
# pad 2 check if key is down
if event.key == pygame.K_UP:
pad2_move_up = True
elif event.key == pygame.K_DOWN:
pad2_move_down = True
# pad 1 check if key is down
elif event.key == pygame.K_w:
pad1_move_up = True
elif event.key == pygame.K_s:
pad1_move_down = True
elif event.key == pygame.K_SPACE:
if not play_start:
play_start = True
pygame.time.set_timer(pygame.USEREVENT, 1000)
display_text_3 = True
elif event.type == pygame.KEYUP:
#pad 2 check if key goes up
if event.key == pygame.K_UP:
pad2_move_up = False
elif event.key == pygame.K_DOWN:
pad2_move_down = False
# pad 1 check if key goes up
elif event.key == pygame.K_w:
pad1_move_up = False
elif event.key == pygame.K_s:
pad1_move_down = False
# check if window has been resized
if event.type == pygame.VIDEORESIZE:
window_width = event.dict['size'][0]
window_height = event.dict['size'][1]
screen = pygame.display.set_mode((window_width, window_height), pygame.RESIZABLE)
screen_rect = screen.get_rect()
if event.type == pygame.USEREVENT:
if display_text_3:
display_text_3 = False
display_text_2 = True
elif display_text_2:
display_text_2 = False
display_text_1 = True
elif display_text_1:
display_text_1 = False
display_text_start = True
elif display_text_start:
display_text_start = False
ball_move = True
# - moves (without draws) -
# move paddle 1
if pad1_move_up and pad1_rect.top > 0: # > screen_rect.top:
pad1_rect.y -= SQUARE_SPEED
if pad1_rect.top < 0:
pad1_rect.top = 0
if pad1_move_down and pad1_rect.bottom < screen_rect.bottom:
pad1_rect.y += SQUARE_SPEED
if pad1_rect.bottom > screen_rect.bottom:
pad1_rect.bottom = screen_rect.bottom
# move paddle 2
if pad2_move_up and pad2_rect.top > 0: # > screen_rect.top:
pad2_rect.y -= SQUARE_SPEED
if pad2_rect.top < 0:
pad2_rect.top = 0
if pad2_move_down and pad2_rect.bottom < screen_rect.bottom:
pad2_rect.y += SQUARE_SPEED
if pad2_rect.bottom > screen_rect.bottom:
pad2_rect.bottom = screen_rect.bottom
# check if ball is out of bounds
if play_start:
# move ball
if ball_move:
ball_rect.x += ball_speed_x
# check FRONT collision with pads
if pad1_rect.colliderect(ball_rect):
#if
ball_rect.left = pad1_rect.right
ball_speed_x = -ball_speed_x
print("Front collision right pad")
if pad2_rect.colliderect(ball_rect):
ball_rect.right = pad2_rect.left
ball_speed_x = -ball_speed_x
print("Front collision left pad")
ball_rect.y += ball_speed_y
# check SIDE collision with pads
if pad1_rect.colliderect(ball_rect):
# move from top
if ball_speed_y > 0:
ball_rect.bottom = pad1_rect.top
print("Top collision right pad")
# move from bottom
else: # elif ball_speed_y < 0:
ball_rect.top = pad1_rect.bottom
print("Bottom collision right pad")
# change both or only Y (depends on what effect you need)
ball_speed_x = -ball_speed_x
ball_speed_y = -ball_speed_y
if pad2_rect.colliderect(ball_rect):
# move from top
if ball_speed_y > 0:
ball_rect.bottom = pad2_rect.top
print("Top collision left pad")
# move from bottom
else: # if ball_speed_y < 0:
ball_rect.top = pad2_rect.bottom
print("Bottom collision left pad")
# change both or only Y (depends on what effect you need)
ball_speed_x = -ball_speed_x
ball_speed_y = -ball_speed_y
# check collision with border
if ball_rect.left <= 0: # <= screen_rect.left:
ball_speed_x = -ball_speed_x
print("left side")
print("point for left player")
# move ball to center
ball_rect.center = screen_rect.center
ball_speed_x = ball_speed * random.choice([1, -1])
ball_speed_y = ball_speed * random.choice([1, -1])
if ball_rect.right >= screen_rect.right:
ball_speed_x = -ball_speed_x
print("right side")
print("point for right player")
# move ball to center
ball_rect.center = screen_rect.center
ball_speed_x = ball_speed * random.choice([1, -1])
ball_speed_y = ball_speed * random.choice([1, -1])
if ball_rect.top <= 0: # <= screen_rect.top:
ball_speed_y = -ball_speed_y
print("top side")
if ball_rect.bottom >= screen_rect.bottom:
ball_speed_y = -ball_speed_y
print("bottom side")
# - draws (without moves) -
screen.fill(BLACK)
if not play_start:
screen.blit(text_press_space, text_press_space_rect)
else: # if play_start:
if display_text_3:
screen.blit(text_3, text_3_rect)
if display_text_2:
screen.blit(text_2, text_2_rect)
if display_text_1:
screen.blit(text_1, text_1_rect)
if display_text_start:
screen.blit(text_start, text_start_rect)
screen.blit(ball, ball_rect)
# draw pads
pygame.draw.rect(screen, WHITE, pad1_rect, 0)
pygame.draw.rect(screen, WHITE, pad2_rect, 0)
pygame.display.flip()
clock.tick(FPS)
# --- end ---
pygame.quit()