Skip to content

Scrolling background with Python

This is a follow up to an earlier post where we created a scrolling background in Flash using ActionScript. This time we’re going to do the same thing, but using Python and Pygame.

The Logic

This animation is what we’re creating. The black box is the actual screen that our players will see, but notice that the backgrounds are moving off the stage. The red and green backgrounds are duplicates of the same image, but are different colors for this demo just to make it easier to see what’s going on.

Click the animation to start and stop.

With Python we’re going to load a copy of the background image into two different Surfaces.

Background Image

Image we're using for the scrolling background.
Image we’re using for the scrolling background.

The image to the right is what we’ll use to scroll. The image is 250 pixels tall by 1,000 pixels wide. The size of the Pygame widow is going to be 250×550 pixels. For what we’re doing we want the height to match, but the width is going to be wider than the screen so that the repitition is less obvious.

It’s saved as background.png.  Pygame is pretty good about loading different image formats, but I like png for this sort of thing.

The Code

import pygame, sys
from pygame.locals import *

pygame.init()

screen = pygame.display.set_mode((550, 250))

clock = pygame.time.Clock()

bgOne = pygame.image.load('background.png')
bgTwo = pygame.image.load('background.png')

bgOne_x = 0
bgTwo_x = bgOne.get_width()

while True:

    screen.blit(bgOne, (bgOne_x, 0))
    screen.blit(bgTwo, (bgTwo_x, 0))

    pygame.display.update()

    bgOne_x -= 1
    bgTwo_x -= 1

    if bgOne_x <= -1 * bgOne.get_width():
        bgOne_x = bgTwo_x + bgTwo.get_width()
    if bgTwo_x <= -1 * bgTwo.get_width():
        bgTwo_x = bgOne_x + bgOne.get_width()

    for event in pygame.event.get():
        if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):
            sys.exit()

    clock.tick(30)

Explanation

Lines 1 – 8 get Pygame ready and set the stage size.

Lines 10 and 11 create two Surface instances, loading from the background.png image file.

Lines 13 and 14 set variables to hold the x position of each background Surface. bgTwo_x is set so that its x position is the same as the width of bgOne which lines up the right edge of bgOne with the left edge of bgTwo.

Line 16 starts the event loop.

Lines 18 and 19 blit the background Surfaces to the screen. They are placed using the bgOne_x and bgTwo_x variables for their x position. Y position is always 0 for this demo, but you could change that if you needed.

Line 21 updates the screen.

Lines 23 and 24 update the x position variables so that they’re one less, and next frame the backgrounds will draw one pixel to the left. Increasing the number will increase the speed.

Lines 26 through 29 check to see if the Surface has gone all the way left off of the stage. If it has, it’s set to go back to the x position of the other Surface plus its width which keeps the right edge of the left most Surface lined up with the left edge of the right most Surface.

Lines 31 – 33 check to see if the program should exit.

Line 35 makes sure that the animation never goes beyond 30 frames per second. You can adjust this to change the speed.

Finished Product

This is what we’ll have at the end. The example is Flash, but it looks the same in Python.

Click to start, click to stop.

Published inCoding

