2

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.

hmood
  • 603
  • 7
  • 25

1 Answers1

1

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()
Rabbid76
  • 202,892
  • 27
  • 131
  • 174