Masks
Part of the Sprites and Images section of Coddy's Pygame journey. Lesson 22 of 36.
A mask is a grid of yes and no, one per pixel: yes where the picture is solid, no where it is see-through. pygame makes one from any image with alpha:
ship_mask = pygame.mask.from_surface(ship)
ball_mask = pygame.mask.from_surface(ball)Make masks once, before the loop, like the images they come from.
Two masks overlap when a solid pixel of one lands on a solid pixel of the other. A mask has no position, so you say where the second one sits compared with the first: the offset, the other's top left minus this one's top left.
offset = (ball_rect.x - ship_rect.x, ball_rect.y - ship_rect.y)
if ship_mask.overlap(ball_mask, offset):overlap returns the first point where they touch, or None when they do not, so it works as a test in an if. Get the offset backwards and the ball is tested as if it sat on the other side of the ship.
Now the red outline needs real contact: the corners alone stay grey.
Challenge
Medium- Before the loop, make
ship_maskandball_maskwithpygame.mask.from_surface. - Colour the outline red when
ship_mask.overlap(ball_mask, offset)finds a point, with the offset fromship_recttoball_rect; grey otherwise.
Try it yourself
import pygame
pygame.init()
screen = pygame.display.set_mode((640, 480))
pygame.display.set_caption("Near Miss")
clock = pygame.time.Clock()
ship = pygame.image.load("assets/images/ship.png").convert_alpha()
ship_rect = ship.get_rect(topleft=(420, 320))
ball = pygame.image.load("assets/images/spike_ball.png").convert_alpha()
ball_rect = ball.get_rect(center=(320, 240))
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
ship_rect.x -= 4
if keys[pygame.K_RIGHT]:
ship_rect.x += 4
if keys[pygame.K_UP]:
ship_rect.y -= 4
if keys[pygame.K_DOWN]:
ship_rect.y += 4
screen.fill((20, 22, 40))
screen.blit(ball, ball_rect)
screen.blit(ship, ship_rect)
if ship_rect.colliderect(ball_rect):
colour = (230, 60, 60)
else:
colour = (90, 90, 120)
pygame.draw.rect(screen, colour, ball_rect, 2)
pygame.display.flip()
clock.tick(60)
pygame.quit()
This lesson includes a short quiz. Start the lesson to answer it and track your progress.
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