Search code examples
pythonpython-3.xpygamebreakout

How to Make the Ball Bounce only if it Hits the Paddle in Python, Pygame (Breakout Recreation)


can anyone help me with this? i am having trouble making a simple way to detect if a ball hits a paddle and then bounce it by changing the rect_change_y variable. here is code that works but the ball does not interact with paddle or die when it hits the bottom of the game.

import pygame

black = ( 0, 0, 0)
white = ( 255, 255, 255)
green = ( 0, 255, 0)
red = ( 255, 0, 0)

rect_x = 10
rect_y = 250

pad_x = 350
pad_y = 480

ball = 3

rect_change_x = 1
rect_change_y = 1

pad_x_c = 0

pygame.init()

size=[700,500]
screen=pygame.display.set_mode(size)

pygame.mouse.set_visible(0)

pygame.display.set_caption("Breakout Recreation WIP")

done=False

clock=pygame.time.Clock()
# -------- Main Program Loop -----------
while ball != 0:
    # ALL EVENT PROCESSING SHOULD GO BELOW THIS COMMENT
    for event in pygame.event.get(): # User did something
        if event.type == pygame.QUIT: # If user clicked close
            done=True # Flag that we are done so we exit this loop
        keys = pygame.key.get_pressed()  #checking pressed keys
        if keys[pygame.K_LEFT]:
            pad_x_c -= 2
        elif keys[pygame.K_RIGHT]:
            pad_x_c += 2  
        else :
            pad_x_c = 0
    # ALL EVENT PROCESSING SHOULD GO ABOVE THIS COMMENT
    # ALL GAME LOGIC SHOULD GO BELOW THIS COMMENT
    # ALL GAME LOGIC SHOULD GO ABOVE THIS COMMENT
    # ALL CODE TO DRAW SHOULD GO BELOW THIS COMMENT
    # First, clear the screen to white. Don't put other drawing commands
    # above this, or they will be erased with this command.
    screen.fill(black)
    # Draw the rectangle
    pygame.draw.rect(screen,white,[rect_x,rect_y,15,15])
    pygame.draw.rect(screen,white,[pad_x,pad_y,50,10])
    # Move the rectangle starting point
    rect_x += rect_change_x
    rect_y += rect_change_y
    pad_x += pad_x_c
    # Bounce the ball if needed
    if rect_y > 480 or rect_y < 10:
        rect_change_y = rect_change_y * -1
    if rect_x > 680 or rect_x < 5:
        rect_change_x = rect_change_x * -1    
    if pad_x <= 5 :
        pad_x_c = 0
    if pad_x >= 645 :
        pad_x_c = 0
    # ALL CODE TO DRAW SHOULD GO ABOVE THIS COMMENT

    pygame.display.flip()

    clock.tick(100)

pygame.quit ()

and then here is code that should work (to me) but doesnt.

import pygame

black = ( 0, 0, 0)
white = ( 255, 255, 255)
green = ( 0, 255, 0)
red = ( 255, 0, 0)

rect_x = 10
rect_y = 250

pad_x = 350
pad_y = 480

ball = 3

rect_change_x = 1
rect_change_y = 1

pad_x_c = 0

pygame.init()

size=[700,500]
screen=pygame.display.set_mode(size)

pygame.mouse.set_visible(0)

pygame.display.set_caption("Breakout Recreation WIP")

done=False

