Search code examples
pythonpython-2.7pygamepong

why is there more than 1 ball and how can i fix it?


hello i am pretty new to programming with pygame and i have this code:

import sys, pygame

pygame.init()
screen = pygame.display.set_mode((800, 368))
background = pygame.image.load("background.png")
background.convert()
screen.blit(background, (0, 0))

speed = [1, 1]
width = 800
height = 368

ball = pygame.image.load("ball.bmp")
ballrect = ball.get_rect()
player1 = pygame.image.load("player1.png")
player1rect = player1.get_rect()

while 1:
    for event in pygame.event.get():
        if event.type == pygame.QUIT: 
            sys.exit()              

    ballrect = ballrect.move(speed)
    if ballrect.left < 0 or ballrect.right > width:
        speed[0] = -speed[0]
    if ballrect.top < 0 or ballrect.bottom > height:
        speed[1] = -speed[1]

    screen.blit(ball, ballrect)
    screen.blit(player1, player1rect)
    pygame.display.update()

but when i run it there comes too many balls it should only be one ball. and there comes more and more balls.


Solution

  • Fredrik Håård is right about re-drawing the background.

    The screen acts as an image, and when you call screen.blit() you draw over part of that image. When the while 1: loop repeats, your image already has one or more copies of the ball on it, and your current code simply draws another image of the ball onto screen.

    You can draw the background before you move the ball, thus avoiding adding a new variable to hold the previous ball position.

    ...
    while 1:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            sys.exit()
    
        screen.blit(background, ballrect, ballrect) #redraw background over old ball location
        ballrect = ballrect.move(speed)
        if ballrect.left < 0 or ballrect.right > width:
            speed[0] = -speed[0]
        if ballrect.top < 0 or ballrect.bottom > height:
            speed[1] = -speed[1]
    
        screen.blit(ball, ballrect)
        screen.blit(player1, player1rect)
        pygame.display.update()
    

    Alternatively, you can reconstruct the entire screen each time, by replacing screen.blit(background, ballrect, ballrect) above with screen.blit(background, (0, 0)), which ensures that the background is correct for each 'frame', but is significantly slower.

    My preferred approach is to note that you can pass pygame.display.update() a list of rectangles, which makes the call return much quicker. Make sure you do an initial, full screen, display update before entering the while loop:

    ...
    pygame.display.update()
    
    while 1:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
    
        old_ballrect = ballrect
        screen.blit(background, old_ballrect, old_ballrect) #redraw background over old ball location
        ballrect = ballrect.move(speed)
        if ballrect.left < 0 or ballrect.right > width:
            speed[0] = -speed[0]
        if ballrect.top < 0 or ballrect.bottom > height:
            speed[1] = -speed[1]
    
        screen.blit(ball, ballrect)
        screen.blit(player1, player1rect)
        pygame.display.update([old_ballrect, ballrect])