Menu
CoddyTech

Sprites au pixel près

Fait partie de la section Sprites et images du Journey Pygame de Coddy. Leçon 23 sur 36.

Les sprites peuvent aussi utiliser des masques, et pygame s’occupe du décalage pour vous. Attribuez à chaque sprite un self.mask, créé une seule fois dans __init__ :

self.mask = pygame.mask.from_surface(self.image)

Passez ensuite pygame.sprite.collide_mask comme quatrième argument à spritecollide :

hits = pygame.sprite.spritecollide(player, balls, False, pygame.sprite.collide_mask)

Le quatrième argument est le test utilisé pour chaque paire. Sans lui, le test porte sur les Rects. Avec collide_mask, il porte sur les masques, positionnés selon le Rect de chaque sprite. groupcollide accepte le même cinquième argument.

Les tests de masque coûtent plus cher que les tests de Rect, mais overlap ne compare que les pixels où les deux Rects se chevauchent, donc les paires éloignées sont traitées rapidement. Pour quelques dizaines de sprites, vous ne remarquerez pas le coût. Si un sprite n’a pas de mask, collide_mask en crée un à partir de son image à chaque test ; définissez-le donc dans __init__.

challenge icon

Défi

Moyen
  1. Crée un self.mask pour Player et Ball à partir de self.image.
  2. Passe pygame.sprite.collide_mask à spritecollide, afin que Hit! s’affiche uniquement lorsque l’image du vaisseau touche une balle.

Essayez vous-même

import pygame

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

ship_image = pygame.image.load("assets/images/ship.png").convert_alpha()
ball_image = pygame.image.load("assets/images/spike_ball.png").convert_alpha()
font = pygame.font.Font(None, 40)


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

    def update(self):
        keys = pygame.key.get_pressed()
        if keys[pygame.K_LEFT]:
            self.rect.x -= 4
        if keys[pygame.K_RIGHT]:
            self.rect.x += 4
        if keys[pygame.K_UP]:
            self.rect.y -= 4
        if keys[pygame.K_DOWN]:
            self.rect.y += 4


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


player = Player()
balls = pygame.sprite.Group(Ball(160, 240), Ball(320, 240), Ball(480, 240))

running = True
while running:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False

    player.update()
    hits = pygame.sprite.spritecollide(player, balls, False)

    screen.fill((20, 22, 40))
    balls.draw(screen)
    screen.blit(player.image, player.rect)
    if hits:
        text = font.render("Hit!", True, (240, 240, 240))
        screen.blit(text, (10, 10))
    pygame.display.flip()
    clock.tick(60)

pygame.quit()

Toutes les leçons de Sprites et images

Entraînez-vous par vous-même : Playground Pygame