Menu
CoddyTech

Group Against Group

Part of the Sprites and Images section of Coddy's Pygame journey. Lesson 20 of 36.

Lasers should destroy enemies. That is a group against a group: any laser against any enemy. groupcollide tests every pair at once:

hits = pygame.sprite.groupcollide(enemies, lasers, True, True)
score += len(hits)

The two Trues are the dokill flags, one per group: the first kills the enemies that were hit, the second the lasers that hit them. A laser that goes on flying after a hit could take out a second enemy above the first.

hits is a dictionary: each enemy that was hit is a key, and its value is the list of lasers that hit it. len(hits) is the number of enemies hit this frame, even when two lasers hit the same one.

The order of the groups decides what the keys are. With groupcollide(lasers, enemies, True, True) the keys would be lasers, and len(hits) would count lasers instead.

challenge icon

Challenge

Medium
  1. After the updates, test enemies against lasers with pygame.sprite.groupcollide, killing both the enemy and the laser.
  2. Add the number of enemies hit to score.

Try it yourself

import pygame

pygame.init()
screen = pygame.display.set_mode((640, 480))
pygame.display.set_caption("Laser Hits")
clock = pygame.time.Clock()

ship_image = pygame.image.load("assets/images/ship.png").convert_alpha()
enemy_image = pygame.image.load("assets/images/enemy_red.png").convert_alpha()
laser_image = pygame.image.load("assets/images/laser.png").convert_alpha()
font = pygame.font.Font(None, 32)


class Player(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = ship_image
        self.rect = self.image.get_rect(midbottom=(320, 470))

    def update(self):
        keys = pygame.key.get_pressed()
        if keys[pygame.K_LEFT]:
            self.rect.x -= 6
        if keys[pygame.K_RIGHT]:
            self.rect.x += 6
        self.rect.clamp_ip(screen.get_rect())


class Enemy(pygame.sprite.Sprite):
    def __init__(self, x, y):
        super().__init__()
        self.image = enemy_image
        self.rect = self.image.get_rect(center=(x, y))

    def update(self):
        self.rect.y += 1
        if self.rect.top > 480:
            self.rect.bottom = 0


class Laser(pygame.sprite.Sprite):
    def __init__(self, x, y):
        super().__init__()
        self.image = laser_image
        self.rect = self.image.get_rect(midbottom=(x, y))

    def update(self):
        self.rect.y -= 10
        if self.rect.bottom < 0:
            self.kill()


player = Player()
lasers = pygame.sprite.Group()
enemies = pygame.sprite.Group()
for i in range(5):
    enemies.add(Enemy(64 + i * 128, 60))
score = 0

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
        elif event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
            lasers.add(Laser(player.rect.centerx, player.rect.top))

    player.update()
    lasers.update()
    enemies.update()

    screen.fill((20, 22, 40))
    enemies.draw(screen)
    lasers.draw(screen)
    screen.blit(player.image, player.rect)
    text = font.render(f"Score: {score}", True, (240, 240, 240))
    screen.blit(text, (10, 10))
    pygame.display.flip()
    clock.tick(60)

pygame.quit()
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Sprites and Images

Practice on your own: Pygame playground