16 Comments

  1. Dorian Dorian

    Hello !
    I tried your script but I can’t make the background scroll from the base to the top without bugs :
    Can you help me? By the way, nice website it helped me a lot !!!!

    import pygame, sys
    from pygame.locals import *
    
    pygame.init()
    
    ecran = pygame.display.set_mode((1280, 720))
    
    clock = pygame.time.Clock()
    
    fond1 = pygame.image.load('fondd.jpg')
    fond2 = pygame.image.load('fondd.jpg')
    
    ordonnee_fond1 = 0
    ordonnee_fond2 = fond1.get_height()
    
    while True:
    
        ecran.blit(fond1, (0,ordonnee_fond1))
        ecran.blit(fond2, (0,ordonnee_fond2))
    
        pygame.display.update()
    
        ordonnee_fond1 -= 1
        ordonnee_fond2 -= 1
    
        if ordonnee_fond1 == -1 * fond1.get_height():
            ordonnee_fond1 = ordonnee_fond2 + fond2.get_height()
        if fond2 == -1 * fond2.get_height():
            ordonnee_fond2 = ordonnee_fond1 + fond1.get_height()
    
        for event in pygame.event.get():
            if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):
                sys.exit()
    
        clock.tick(300)
  2. Emma Emma

    Hy!

    I tried your code and I really works but I’ve got a problem with loading my character that I want to put in front of the scrolling background… It goes behind with this code :

    #Chargement et collage du personnage
    jumpy = pygame.image.load(“Jumpy1c.GIF”).convert_alpha()
    screen.blit(jumpy, (0,468))
    position_jumpy = jumpy.get_rect()
    pygame.display.flip()

    Do you know what I could do ? Thanks !!

    • Make sure you’re putting the jumpy guy in the code to draw after the background. I think you probably only need to do display.flip / update once.

  3. Emma Emma

    Thank you for you’re anwser
    I think I did it right but it still doesn’t work…

    This is my complete code :

    import pygame, sys
    from pygame.locals import *
    pygame.init()

    screen = pygame.display.set_mode((1000, 727))

    clock = pygame.time.Clock()

    #Chargement et collage du fond
    fond = pygame.image.load(“Fond1.jpg”).convert()
    screen.blit(fond, (0,0))

    #Defilement du fond
    fond1 = pygame.image.load(‘Fond1.jpg’)
    fond2 = pygame.image.load(‘Fond1.jpg’)

    fond1_x = 0
    fond2_x = fond1.get_width()

    while True:

    screen.blit(fond1, (fond1_x, 0))
    screen.blit(fond2, (fond2_x, 0))

    pygame.display.update()

    fond1_x -= 1
    fond2_x -= 1

    if fond1_x == -1 * fond1.get_width():
    fond1_x = fond2_x + fond2.get_width()
    if fond2_x == -1 * fond2.get_width():
    fond2_x = fond1_x + fond1.get_width()

    for event in pygame.event.get():
    if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):
    sys.exit()

    clock.tick(30)

    #Chargement et collage de jumpy
    jumpy = pygame.image.load(“Jumpy1c.GIF”).convert_alpha()
    screen.blit(jumpy, (0,468))
    position_jumpy = jumpy.get_rect()
    pygame.display.flip()

    thank you very much

    • Emma Emma

      I can actually put Jumpy after this :

      #Chargement et collage du fond
      fond = pygame.image.load(“Fond1.jpg”).convert()
      screen.blit(fond, (0,0))

      but still does not work ! Jumpy is behind the scrolling picture (we can actually see his feet lol)

  4. :)) :))

    Can someone help me as when I run this code, it says “AttributeError: ‘pygame.Surface’ object has no attribute ‘get_Width'” I don’t understand how to solve the issue, if someone can help that would be appreciated.

    Here is the code:
    import pygame
    import sys

    pygame.init()

    size = [800, 600]

    clock = pygame.time.Clock()
    screen = pygame.display.set_mode(size)
    Height = 600
    Width = 800
    image = pygame.image.load(‘yee.jpg’)
    image = pygame.transform.scale(image, size)

    game_over = False

    speed = 30

    bgOne = pygame.image.load(‘yee.jpg’)
    bgTwo = pygame.image.load(‘yee.jpg’)
    bgOne_Y = 0
    bgTwo_Y = bgOne.get_Height()
    bgOne_Y -= 1
    bgTwo_Y -= 1

    while not game_over:
    pygame.display.flip()
    screen.blit(image, [0, 0])
    for event in pygame.event.get():
    if event.type == pygame.QUIT:
    sys.exit()
    screen.blit(bgOne, (bgOne_Y, 0))
    screen.blit(bgTwo, (bgTwo_Y, 0))

    if bgOne_Y == -1 * bgOne.get_Height():
    bgOne_Y = bgTwo_Y + bgTwo.get_Height()
    if bgTwo == -1 * bgTwo.get_Height():
    bgTwo_Y = bgOne_Y + bgOne.get_Height()

    game_over = True

    pygame.display.flip()
    pygame.display.update()
    clock.tick(30)

    (thanks in advanced)

    • :)) :))

      Oops, I meant get_Height, not get_Width. so it would be AttributeError: ‘pygame.Surface’ object has no attribute ‘get_Height’

  5. Beaumale Beaumale

    Bonjour, tous le monde, j’aimerais faire un défilement de mon background comme toi mais avec 3 images mais je n’arrive pas à faire fonctionner ton code avec le mien … Voici ce que j’ai fait:
    import pygame
    import os, sys

    def main():
    pygame.init()

    ecran = pygame.display.set_mode((1200, 600))
    pygame.display.set_caption(‘Le rêve de Robotnik’)

    jeu_en_cours = True

    while jeu_en_cours :

    for event in pygame.event.get():
    if event.type == pygame.QUIT:
    jeu_en_cours = FALSE

    if event.type == pygame.KEYDOWN:
    if event.key == pygame.K_ESCAPE:
    jeu_en_cours = False

    image1 = load_image(‘background_fix.png’, ecran)
    ecran.blit(image1, (0, 0))
    image2 = load_image(‘background_middle.png’, ecran)
    ecran.blit(image2, (0, 0))
    image3 = load_image(‘background_front.png’, ecran)
    ecran.blit(image3, (0, 0))
    pygame.display.flip()

    pygame.quit()

    def load_image(name, ecran, colorkey=None):
    fullname = os.path.join(‘resources/’, name)
    image = pygame.image.load(fullname)
    return image

    pygame.init()
    screen = pygame.display.set_mode((1200, 600))

    clock = pygame.time.Clock()

    image1 = pygame.image.load(‘background_fix.png’)
    image2 = pygame.image.load(‘background_middle.png’)
    image3 = pygame.image.load(‘background_front.png’)

    image1_x = 0
    image2_x = image1.get_width()
    image3_x = image2.get_width()

    while True:

    screen.blit(image1, (image1_x, 0))
    screen.blit(image2, (image2_x, 0))
    screen.blit(image3, (image3_x, 0))

    pygame.display.update()

    image1_x -= 1
    image2_x -= 1
    image3_x -= 1

    if image1_x &ampampamplt == -1 * image1.get_width():
    image1_x = image2_x + image2.get_width()
    if image2_x &ampampamplt == -1 * image2.get_width():
    image2_x = image1_x + image3.get_width()
    if image3_x &ampampamplt == -1 * image3.get_width():
    image3_x = image1_x + image1.get_width()

    for event in pygame.event.get():
    if event.type == QUIT or (event.type == KEYUP and event.key == K_ESCAPE):
    sys.exit()

    clock.tick(30)

    screen

    if __name__ == “__main__”:
    main()
    Merci !

Leave a Reply

Your email address will not be published. Required fields are marked *