clock=pygame.time.Clock()
# -------- Main Program Loop -----------
while ball != 0:
    # ALL EVENT PROCESSING SHOULD GO BELOW THIS COMMENT
    for event in pygame.event.get(): # User did something
        if event.type == pygame.QUIT: # If user clicked close
            done=True # Flag that we are done so we exit this loop
        keys = pygame.key.get_pressed()  #checking pressed keys
        if keys[pygame.K_LEFT]:
            pad_x_c -= 2
        elif keys[pygame.K_RIGHT]:
            pad_x_c += 2  
        else :
            pad_x_c = 0
    # ALL EVENT PROCESSING SHOULD GO ABOVE THIS COMMENT
    # ALL GAME LOGIC SHOULD GO BELOW THIS COMMENT
    # ALL GAME LOGIC SHOULD GO ABOVE THIS COMMENT
    # ALL CODE TO DRAW SHOULD GO BELOW THIS COMMENT
    # First, clear the screen to white. Don't put other drawing commands
    # above this, or they will be erased with this command.
    screen.fill(black)
    # Draw the rectangle
    pygame.draw.rect(screen,white,[rect_x,rect_y,15,15])
    pygame.draw.rect(screen,white,[pad_x,pad_y,50,10])
    # Move the rectangle starting point
    rect_x += rect_change_x
    rect_y += rect_change_y
    pad_x += pad_x_c
    # Bounce the ball if needed
    if rect_y == pad_y:
        if rect_x == pad_x:
            rect_change_y = rect_change_y * -1
    if rect_y > 490:
        ball -= 1
        rect_y = 250
        rect_x = 10
        rect_change_x = 1
        rect_change_y = 1
    if rect_y < 10:
        rect_change_y = rect_change_y * -1
    if rect_x > 680 or rect_x < 5:
        rect_change_x = rect_change_x * -1       
    if pad_x <= 5 :
        pad_x_c = 0
    if pad_x >= 645 :
        pad_x_c = 0
    # ALL CODE TO DRAW SHOULD GO ABOVE THIS COMMENT

    pygame.display.flip()

    clock.tick(100)

pygame.quit ()

finally, any suggestions on how to make the blocks and do the same thing to them, except destroying them instead of the ball?

Thanks Everyone!


Solution

  • You can use the Rect class to represent the ball and the paddle, and also take advantage of the methods this class provides:

    • Rect.move_ip to move the rectangles in place:

      myrect = pygame.Rect(0, 0, 10, 10)
      myrect.move_ip(100, 50)
      

      myrect top left corner is at (100, 50) and keeps the same width and height.

    • Rect.clamp_ip to ensure the rectangles are both inside the screen.

      myrect = pygame.Rect(100, 0, 10, 10)
      bounds = pygame.Rect(0, 0, 50, 50)
      myrect.clamp_ip(bounds)
      

      myrect top left corner is at (40, 0) and its bottom right corner at (10, 50), inside bounds rectangle.

    • Rect.colliderect to check if the ball and the paddle collide.

      myrect = pygame.Rect(0, 0, 10, 10)
      another = pygame.Rect(5, 5, 10, 10)
      print(myrect.colliderect(another)) # 1
      

      Since myrect and another overlap, when you call colliderect it returns 1, indicating that there is a collision between the two rectangles.


    I really like Pygame, so I don't mind to rewrite your program applying these suggestions. Hope it helps:

    import pygame
    
    # Constants
    WIDTH = 700
    HEIGHT = 500
    SCREEN_AREA = pygame.Rect(0, 0, WIDTH, HEIGHT)
    BLACK = (0, 0, 0)
    WHITE = (255, 255, 255)
    
    # Initialization
    pygame.init()
    screen = pygame.display.set_mode([WIDTH, HEIGHT])
    pygame.mouse.set_visible(0)
    pygame.display.set_caption("Breakout Recreation WIP")
    clock = pygame.time.Clock()
    
    # Variables
    paddle = pygame.Rect(350, 480, 50, 10)
    ball = pygame.Rect(10, 250, 15, 15)
    paddle_movement_x = 0
    ball_direction = (1, 1)
    balls = 3
    done = False
    
    while not done and balls > 0:
    
        # Process events
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                done = True
            keys = pygame.key.get_pressed()
            if keys[pygame.K_LEFT]:
                paddle_movement_x = -2
            elif keys[pygame.K_RIGHT]:
                paddle_movement_x = 2
            else:
                paddle_movement_x = 0
    
        # Move paddle
        paddle.move_ip(paddle_movement_x, 0)
        paddle.clamp_ip(SCREEN_AREA)
    
        # Move ball
        ball.move_ip(*ball_direction)
        if ball.right > WIDTH or ball.left < 0:
            ball_direction = -ball_direction[0], ball_direction[1]
        elif ball.top < 0 or ball.bottom > HEIGHT or paddle.colliderect(ball):
            ball_direction = ball_direction[0], -ball_direction[1]
        ball.clamp_ip(SCREEN_AREA)
    
        # Redraw screen
        screen.fill(BLACK)
        pygame.draw.rect(screen, WHITE, paddle)
        pygame.draw.rect(screen, WHITE, ball)
        pygame.display.flip()
        clock.tick(100)
    
    pygame.quit()