Menu
CoddyTech

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 icon

Challenge

Medium
  1. Before the loop, make ship_mask and ball_mask with pygame.mask.from_surface.
  2. Colour the outline red when ship_mask.overlap(ball_mask, offset) finds a point, with the offset from ship_rect to ball_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()
quiz iconTest yourself

This lesson includes a short quiz. Start the lesson to answer it and track your progress.

All lessons in Sprites and Images

Practice on your own: Pygame playground