Menu
CoddyTech

Sprites pixel perfect

Parte da seção Sprites e imagens do Journey de Pygame da Coddy. Lição 23 de 36.

Os sprites também podem usar máscaras, e o pygame calcula o deslocamento para você. Atribua a cada sprite um self.mask, criado uma única vez em __init__:

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

Em seguida, passe pygame.sprite.collide_mask como quarto argumento para spritecollide:

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

O quarto argumento é o teste usado para cada par. Sem ele, o teste usa os Rects. Com collide_mask, ele usa as máscaras, posicionadas pelo Rect de cada sprite. groupcollide recebe o mesmo quinto argumento.

Os testes com máscaras custam mais do que os testes com Rects, mas overlap compara apenas os pixels em que os dois Rects se sobrepõem, então os pares distantes são processados rapidamente. Com algumas dezenas de sprites, você não vai notar o custo. Se um sprite não tiver mask, collide_mask cria uma a partir da imagem dele em cada teste, então defina-a em __init__.

challenge icon

Desafio

Médio
  1. Dê a Player e Ball uma self.mask criada a partir de self.image.
  2. Passe pygame.sprite.collide_mask para spritecollide, para que Hit! apareça somente enquanto a imagem da nave tocar uma bola.

Experimente você mesmo

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()

Todas as lições de Sprites e imagens

Pratique por conta própria: Playground de Pygame