pythonpygamepong

Pong on pygame, ball always bouncing despite not colliding with the paddle


I'm failly new to programming in general and this is my second game ever so sorry in advance. I made a pong game with only one paddle for now, but the ball keeps bouncing even when it's not hitting the paddle. This is my draw ball function:

    def draw_ball(self): 
        self.sc.blit(ball, (self.bx,self.by))
        self.bx += self.speedx
        self.by += self.speedy

        if self.bx >= 1000:#check goals
            self.bx = 250
            self.by = 340

        if self.bx <= 38: #check coalision
            self.speedx *= -1
        if self.by<= 12: 
            self.speedy *= -1
        if  self.by>= 725: 
            self.speedy *= -1
        
        #check coalision with the paddle 
        #px and py are the coordinates of the paddle 
        if self.bx > (self.px - 35) and (self.by < (self.py + 196) and  (self.by + 38) > self.py) : 
            self.speedx *= -1

Here is the main loop:

#global variables
WIN_HEIGHT = 1024 
WIN_WIDTH = 768 
SPEED = 5 
PX = 956
PY  = 320 
MOVEMENT = 5
BALL = Ball(550, 60, screen, .5, .4, PX, PY)


running = True 
while running: 

  redraw_screen()

  for event in pygame.event.get():
    if event.type == pygame.QUIT:
      running = False
    mouse_pos = pygame.mouse.get_pos()
    if event.type == pygame.MOUSEBUTTONDOWN and START_BUTTON.is_clicked(mouse_pos):
      running = False
      playing = True

     while playing: 
        screen.fill((0,0,0))
        BALL.draw_ball()
        PLAYER.draw_player()
        pygame.display.flip()

        for event in pygame.event.get():
          if event.type == pygame.QUIT:
            running = False
            playing = False 

Thanks for your help.


Solution

  • I recommend to use pygame.Rect objects and the method .colliderect()

    Define rectangles for the ball, paddle and screen or get the rectangles from a pygame.Surface by .get_rect():

    ball_rect = ball.get_rect(topleft = (self.bx, self.by))
    right_paddle_rect = pygame.Rect(self.px, self.py, 38, 196)
    screen_rect = self.sc.get_rect()
    

    Test the collision of the ball and the borders of the screen:

    if ball_rect.top < screen_rect.top or ball_rect.bottom > screen_rect.bottom:
        self.speedy *= -1
    if ball_rect.left < screen_rect.left:
        self.speedx *= -1
    if ball_rect.right > screen_rect.right:
        self.bx = 250
        self.by = 340
    

    Be carful when you test the collision between the ball and the paddle. See Sometimes the ball doesn't bounce off the paddle in pong game:

    if ball_rect.colliderect(right_paddle_rect):
                self.speedx = -abs(self.speedx) 
    

    Complete method draw_ball:

    def draw_ball(self):
        self.sc.blit(ball, (self.bx, self.by))
    
        self.bx += self.speedx
        self.by += self.speedy
    
        ball_rect = ball.get_rect(topleft = (self.bx, self.by))
        right_paddle_rect = pygame.Rect(self.px, self.py, 38, 196)
        screen_rect = self.sc.get_rect()
    
        if ball_rect.top < screen_rect.top or ball_rect.bottom > screen_rect.bottom:
            self.speedy *= -1
        if ball_rect.left < screen_rect.left:
            self.speedx *= -1
        if ball_rect.right > screen_rect.right:
            self.bx = 250
            self.by = 340
    
        if ball_rect.colliderect(right_paddle_rect):
            self.speedx = -abs(self.speedx) 
    

    Minimal example:

    import pygame
    
    class Game:
        def __init__(self, screen):
            self.sc = screen
            self.bx, self.by = 250, 340
            self.speedx, self.speedy = 5, 5
            self.px, self.py = 700, 200
    
        def draw_ball(self):
            self.sc.blit(ball, (self.bx, self.by))
    
            self.bx += self.speedx
            self.by += self.speedy
    
            ball_rect = ball.get_rect(topleft = (self.bx, self.by))
            right_paddle_rect = pygame.Rect(self.px, self.py, 38, 196)
            screen_rect = self.sc.get_rect()
    
            if ball_rect.top < screen_rect.top or ball_rect.bottom > screen_rect.bottom:
                self.speedy *= -1
            if ball_rect.left < screen_rect.left:
                self.speedx *= -1
            if ball_rect.right > screen_rect.right:
                self.bx = 250
                self.by = 340
    
            if ball_rect.colliderect(right_paddle_rect):
                self.speedx = -abs(self.speedx) 
    
    pygame.init()
    screen = pygame.display.set_mode((800, 600))
    clock = pygame.time.Clock()
    
    ball = pygame.Surface((38, 38), pygame.SRCALPHA)
    pygame.draw.circle(ball, (255, 255, 255), (19, 19), 19)
    game = Game(screen)
    
    run = True
    while run:
        clock.tick(60)
    
        # event loop
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
            if event.type == pygame.KEYDOWN:
                print(pygame.key.name(event.key))
    
        keys = pygame.key.get_pressed()
        pspeed = 5
        if keys[pygame.K_UP]:
           game.py = max(0, game.py - pspeed) 
        if keys[pygame.K_DOWN]:
           game.py = min(screen.get_height()-196, game.py + pspeed) 
    
        screen.fill(0)
        game.draw_ball()
        pygame.draw.rect(screen, (255, 255, 255), (game.px, game.py, 38, 196)) 
        pygame.display.flip()