Search code examples
pythonpygame-surfacepython-3.10pygame2

transparent bits in pygame mask are black instead of being transparent


I have a program where it fills in the bits of a mask that are overlapped from another mask, but when I blit the mask of the overlapping bits onto the screen, the transparent bits are fully black for some reason? The program works as intended and I've tried converting the surface for the overlapping bits to per pixel alpha but the transparent bits are black

example gif

import pygame
import sprites

SCREEN_HEIGHT, SCREEN_WIDTH = 800, 800
running = True

pygame.init()

screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
clock = pygame.time.Clock()

player = sprites.Block((100, 100))
block2 = sprites.Block((100, 100))
blocks = pygame.sprite.Group(block2)

block2.rect.topleft = 150, 150
block2.image.fill((0, 255, 0))

while running:
    events = pygame.event.get()

    screen.fill((100, 100, 100))
    for event in events:
        if event.type == pygame.QUIT:
            running = False

    player.move(screen.get_rect())
    screen.blit(player.image, player.rect)
    blocks.draw(screen)

    for block in blocks:
        offset = (player.rect.x - block.rect.x, player.rect.y - block.rect.y)
        colliding_bits = player.mask.overlap_mask(block.mask, offset)
        colliding_bits_image = colliding_bits.to_surface(setcolor=(0, 255, 0))

        screen.blit(colliding_bits_image, block.rect)

    clock.tick(144)
    pygame.display.flip()

code containing the sprite classes:

import pygame


class Block(pygame.sprite.Sprite):
    def __init__(self, size):
        self.image = pygame.image.load("flappy_bird.png")
        self.rect = self.image.get_rect()
        self.mask = pygame.mask.from_surface(self.image)

        self.speed = 1

        super().__init__()

    def move(self, screen_rect):
        pressed_keys = pygame.key.get_pressed()

        if pressed_keys[pygame.K_w]:
            self.rect.move_ip(0, -self.speed)
        if pressed_keys[pygame.K_s]:
            self.rect.move_ip(0, self.speed)
        if pressed_keys[pygame.K_a]:
            self.rect.move_ip(-self.speed, 0)
        if pressed_keys[pygame.K_d]:
            self.rect.move_ip(self.speed, 0)

        self.rect.clamp_ip(screen_rect)

Solution

  • I added the unsetcolor attribute to the to_surface method and removed the line blocks.draw(screen) and it seems to produce the desired result :

    from math import fabs
    import pygame
    import sprites
    
    SCREEN_HEIGHT, SCREEN_WIDTH = 800, 800
    running = True
    
    pygame.init()
    
    screen = pygame.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT))
    clock = pygame.time.Clock()
    
    player = sprites.Block((100, 100))
    block2 = sprites.Block((100, 100))
    blocks = pygame.sprite.Group(block2)
    
    block2.rect.topleft = 150, 150
    block2.image.fill((0, 255, 0))
    
    while running:
        events = pygame.event.get()
    
        screen.fill((100, 100, 100))
        for event in events:
            if event.type == pygame.QUIT:
                running = False
    
        player.move(screen.get_rect())
        screen.blit(player.image, player.rect)
    
        for block in blocks:
            offset = (player.rect.x - block.rect.x, player.rect.y - block.rect.y)
            colliding_bits = player.mask.overlap_mask(block.mask, offset)
            colliding_bits_image = colliding_bits.to_surface(setcolor=(0, 255, 0, 255), unsetcolor=(0, 0, 0, 0))
    
            screen.blit(colliding_bits_image, block.rect)
    
        clock.tick(144)
        pygame.display.flip()