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
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.
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 !!!!
What’s it not doing right?
Just try it ;) the picture doesn’t show properly from top to low
Looks like both images scroll once and then it stops. Is that what you’re seeing?
Exactly!!
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.
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
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)
if bgOne_x <= -1 * bgOne.get_width():
^
Syntax error.
Is this happening to anyone else?
Yes :(
Can you make it in class?
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’
how to do this same thing in reverse direction
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 &ampamplt == -1 * image1.get_width():
image1_x = image2_x + image2.get_width()
if image2_x &ampamplt == -1 * image2.get_width():
image2_x = image1_x + image3.get_width()
if image3_x &ampamplt == -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 !