I have made a pong game. Now the problem is that when I move the paddle, the ball doesn't go past it but bounces of some invisible wall. Here is my code and run it yourselves and you can see the problem(You have to move the paddles around a little bit)
# Pong
# Importing libraries
import pygame
import random
import time
# Initializing PyGame
pygame.init()
# Creating a font
font = pygame.font.SysFont(None, 30)
# Set the height and width of the screen
window_width = 700
window_height = 500
size = [window_width, window_height]
game_win = pygame.display.set_mode(size)
# Creating a messaging system
def message(sentence, x, y):
sentence = font.render(sentence, True, white)
game_win.blit(sentence, [x, y])
# Creating a color
white = (225, 225, 225)
black = (0, 0, 0)
# Setting up ball
ball_size = 25
class Ball:
"""
Class to keep track of a ball's location and vector.
"""
def __init__(self):
self.x = 0
self.y = 0
self.change_x = 0
self.change_y = 0
def make_ball():
ball = Ball()
# Starting position of the ball.
# Take into account the ball size so we don't spawn on the edge.
ball.x = 350
ball.y = 250
# Speed and direction of rectangle
ball.change_x = 5
ball.change_y = 5
return ball
def main():
# Scores
left_score = 0
right_score = 0
pygame.init()
pygame.display.set_caption("Ping Pong")
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
ball_list = []
ball = make_ball()
ball_list.append(ball)
# Right paddle coordinates
y = 200
y_change = 0
x = 50
# Left paddle coordinates
y1 = 200
y1_change = 0
x1 = 650
while not done:
# --- Event Processing
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
y_change = -5
elif event.key == pygame.K_s:
y_change = 5
elif event.key == pygame.K_UP:
y1_change = -5
elif event.key == pygame.K_DOWN:
y1_change = 5
elif event.type == pygame.KEYUP:
y_change = 0
y1_change = 0
y += y_change
y1 += y1_change
if y > window_height - 100:
y -= 5
if y < 50:
y += 5
if y1 > window_height - 100:
y1 -= 5
if y1 < 50:
y1 += 5
message("Left player score: " + str(left_score), 10, 10)
message("Right player score: " + str(right_score), 490, 10)
# Drawing a left paddle
pygame.draw.rect(game_win, white, [x, y, 25, 100])
# Drawing a right paddle
pygame.draw.rect(game_win, white, [x1, y1, 25, 100])
# Updating screen to changes take place
pygame.display.update()
# Logic
for ball in ball_list:
# Move the ball's center
ball.x += ball.change_x
ball.y += ball.change_y
# Bounce the ball if needed
if ball.y > 50 - ball_size or ball.y < ball_size:
ball.change_y *= -1
if ball.x > window_width - ball_size:
ball.change_x *= -1
left_score += 1
if ball.x < ball_size:
ball.change_x *= -1
right_score += 1
# Here is the part where it all becomes weird and buggy
if ball.x-ball_size <= x <= ball.x + ball_size:
ball.change_x *= -1
if ball.x-ball_size <= x1 <= ball.x + ball_size:
ball.change_x *= -1
if ball.y-ball_size <= y <= ball.y + ball_size:
ball.change_x *= -1
if ball.y-ball_size <= y1 <= ball.y + ball_size:
ball.change_x *= -1
if right_score == 10:
message('RIGHT PLAYER HAS WON!!', 300, 200)
time.sleep(10)
done = True
elif left_score == 10:
message("LEFT PLAYER HAS WON!!", 300, 200)
time.sleep(10)
done = True
# Drawing
# Set the screen background
game_win.fill(black)
# Draw the balls
for ball in ball_list:
pygame.draw.circle(game_win, white, [ball.x, ball.y], ball_size)
# Wrap-up
# Limit to 60 frames per second
clock.tick(60)
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# Close everything down
pygame.quit()
if __name__ == "__main__":
main()
When I move the paddle away, the ball can still bounce off some invisible wall. Everything else is good, just the part where I have put # Bounce if needed
.
I recommend to compute the bounding rectangle of the ball and the paddles and to use pygame.Rect
and colliderect()
to detect the collision between a ball and a paddle.
See alos Sometimes the ball doesn't bounce off the paddle in pong game.
For instance:
def main():
# [...]
while not done:
# [...]
# Logic
for ball in ball_list:
# [...]
ball_rect = pygame.Rect(ball.x-ball_size, ball.y-ball_size, ball_size*2, ball_size*2)
left_paddle_rect = pygame.Rect(x, y, 25, 75)
if ball.change_x < 0 and ball_rect.colliderect(left_paddle_rect):
ball.change_x = abs(ball.change_x)
right_paddle_rect = pygame.Rect(x1, y1, 25, 75)
if ball.change_x > 0 and ball_rect.colliderect(right_paddle_rect):
ball.change_x = -abs(ball.change_x)
Furthermore, there the height of the window is 500 rather than 50_
if ball.y > 50 - ball_size or ball.y < ball_size:
if ball.y > 500 - ball_size or ball.y < ball_size:
I recommend to remove the multiple calls to pygame.display.flip()
respectively pygame.display.update()
. Do just one update of the display at the end of the main application loop. See the complete example:
# Importing libraries
import pygame
import random
import time
# Initializing PyGame
pygame.init()
# Creating a font
font = pygame.font.SysFont(None, 30)
# Set the height and width of the screen
window_width = 700
window_height = 500
size = [window_width, window_height]
game_win = pygame.display.set_mode(size)
# Creating a messaging system
def message(sentence, x, y):
sentence = font.render(sentence, True, white)
game_win.blit(sentence, [x, y])
# Creating a color
white = (225, 225, 225)
black = (0, 0, 0)
# Setting up ball
ball_size = 25
class Ball:
"""
Class to keep track of a ball's location and vector.
"""
def __init__(self):
self.x = 0
self.y = 0
self.change_x = 0
self.change_y = 0
def make_ball():
ball = Ball()
# Starting position of the ball.
# Take into account the ball size so we don't spawn on the edge.
ball.x = 350
ball.y = 250
# Speed and direction of rectangle
ball.change_x = 5
ball.change_y = 5
return ball
def main():
# Scores
left_score = 0
right_score = 0
pygame.init()
pygame.display.set_caption("Ping Pong")
# Loop until the user clicks the close button.
done = False
# Used to manage how fast the screen updates
clock = pygame.time.Clock()
ball_list = []
ball = make_ball()
ball_list.append(ball)
# Right paddle coordinates
y = 200
y_change = 0
x = 50
# Left paddle coordinates
y1 = 200
y1_change = 0
x1 = 650
while not done:
# --- Event Processing
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
elif event.type == pygame.KEYDOWN:
if event.key == pygame.K_w:
y_change = -5
elif event.key == pygame.K_s:
y_change = 5
elif event.key == pygame.K_UP:
y1_change = -5
elif event.key == pygame.K_DOWN:
y1_change = 5
elif event.type == pygame.KEYUP:
y_change = 0
y1_change = 0
y += y_change
y1 += y1_change
if y > window_height - 100:
y -= 5
if y < 50:
y += 5
if y1 > window_height - 100:
y1 -= 5
if y1 < 50:
y1 += 5
message("Left player score: " + str(left_score), 10, 10)
message("Right player score: " + str(right_score), 490, 10)
# Logic
for ball in ball_list:
# Move the ball's center
ball.x += ball.change_x
ball.y += ball.change_y
# Bounce the ball if needed
if ball.y > 500 - ball_size or ball.y < ball_size:
ball.change_y *= -1
if ball.x > window_width - ball_size:
ball.change_x *= -1
left_score += 1
if ball.x < ball_size:
ball.change_x *= -1
right_score += 1
# Here is the part where it all becomes weird and buggy
ball_rect = pygame.Rect(ball.x-ball_size, ball.y-ball_size, ball_size*2, ball_size*2)
left_paddle_rect = pygame.Rect(x, y, 25, 75)
if ball.change_x < 0 and ball_rect.colliderect(left_paddle_rect):
ball.change_x = abs(ball.change_x)
right_paddle_rect = pygame.Rect(x1, y1, 25, 75)
if ball.change_x > 0 and ball_rect.colliderect(right_paddle_rect):
ball.change_x = -abs(ball.change_x)
if right_score == 10:
message('RIGHT PLAYER HAS WON!!', 300, 200)
time.sleep(10)
done = True
elif left_score == 10:
message("LEFT PLAYER HAS WON!!", 300, 200)
time.sleep(10)
done = True
# Drawing
# Set the screen background
game_win.fill(black)
# Drawing a left paddle
pygame.draw.rect(game_win, white, [x, y, 25, 100])
# Drawing a right paddle
pygame.draw.rect(game_win, white, [x1, y1, 25, 100])
# Draw the balls
for ball in ball_list:
pygame.draw.circle(game_win, white, [ball.x, ball.y], ball_size)
# Go ahead and update the screen with what we've drawn.
pygame.display.flip()
# Wrap-up
# Limit to 60 frames per second
clock.tick(60)
# Close everything down
pygame.quit()
if __name__ == "__main__":
main()