Full Game Project: "Catch the Data"
It's time to bring it all together! We will build a complete game called "Catch the Data" where the player moves a basket to catch falling data packets while avoiding viruses.
Learning Objectives
- 12.5.3.9 Create a simple computer game
Game Design
The Blueprint
- Player: Only moves left/right at the bottom.
- Packets (Green): Fall from top. +10 Score.
- Viruses (Red): Fall from top. Game Over if hit.
- Win Condition: Reach 500 points.
- Lose Condition: Hit a virus.
Complete Code
Copy this code into a new file catch_the_data.py and run it.
import pygame
import sys
import random
# --- Constants ---
WIDTH, HEIGHT = 800, 600
FPS = 60
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
GREEN = (0, 200, 100)
RED = (200, 50, 50)
BLUE = (50, 100, 255)
# --- Classes ---
class Player(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((60, 40))
self.image.fill(BLUE)
self.rect = self.image.get_rect(center=(WIDTH//2, HEIGHT - 50))
self.speed = 8
def update(self):
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
self.rect.x -= self.speed
if keys[pygame.K_RIGHT]:
self.rect.x += self.speed
# Keep on screen
self.rect.clamp_ip(pygame.Rect(0, 0, WIDTH, HEIGHT))
class FallingObject(pygame.sprite.Sprite):
def __init__(self, obj_type):
super().__init__()
self.type = obj_type
size = 30 if obj_type == "packet" else 40
self.image = pygame.Surface((size, size))
if self.type == "packet":
self.image.fill(GREEN)
self.speed = random.randint(4, 7)
else:
self.image.fill(RED)
self.speed = random.randint(6, 9)
self.rect = self.image.get_rect(
center=(random.randint(20, WIDTH-20), -20)
)
def update(self):
self.rect.y += self.speed
if self.rect.top > HEIGHT:
self.kill()
# --- Setup ---
pygame.init()
screen = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Catch the Data!")
clock = pygame.time.Clock()
font = pygame.font.SysFont("Arial", 28)
big_font = pygame.font.SysFont("Arial", 72)
# Game State
player = Player()
all_sprites = pygame.sprite.Group(player)
packets = pygame.sprite.Group()
viruses = pygame.sprite.Group()
score = 0
game_state = "playing" # playing, won, lost
# Timer for spawning
SPAWN_EVENT = pygame.USEREVENT + 1
pygame.time.set_timer(SPAWN_EVENT, 500) # Every 500ms
# --- Main Loop ---
running = True
while running:
# 1. Event Handling
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if game_state == "playing":
if event.type == SPAWN_EVENT:
# 80% chance for packet, 20% for virus
if random.random() < 0.8:
obj = FallingObject("packet")
packets.add(obj)
all_sprites.add(obj)
else:
obj = FallingObject("virus")
viruses.add(obj)
all_sprites.add(obj)
# Restart logic
if game_state != "playing" and event.type == pygame.KEYDOWN:
if event.key == pygame.K_r:
# Reset game
game_state = "playing"
score = 0
all_sprites.empty()
packets.empty()
viruses.empty()
player = Player()
all_sprites.add(player)
# 2. Update
if game_state == "playing":
all_sprites.update()
# Check collisions
# Packet hits
hits = pygame.sprite.spritecollide(player, packets, True)
if hits:
score += 10 * len(hits)
# Virus hits
hits = pygame.sprite.spritecollide(player, viruses, False)
if hits:
game_state = "lost"
# Win condition
if score >= 500:
game_state = "won"
# 3. Render
screen.fill(BLACK)
if game_state == "playing":
all_sprites.draw(screen)
# Draw UI
score_text = font.render(f"Data: {score}/500", True, WHITE)
screen.blit(score_text, (10, 10))
elif game_state == "lost":
text = big_font.render("SYSTEM INFECTED!", True, RED)
rect = text.get_rect(center=(WIDTH//2, HEIGHT//2))
screen.blit(text, rect)
sub = font.render("Press R to Reboot", True, WHITE)
sub_rect = sub.get_rect(center=(WIDTH//2, HEIGHT//2 + 60))
screen.blit(sub, sub_rect)
elif game_state == "won":
text = big_font.render("UPLOAD COMPLETE!", True, GREEN)
rect = text.get_rect(center=(WIDTH//2, HEIGHT//2))
screen.blit(text, rect)
sub = font.render(f"Final Score: {score}. Press R to Play Again", True, WHITE)
sub_rect = sub.get_rect(center=(WIDTH//2, HEIGHT//2 + 60))
screen.blit(sub, sub_rect)
pygame.display.flip()
clock.tick(FPS)
pygame.quit()
sys.exit()Code Breakdown
1. Game States
We use a variable game_state separate logic for playing, winning, and losing. When the
game ends, we stop updating sprites and stop spawning items, but keep the loop running to show the
"Game Over" text and wait for a restart key.
2. Timers (USEREVENT)
Instead of relying on random chance every frame (which varies with FPS), we use
pygame.time.set_timer() to trigger a customer event exactly every 500 milliseconds.
This makes spawning consistent.
3. Inheritance
Use a single FallingObject class for both packets and viruses. We pass a
type argument to __init__ to decide if it's green (good) or red (bad).
This saves writing two nearly identical classes.
Project Extensions
Add a "Golden Packet" that spawns rarely gives +50 points and plays a sound.
Add difficulty scaling: Make objects fall faster as the score gets higher.
Add lives: Allow the player to hit 3 viruses before Game Over. Display lives as icons.