Collision Detection
Collision detection is how games know when two objects touch — like a player hitting a coin, a bullet hitting an enemy, or a character bumping into a wall. PyGame uses rectangles to check for these overlaps efficiently.
Learning Objectives
- 12.5.3.1 Code the movement of graphic objects
- 12.5.3.6 Process events (collisions)
Conceptual Anchor
The Bounding Box Analogy
Imagine every object in your game is wrapped in an invisible rectangular box. To check if two complex shapes touch, we just check "do their boxes overlap?". It's fast, simple, and works for 99% of 2D games.
Rules & Theory
Rectangle Collisions (Rect vs Rect)
# Check if two Rects overlap
if player_rect.colliderect(coin_rect):
print("Hit!")
# Check if a Rect contains a point (e.g., mouse click)
if button_rect.collidepoint(mx, my):
print("Clicked!")Sprite Collisions (Sprite vs Group)
| Function | Description |
|---|---|
pygame.sprite.spritecollide(sprite, group, dokill) |
Returns a list of sprites from the group that intersect with the
sprite. dokill=True removes hit sprites from the
group. |
pygame.sprite.groupcollide(grp1, grp2, kill1, kill2) |
Checks for collisions between two groups. Returns a dictionary of hits.
kill1/kill2 determine if hit sprites are removed. |
Worked Examples
1 Collecting Coins (Sprite vs Group)
# Player hits coins -> coins disappear, score increases
hits = pygame.sprite.spritecollide(player, coins, True)
for coin in hits:
# This loop runs once for every coin hit this frame
score += 10
play_coin_sound()
print("Coin collected!")2 Bullets Hitting Enemies (Group vs Group)
# Bullets (grp1) hit Enemies (grp2)
# True, True -> BOTH bullet and enemy disappear
hits = pygame.sprite.groupcollide(bullets, enemies, True, True)
for bullet in hits:
# hits is a dict: {bullet: [enemy1, enemy2...]}
# usually 1 bullet hits 1 enemy
for enemy in hits[bullet]:
score += 50
create_explosion(enemy.rect.center)3 Wall Collision (Stop Movement)
# Move x-axis
player.rect.x += player.vel_x
# Check wall collisions immediately
hits = pygame.sprite.spritecollide(player, walls, False)
for wall in hits:
if player.vel_x > 0: # Moving right; hit left side of wall
player.rect.right = wall.rect.left
elif player.vel_x < 0: # Moving left; hit right side of wall
player.rect.left = wall.rect.right
# Move y-axis
player.rect.y += player.vel_y
# Check wall collisions again
hits = pygame.sprite.spritecollide(player, walls, False)
for wall in hits:
if player.vel_y > 0: # Moving down; hit top of wall
player.rect.bottom = wall.rect.top
elif player.vel_y < 0: # Moving up; hit bottom of wall
player.rect.top = wall.rect.bottomCommon Pitfalls
Tunneling Effect
If an object moves too fast (e.g., speed=50), it might "jump" completely over a thin wall (width=10) in a single frame without ever overlapping it. Fix: limit speed or use multiple smaller steps.
Modifying List While Iterating
spritecollide(..., True) modifies the group internally, which is safe. But if you
manually loop through a list and remove items
(for enemy in enemies: enemies.remove(enemy)), it can cause errors. Iterate over a
copy instead: pixels[:].
Tasks
Create a game where the player collects randomly placed "food" squares. Score +1 for each.
Create a "dodge the falling rocks" game. If player collides with a rock, game over.
Implement a maze game where the player cannot walk through wall sprites (use the stop movement logic).
Self-Check Quiz
Q1: What does dokill=True mean in spritecollide?
Q2: How do you check if a point is inside a rectangle?
rect.collidepoint(x, y) — useful for mouse clicks on buttons.Q3: Why separate x and y movement for wall collisions?