Creating a Seamless Scrolling Background in a Python Race Game

Achieve a smooth forward motion effect using clever background tiling

Posted by Hüseyin Sekmenoğlu on April 08, 2024 Full Stack Projects

When building a 2D race game in Python, one of the most visually engaging elements is the illusion of forward motion. This is typically achieved by keeping the car stationary and animating the background so it scrolls vertically. But to do this properly, the background must tile seamlessly otherwise, players will notice breaks or jumps in the scenery.

In this guide, you’ll learn how to create a vertically seamless background and implement smooth scrolling using Pygame.


🧱 What You’ll Need

  • Python 3.x

  • Pygame installed (pip install pygame)

  • A vertically tileable background image

  • A car sprite (optional for now)


🎨 Step 1: Prepare the Background Image

Your background image needs to loop perfectly. This means the bottom edge should align visually with the top edge. If your image doesn’t tile naturally, you can blend the top and bottom using Python and Pillow (PIL):

from PIL import Image
import numpy as np

image = Image.open("background.jpg")
img_array = np.array(image)

top = img_array[:100]
bottom = img_array[-100:]
blended = ((top * 0.5) + (bottom * 0.5)).astype(np.uint8)

img_array[:100] = blended
img_array[-100:] = blended

Image.fromarray(img_array).save("seamless_background.jpg")

ou can adjust the 100 pixels based on your image height.


🕹️ Step 2: Implement Scrolling in Pygame

Once your background is seamless, you can load and scroll it in your game.

import pygame

pygame.init()
WIDTH, HEIGHT = 800, 600
FPS = 60
SCROLL_SPEED = 5

screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Race Game")

bg = pygame.image.load("seamless_background.jpg")
bg = pygame.transform.scale(bg, (WIDTH, HEIGHT))

y1 = 0
y2 = -HEIGHT

clock = pygame.time.Clock()
running = True

while running:
    clock.tick(FPS)

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

    y1 += SCROLL_SPEED
    y2 += SCROLL_SPEED

    if y1 >= HEIGHT:
        y1 = -HEIGHT
    if y2 >= HEIGHT:
        y2 = -HEIGHT

    screen.blit(bg, (0, y1))
    screen.blit(bg, (0, y2))
    pygame.display.update()

pygame.quit()

This setup scrolls two stacked copies of the background. As one leaves the screen, it’s moved above the other creating a continuous loop.


🚘 Add the Car

To complete the illusion, load a car sprite and keep it fixed near the bottom center of the screen while the background scrolls.

car = pygame.image.load("car.png")
car = pygame.transform.scale(car, (60, 120))

car_x = WIDTH // 2 - 30
car_y = HEIGHT - 140

# Inside the main loop
screen.blit(car, (car_x, car_y))

🧠 Final Tips

  • Keep your background's visual rhythm consistent to avoid jarring loops

  • Avoid strong horizontal features near the image’s top and bottom edges

  • Test scrolling at multiple speeds to tune difficulty and feel


✅ Summary

A smooth scrolling background makes your race game feel dynamic and immersive. While seamless tiling requires some image prep, once done, it opens up the road literally for a fluid racing experience.

Happy coding and may your game be fast and flawless!

Game Link: https://hub.kodland.org/en/project/342899