Sprites, Collisions and Animations

Pygame Game Development Course

Felipe A. Moreno-Vera

💥 Collisions

What is a Collision?

A collision occurs when two objects overlap in space. Detecting it is essential for: taking damage, picking up items, blocking movement, shooting, and more.

Pygame offers several levels of precision, with a clear trade-off:

Faster ←──────────────────────────────→ More Precise

  Rect-Rect      Circle-Circle      Pixel-perfect
  (AABB)         (distance)         (mask)

Rect-Rect Collision (AABB)

AABB = Axis-Aligned Bounding Box. The fastest and most commonly used method.

# Method 1: rect.colliderect()
if player.rect.colliderect(enemy.rect):
    print("Collision!")

# Method 2: rect.collidepoint() — point inside rect
if player.rect.collidepoint(pygame.mouse.get_pos()):
    print("Mouse is over the player")

# Method 3: rect.collidelist() — against a list of rects
index = player.rect.collidelist([rect1, rect2, rect3])
# Returns the index of the first collided rect, or -1

Rect-Rect Collision (AABB)

AABB = Axis-Aligned Bounding Box. The fastest and most commonly used method.

# Method 1: rect.colliderect()
if player.rect.colliderect(enemy.rect):
    print("Collision!")

# Method 2: rect.collidepoint() — point inside rect
if player.rect.collidepoint(pygame.mouse.get_pos()):
    print("Mouse is over the player")

# Method 3: rect.collidelist() — against a list of rects
index = player.rect.collidelist([rect1, rect2, rect3])
# Returns the index of the first collided rect, or -1

Manual AABB Implementation

AABB Collision — tests:
=======================================================
  Partially overlapping                  → ✅ COLLISION
  Separated horizontally                 → ❌ no collision
  B fully inside A                       → ✅ COLLISION
  Just touching (edge)                   → ✅ COLLISION
  Separated by 1px                       → ❌ no collision

Circle-Circle Collision

More precise for round objects (bullets, coins, circular characters). The logic: two circles collide if the distance between their centers is less than the sum of their radii.

    A            B
   (●)          (●)
       ←── d ──→

  If d < rA + rB → collision

Circle-Circle Collision

More precise for round objects (bullets, coins, circular characters). The logic: two circles collide if the distance between their centers is less than the sum of their radii.

    A            B
   (●)          (●)
       ←── d ──→

  If d < rA + rB → collision
import math

def circle_collision(cx1, cy1, r1, cx2, cy2, r2):
    distance = math.sqrt((cx2 - cx1)**2 + (cy2 - cy1)**2)
    return distance < r1 + r2

# Optimization: avoid sqrt using squared distance
def circle_collision_fast(cx1, cy1, r1, cx2, cy2, r2):
    dx = cx2 - cx1
    dy = cy2 - cy1
    dist_sq = dx*dx + dy*dy
    return dist_sq < (r1 + r2)**2   # No sqrt needed

spritecollide() — Group Collisions

This is the most powerful collision function in Pygame.

# Detect collision of ONE sprite against a GROUP
hits = pygame.sprite.spritecollide(
    player,    # individual sprite
    bullets,   # group to check against
    True       # True = remove colliding sprites from the group
)
# hits is a list of sprites that collided
if hits:
    health -= len(hits)

# Detect collisions between TWO GROUPS
clashes = pygame.sprite.groupcollide(
    bullets,   # group 1
    enemies,   # group 2
    True,      # remove from group 1
    True       # remove from group 2
)
# clashes is a dict: {bullet: [enemies_hit], ...}

# Using circular collision (more precise)
hits = pygame.sprite.spritecollide(
    player, bullets, True,
    collided=pygame.sprite.collide_circle
)

# Using pixel masks (maximum precision, slowest)
hits = pygame.sprite.spritecollide(
    player, bullets, True,
    collided=pygame.sprite.collide_mask
)

Collision Response

Detecting the collision is only half the job. The other half is what to do when it happens.

Collision Response

Detecting the collision is only half the job. The other half is what to do when it happens.

Pattern 1 — Separation (platforms, walls)

# Move first, then correct
player.rect.x += vel_x
for platform in platforms:
    if player.rect.colliderect(platform.rect):
        if vel_x > 0:   # Moving right
            player.rect.right = platform.rect.left
        elif vel_x < 0: # Moving left
            player.rect.left = platform.rect.right
        vel_x = 0

Collision Response

Detecting the collision is only half the job. The other half is what to do when it happens.

Pattern 1 — Separation (platforms, walls)

# Move first, then correct
player.rect.x += vel_x
for platform in platforms:
    if player.rect.colliderect(platform.rect):
        if vel_x > 0:   # Moving right
            player.rect.right = platform.rect.left
        elif vel_x < 0: # Moving left
            player.rect.left = platform.rect.right
        vel_x = 0

Pattern 2 — Bounce (bullets, balls)

if bullet.rect.left <= 0 or bullet.rect.right >= WIDTH:
    bullet.vel_x *= -1   # Reverse horizontal velocity

Collision Response

Detecting the collision is only half the job. The other half is what to do when it happens.

Pattern 1 — Separation (platforms, walls)

# Move first, then correct
player.rect.x += vel_x
for platform in platforms:
    if player.rect.colliderect(platform.rect):
        if vel_x > 0:   # Moving right
            player.rect.right = platform.rect.left
        elif vel_x < 0: # Moving left
            player.rect.left = platform.rect.right
        vel_x = 0

Pattern 2 — Bounce (bullets, balls)

if bullet.rect.left <= 0 or bullet.rect.right >= WIDTH:
    bullet.vel_x *= -1   # Reverse horizontal velocity

Pattern 3 — Destruction (item picked up, enemy eliminated)

items_picked = pygame.sprite.spritecollide(player, items, True)  # True = kill
score += len(items_picked) * 10

Collision Method Comparison

Collision method comparison
============================================================

  Method                 Cost     Precision                  When to use
  --------------------------------------------------------------------------------
  AABB (Rect-Rect)       O(1)     Low — invisible box        Platforms, items, most objects
  Circle-Circle          O(1)     Medium — circular          Bullets, coins, round characters
  collide_rect_ratio     O(1)     Medium — shrunk rect       Hitbox smaller than the sprite
  collide_mask           O(n)     Maximum — pixel by pixel   Bosses, irregular shapes (use sparingly)

General rule: start with AABB. Switch only when the inaccuracy
is noticeable. Reserve collide_mask for very few sprites.

Collisions — Summary

  • AABB (colliderect) = fastest, sufficient for most cases
  • spritecollide(sprite, group, kill) = one vs. many collision
  • groupcollide(g1, g2, k1, k2) = group vs. group collision
  • Response depends on type: separate, bounce, or destroy