[concept]Game Development with Pygame
Pygame Setup & Game Loop
# theory
pygame basics
Pygame is a Python library for making games. It handles the window, drawing, keyboard/mouse input, and timing. You basically get a blank canvas and Pygame gives you the tools to draw on it 60 times per second.
import pygame
pygame.init()
That's all you need to get started. Everything else builds on top.
from the videos
Pygame Install (2:09)
pip install pygamein terminalimport pygameat the top of your filepygame.init()to initialize all modules- Testing with a simple window to confirm it works
Rectangles vs Vectors (5:39)
- When to use
pygame.Rectvspygame.math.Vector2 - Rects are great for collision detection and positioning
- Vectors are better for physics and smooth movement
- Gerber's advice: use Rect for position/collision, Vector2 for velocity/direction
Delta Time (3:48)
- Frame-rate independent movement
- Why 60fps on your machine != 60fps on another machine
- The
dtpattern that makes movement consistent everywhere
the game loop
Every game runs in a loop. It keeps going until the player quits. Each time through the loop is one "frame."
import pygame
pygame.init()
screen = pygame.display.set_mode((800, 600))
clock = pygame.time.Clock()
running = True
while running:
# 1. Handle events (keyboard, mouse, quit)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# 2. Update game state (move things, check collisions)
# ... game logic goes here
# 3. Draw everything
screen.fill((0, 0, 0)) # black background
pygame.display.flip() # show the frame
clock.tick(60) # cap at 60 frames per second
pygame.quit()
Those three steps (handle events → update → draw) repeat every frame. That's the whole pattern.
delta time
This tripped me up at first. If you just do x += 5 every frame, your game runs at different speeds on different computers. A faster computer runs more frames per second, so things move faster. That's bad.
The fix is delta time (dt). It measures how long the last frame took:
clock = pygame.time.Clock()
while running:
dt = clock.tick(60) / 1000.0 # dt in seconds (e.g., 0.016 for 60fps)
# Now multiply ALL movement by dt
x += velocity * dt # consistent speed regardless of frame rate
Gerber tip: Always multiply velocity by dt. It's the difference between "5 pixels per frame" (inconsistent) and "300 pixels per second" (consistent on every machine).
# BAD; frame-dependent
x += 5
# GOOD; frame-independent
SPEED = 300 # pixels per second
x += SPEED * dt
Rect vs Vector2
Gerber makes an entire video about this because students get confused:
Use pygame.Rect when:
- You need collision detection (
colliderect(),collidepoint()) - You want to use handy properties like
.center,.topleft,.clamp_ip() - You're positioning sprites on screen
Use pygame.math.Vector2 when:
- You need smooth movement with floats (Rects use integers!)
- You want to normalize directions
- You need distance calculations
- You're doing physics with velocity/acceleration
Common pattern; use both:
class Ball(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.pos = pygame.math.Vector2(400, 300) # float position
self.vel = pygame.math.Vector2(3, -2) # float velocity
self.rect = pygame.Rect(0, 0, 20, 20) # for collision
def update(self, dt):
self.pos += self.vel * dt * 60
self.rect.center = self.pos # sync rect to float pos
screen coordinates
Pygame's coordinate system starts at the top-left corner:
- (0, 0) = top-left
- x increases going RIGHT
- y increases going DOWN
So (800, 600) is the bottom-right of an 800x600 window. A bit counterintuitive if you're used to math, but you get used to it fast.
colors
Colors are (R, G, B) tuples with values 0-255:
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
drawing basics
# Draw a filled rectangle: surface, color, (x, y, width, height)
pygame.draw.rect(screen, RED, (100, 100, 50, 50))
# Draw a circle: surface, color, (center_x, center_y), radius
pygame.draw.circle(screen, BLUE, (400, 300), 30)
# Draw a line: surface, color, start_pos, end_pos, width
pygame.draw.line(screen, WHITE, (0, 0), (800, 600), 2)
The order matters; things drawn later appear on top.
🎨 asset creation tips
Where to find free sprites and tilesets:
- Kenney.nl: amazing free assets, super polished, great for prototyping
- itch.io: search "free sprites" or "free tileset", tons of options
- OpenGameArt.org: community-contributed art, check licenses
Tools for making your own:
- Aseprite (paid but worth it); pixel art and animation
- Piskel (free, browser-based); simple pixel art
- Tiled: tilemap editor, exports JSON your game can load
tips
- Gerber tip: Keep all constants in a
settings.pyfile; way easier to tune the game later - Gerber tip: Always call
pygame.quit()at the end; prevents the window from hanging - Tip: Use
pygame.display.set_caption("Game Title")to set the window title - Tip:
clock.tick(60)returns milliseconds since last call; divide by 1000 for seconds
common mistakes
- Forgetting pygame.quit(): the window hangs when you close it
- Not calling pygame.display.flip(): nothing shows up, you just stare at a black screen wondering why
- Using pygame.QUIT instead of pygame.quit(): QUIT is an event type, quit() is a function
- Hardcoding frame rate assumptions: use delta time instead of assuming 60fps
- Putting draw calls before update: you'll draw the old state, not the new one
# examples [2]
The simplest Pygame setup with proper delta time handling
pygame needs a real window — copy this into a .py file and run it locally.
Gerber's recommended structure; all constants in one place
pygame needs a real window — copy this into a .py file and run it locally.
# challenges [2]