Racing Game in Python (Pygame) — Step-by-Step Tutorial with Source Code


Build a fast, fun python game using Pygame. This mini project is perfect for python projects for beginners: you’ll learn graphics, input handling, collision detection, scoring, and a restart screen.

What You’ll Build

  • 3-lane road with a player car that moves left/right
  • Obstacle “waves” that always leave one safe lane
  • Score + Highscore display
  • Game Over screen with “Press SPACE to Restart”

Requirements

  1. Install Python (3.9+ recommended).
  2. Install Pygame:
    pip install pygame

🌐 Car Game Animation


import pygame
import random
import sys

pygame.init()

# Screen settings
WIDTH, HEIGHT = 400, 600
ROAD_WIDTH = 240
ROAD_X = (WIDTH - ROAD_WIDTH) // 2
LANE_COUNT = 3
LANE_WIDTH = ROAD_WIDTH // LANE_COUNT

# Car settings
CAR_WIDTH, CAR_HEIGHT = 30, 50
car_y = HEIGHT - CAR_HEIGHT - 40

# Obstacle settings
OBSTACLE_WIDTH, OBSTACLE_HEIGHT = 25, 40
obstacle_speed = 4
OBSTACLE_GAP = 150   # 🔥 vertical gap between waves

screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Racing Game with Highscore")
clock = pygame.time.Clock()
font = pygame.font.SysFont("Arial", 28)

# Colors
WHITE = (255, 255, 255)
GRAY = (64, 64, 64)
GREEN = (34, 177, 76)
RED = (200, 50, 50)
YELLOW = (241, 196, 15)
BLUE = (41, 128, 185)

# Highscore
highscore = 0


def lane_x(lane):
    return ROAD_X + lane * LANE_WIDTH + (LANE_WIDTH - CAR_WIDTH) // 2

def draw_road():
    screen.fill(GREEN)
    pygame.draw.rect(screen, GRAY, (ROAD_X, 0, ROAD_WIDTH, HEIGHT))
    for i in range(1, LANE_COUNT):
        pygame.draw.line(screen, WHITE, (ROAD_X + i * LANE_WIDTH, 0), (ROAD_X + i * LANE_WIDTH, HEIGHT), 4)

def draw_car(lane, y):
    x = lane_x(lane)
    pygame.draw.rect(screen, BLUE, (x, y, CAR_WIDTH, CAR_HEIGHT))
    pygame.draw.rect(screen, YELLOW, (x + 6, y + 18, 18, 15))

def draw_obstacle(lane, y):
    x = lane_x(lane)
    pygame.draw.rect(screen, RED, (x, y, OBSTACLE_WIDTH, OBSTACLE_HEIGHT))

def collision(rect1, rect2):
    return pygame.Rect(rect1).colliderect(pygame.Rect(rect2))


def game_loop():
    global highscore
    car_lane = 1
    obstacles = []
    score = 0
    running = True

    # 🔥 Cooldown control
    last_spawn_y = 0

    while running:
        draw_road()

        # Event handling
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()

            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_LEFT and car_lane > 0:
                    car_lane -= 1
                if event.key == pygame.K_RIGHT and car_lane < LANE_COUNT - 1:
                    car_lane += 1

        # Spawn new obstacle wave (ONLY when last one moved down enough)
        if not obstacles or (obstacles[-1][1] > OBSTACLE_GAP):
            lanes = [0, 1, 2]
            free_lane = random.choice(lanes)  # always keep 1 lane free
            for lane in lanes:
                if lane != free_lane:
                    obstacles.append([lane, -OBSTACLE_HEIGHT])

        # Move obstacles
        obstacles[:] = [[lane, y + obstacle_speed] for lane, y in obstacles if y < HEIGHT]
        for lane, y in obstacles:
            draw_obstacle(lane, y)

        # Draw car
        draw_car(car_lane, car_y)

        # Collision check
        car_rect = (lane_x(car_lane), car_y, CAR_WIDTH, CAR_HEIGHT)
        for lane, y in obstacles:
            obs_rect = (lane_x(lane), y, OBSTACLE_WIDTH, OBSTACLE_HEIGHT)
            if collision(car_rect, obs_rect):
                running = False

        # Score
        score += 1
        score_text = font.render(f"Score: {score // 10}", True, WHITE)
        screen.blit(score_text, (10, 10))

        # Highscore
        highscore_text = font.render(f"Highscore: {highscore}", True, WHITE)
        screen.blit(highscore_text, (10, 40))

        pygame.display.update()
        clock.tick(60)

    # Update Highscore
    if score // 10 > highscore:
        highscore = score // 10

    game_over_screen(score // 10)


def game_over_screen(final_score):
    while True:
        screen.fill(RED)
        over_text = font.render(f"Game Over!", True, WHITE)
        score_text = font.render(f"Your Score: {final_score}", True, WHITE)
        highscore_text = font.render(f"Highscore: {highscore}", True, WHITE)
        restart_text = font.render("Press SPACE to Restart", True, WHITE)
        quit_text = font.render("Press Q to Quit", True, WHITE)

        screen.blit(over_text, (WIDTH // 2 - over_text.get_width() // 2, HEIGHT // 2 - 80))
        screen.blit(score_text, (WIDTH // 2 - score_text.get_width() // 2, HEIGHT // 2 - 40))
        screen.blit(highscore_text, (WIDTH // 2 - highscore_text.get_width() // 2, HEIGHT // 2))
        screen.blit(restart_text, (WIDTH // 2 - restart_text.get_width() // 2, HEIGHT // 2 + 40))
        screen.blit(quit_text, (WIDTH // 2 - quit_text.get_width() // 2, HEIGHT // 2 + 80))

        pygame.display.update()

        # Event handling
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                pygame.quit()
                sys.exit()

            if event.type == pygame.KEYDOWN:
                if event.key == pygame.K_SPACE:  # Restart
                    return
                if event.key == pygame.K_q:  # Quit
                    pygame.quit()
                    sys.exit()


def main():
    while True:
        game_loop()


if __name__ == "__main__":
    main()


🔍 Output Preview


How to Run

  1. Save the file as racing_game.py.
  2. Open Terminal/PowerShell in the folder and run:
    python racing_game.py
  3. Controls: Left Arrow / Right Arrow to change lanes.

Troubleshooting

  • No module named pygame: run pip install pygame.
  • Window not responding: don’t block the main loop; keep pygame.event.get() calls.
  • Too hard? Increase OBSTACLE_GAP (e.g., 180–220) or decrease obstacle_speed.

Why This Is a Great Mini Project

This python mini project teaches real game dev concepts (render loop, events, collisions) and is a strong addition to your portfolio of python projects with source code.

Related Searches (for readers)

games using python, python game code, python coding for games, games in python, python projects for beginners, mini project in python, simple projects in python, python project ideas

FAQ

Q: Can I add images or sounds?
Yes. Load sprites with pygame.image.load() and sounds with pygame.mixer.Sound().

Q: How to increase difficulty?
Gradually increase obstacle_speed and reduce OBSTACLE_GAP as score rises.

🔗