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