Pixel-Perfect Sprites
Part of the Sprites and Images section of Coddy's Pygame journey. Lesson 23 of 36.
Sprites can use masks too, and pygame does the offset for you. Give each sprite a self.mask, made once in __init__:
self.mask = pygame.mask.from_surface(self.image)Then pass pygame.sprite.collide_mask as a fourth argument to spritecollide:
hits = pygame.sprite.spritecollide(player, balls, False, pygame.sprite.collide_mask)The fourth argument is the test used for each pair. Without it the test is the Rects. With collide_mask it is the masks, placed by each sprite's Rect. groupcollide takes the same fifth argument.
Mask tests cost more than Rect tests, but overlap only compares the pixels where the two Rects overlap, so pairs far apart are quick. For a few dozen sprites you will not notice the cost. If a sprite has no mask, collide_mask makes one from its image on every test, so set it in __init__.
Challenge
Medium- Give
PlayerandBallaself.maskmade fromself.image. - Pass
pygame.sprite.collide_masktospritecollide, soHit!shows only while the ship's picture touches a ball.
Try it yourself
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()
All lessons in Sprites and Images
3Classes for Game Objects
Your First ClassMethodsSelf Is the ObjectA List of ObjectsObjects with ImagesA SubclassPractice on your own: Pygame playground