Search code examples
pythonpygame

Rectangle Collision with each other


I am currently trying to create a pong game but for some reason, the ball would not bounce off of the rectangles and I am not sure where I have made a mistake even though I followed a video about rectangle collision online. Please let me know where I made a mistake and how I can improve my code. Thanks!

import pygame, sys, random, time

from pygame.time import Clock


pygame.init()

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

# Display
screen_width = 1000
screen_height = 600
screen = pygame.display.set_mode((screen_width, screen_height))
pygame.display.set_caption("2-player Pong")

# Rectangles
class Rectangle():
    def __init__(self, screen, x):
        self.screen = screen 
        self.screen_rect= screen.get_rect()
        self.x = x 
        self.y = 250
        self.width = 30 
        self.height = 100
        self.rect = pygame.Rect(self.x, self.y, self.width, self.height)
        self.colour = black
        self.velocity = 5

    def draw_rectangle(self): 
        pygame.draw.rect(self.screen, self.colour, self.rect)

rect1 = Rectangle(screen, 50)
rect2 = Rectangle(screen, 920)

class Ball(): 
    def __init__(self, colour):
        self.screen = screen 
        self.colour = colour 
        self.width = 20
        self.height = 20
        self.x = screen_width//2 - 25
        self.y = screen_height//2 - 25
        self.rect = pygame.Rect(self.x, self.y, self.width, self.height)
        self.possible_velocities_x = [-4, 4]
        self.possible_velocities_y = [-2, 2]
        self.velocity = [random.choice(self.possible_velocities_x), random.choice(self.possible_velocities_y)]

    def draw_ball(self):
        pygame.draw.rect(self.screen, self.colour, self.rect)
    
    def move_ball(self):
        global rect1, rect2
        self.rect.x += self.velocity[0]
        self.rect.y += self.velocity[1]

        # Collision with Screen 
        if self.rect.top <= 10 or self.rect.bottom >= screen_height - 10: 
            self.velocity[1] *= -1

        # Collision with Rectangles
        if self.rect.colliderect(rect1) or self.rect.colliderect(rect2):
            if self.rect.left - rect1.rect.right == 0:
                self.possible_velocities_x *= -1 
            if self.rect.right - rect2.rect.left == 0: 
                self.possible_velocities_x *= -1 

clock = pygame.time.Clock()

ball = Ball(white)

pong = True 

while pong:
    pygame.time.delay(10)
    clock.tick(100)
    # Watch for keyboard and mouse events.
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
                pong = False 

    keys = pygame.key.get_pressed()

    if keys[pygame.K_UP] and rect2.rect.y >= 0:
        rect2.rect.y -= rect2.velocity

    if keys[pygame.K_DOWN] and rect2.rect.y <= 600 - rect2.rect.height:
        rect2.rect.y += rect2.velocity

    if keys[pygame.K_w] and rect1.rect.y >= 0:
        rect1.rect.y -= rect1.velocity

    if keys[pygame.K_s] and rect1.rect.y <= 600 - rect1.rect.height:
        rect1.rect.y += rect1.velocity
        
    screen.fill(green)

    rect1.draw_rectangle()
    rect2.draw_rectangle()
    ball.draw_ball()
    ball.move_ball()
    
    # pygame.draw.rect(screen, black, (rect_x2, rect_y2, rect_width2, rect_height2))

    pygame.display.update() # Make the most recently drawn screen visible.

pygame.quit()

Solution

  • You must change self.velocity[0] when the ball touches the paddle. Since the movement of the ball is more than 1 pixel per frame, the ball does not exactly touch the paddle. This mans the condition self.rect.left - rect1.rect.right == 0 and self.rect.right - rect2.rect.left == 0 will not be fulfilled. If the movement in x direction is negative, the new movement needs to be positive (abs(self.velocity[0])). If the movement in x direction is positive, the new movement needs to be negative (-abs(self.velocity[0])):

    class Ball():
        # [...]
    
        def move_ball(self):
            self.rect.x += self.velocity[0]
            self.rect.y += self.velocity[1]
    
            # Collision with Screen 
            if self.rect.top <= 10 or self.rect.bottom >= screen_height - 10: 
                self.velocity[1] *= -1
    
            # Collision with Rectangles
            if self.rect.colliderect(rect1) or self.rect.colliderect(rect2):
                if self.velocity[0] < 0:
                    self.velocity[0] = abs(self.velocity[0])
                else:
                    self.velocity[0] = -abs(self.velocity[0])
    

    See also Sometimes the ball doesn't bounce off the paddle in pong game