Menu
CoddyTech

Sprites precisos a nivel de píxel

Parte de la sección Sprites e imágenes del Journey de Pygame de Coddy. Lección 23 de 36.

Los sprites también pueden usar máscaras, y pygame calcula el desplazamiento por ti. Asigna a cada sprite un self.mask, creado una sola vez en __init__:

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

Después, pasa pygame.sprite.collide_mask como cuarto argumento de spritecollide:

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

El cuarto argumento es la prueba que se usa para cada par. Sin él, la prueba se realiza con los Rect. Con collide_mask, se realiza con las máscaras, colocadas según el Rect de cada sprite. groupcollide recibe el mismo quinto argumento.

Las pruebas con máscaras cuestan más que las pruebas con Rect, pero overlap solo compara los píxeles donde se superponen los dos Rect, así que los pares muy separados se procesan rápidamente. Con unas pocas docenas de sprites, no notarás el costo. Si un sprite no tiene mask, collide_mask crea una a partir de su imagen en cada prueba, así que configúrala en __init__.

challenge icon

Desafío

Intermedio
  1. Asigna a Player y Ball una self.mask creada a partir de self.image.
  2. Pasa pygame.sprite.collide_mask a spritecollide, para que Hit! aparezca solo mientras la imagen de la nave toque una bola.

Pruébalo tú mismo

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 las lecciones de Sprites e imágenes

Practica por tu cuenta: Playground de Pygame