Module 15 of 20 Phase: Intelligence & Camera

Building a Real Camera
Follow, Scroll, Shake & Parallax

Pygame has no built-in camera — you build one out of a single offset vector applied to everything you draw. This module covers following the player, smooth scrolling, zoom, screen shake, parallax backgrounds and mini-maps.

🎥
10 Lessons
This module
~2.5 hrs
Estimated time
📊
Intermediate
Difficulty
🐍
Offset vector
Core concept
Section 1

The Camera Offset Pattern

A 2D camera is nothing but an (x, y) offset subtracted from every world position before drawing. World objects never move — only the offset changes, creating the illusion of a scrolling world.

camera.py
class Camera:
    def __init__(self, width, height):
        self.offset = pygame.Vector2(0, 0)
        self.width = width
        self.height = height

    def apply(self, world_pos):
        return world_pos - self.offset

    def center_on(self, target_pos):
        self.offset.x = target_pos.x - self.width / 2
        self.offset.y = target_pos.y - self.height / 2

# in the draw loop:
screen.blit(player_img, camera.apply(player.pos))
screen.blit(enemy_img, camera.apply(enemy.pos))
Section 2

Following the Player & Smooth Scrolling

Snapping the camera exactly to the player every frame feels rigid. Instead, lerp the camera's offset toward the target position gradually, so it eases into place.

smooth_follow.py
def smooth_follow(self, target_pos, dt, smoothing=5.0):
    desired_x = target_pos.x - self.width / 2
    desired_y = target_pos.y - self.height / 2
    self.offset.x += (desired_x - self.offset.x) * smoothing * dt
    self.offset.y += (desired_y - self.offset.y) * smoothing * dt
Section 3

Zoom & Screen Shake

🔍
Zoom
Render the world to a smaller off-screen Surface, then pygame.transform.scale() it up to fill the window — scaling up = zoom in, scaling down = zoom out.
💥
Screen Shake
Add a small random offset to the camera for a fixed duration after an impact — decaying in magnitude over the shake's lifetime.
🗺️
Mini-map
Draw every entity's position scaled down into a small corner Surface — same offset math, just a different scale factor.
screen_shake.py
import random

def trigger_shake(camera, duration=0.3, magnitude=8):
    camera.shake_timer = duration
    camera.shake_magnitude = magnitude

def update_shake(camera, dt):
    if camera.shake_timer > 0:
        camera.shake_timer -= dt
        camera.shake_offset = pygame.Vector2(
            random.uniform(-camera.shake_magnitude, camera.shake_magnitude),
            random.uniform(-camera.shake_magnitude, camera.shake_magnitude),
        )
    else:
        camera.shake_offset = pygame.Vector2(0, 0)
Section 4 · Parallax

Parallax Backgrounds

Parallax fakes depth by scrolling distant background layers SLOWER than the foreground — mimicking how distant mountains appear to move less than nearby trees as you travel.

💡
Key insight: Multiply the camera offset by a "depth factor" per layer (e.g. 0.2 for far mountains, 0.5 for mid-ground trees, 1.0 for the actual gameplay layer) before drawing each background layer.
parallax.py
layers = [
    {"img": mountains_img, "depth": 0.2},
    {"img": trees_img,     "depth": 0.5},
]

def draw_parallax(screen, camera, layers):
    for layer in layers:
        offset_x = -camera.offset.x * layer["depth"]
        screen.blit(layer["img"], (offset_x, 0))
Section 5

World Space vs. Screen Space

Every position in your game exists in two coordinate systems at once: world space, where objects have fixed, permanent coordinates, and screen space, the small visible window into that world. camera.offset is the translation between the two — subtract it from a world position and you get where that object should actually be drawn.

World World Origin (0,0) camera.offset Camera Viewport = what's drawn to the screen
The Camera Viewport is a window into World space — camera.offset is the vector from the world's origin to that window's top-left corner.

🧠 Quick Knowledge Check

1. What fundamentally IS a 2D camera in Pygame?
2. Why lerp the camera toward the player instead of snapping instantly?
3. How does parallax scrolling create the illusion of depth?
4. What technique produces screen shake?
5. How can you achieve a "zoom" effect in Pygame?
Finished Module 15?

Mark it complete to track your progress through Complete Pygame Mastery 2026.

🗒 Cheat Sheet 📝 Worksheet