Menu
CoddyTech

Pixelgenaue Sprites

Teil des Abschnitts Sprites und Bilder der Pygame-Journey von Coddy. Lektion 23 von 36.

Sprites können ebenfalls Masken verwenden, und pygame übernimmt den Versatz für dich. Weise jedem Sprite ein self.mask zu, das einmal in __init__ erstellt wird:

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

Übergib dann pygame.sprite.collide_mask als viertes Argument an spritecollide:

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

Das vierte Argument ist der Test, der für jedes Paar verwendet wird. Ohne dieses Argument werden die Rects getestet. Mit collide_mask werden die Masken getestet, die anhand des Rects des jeweiligen Sprites positioniert werden. groupcollide akzeptiert dasselbe fünfte Argument.

Maskentests sind aufwendiger als Rect-Tests, aber overlap vergleicht nur die Pixel, an denen sich die beiden Rects überlappen, sodass Paare mit großem Abstand schnell getestet werden. Bei einigen Dutzend Sprites wirst du den Aufwand nicht bemerken. Wenn ein Sprite keine mask hat, erstellt collide_mask bei jedem Test eine aus seinem Bild. Weise sie daher in __init__ zu.

challenge icon

Aufgabe

Mittel
  1. Gib Player und Ball eine self.mask, die aus self.image erstellt wird.
  2. Übergib pygame.sprite.collide_mask an spritecollide, damit Hit! nur angezeigt wird, solange das Bild des Raumschiffs einen Ball berührt.

Probier es selbst

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

Alle Lektionen in Sprites und Bilder

Übe selbstständig: Pygame-Playground