I have two images:
I'd like to essentially 'cut out' the black shape from the texture tile so that I end up with something along these lines:
Except transparent around the shape. Is this possible using pygame? This example I had to create in GIMP.
Additionally, would it be too performance-heavy to do this for every frame for a few sprites in a real-time environment? (30+ frames per second)
The drawing functions are fine if you want to draw simple shapes on the screen, but many games have images (also called sprites). Pygame is able to load images onto Surface objects from PNG, JPG, GIF, and BMP image files.
By default, pygame uses “Pygame window” as its title and pygame icon as its logo for pygame window. We can use set_caption() function to change the name and set_icon() to set icon of our window.
display. set_mode() function, which returns the pygame. Surface object for the window.
I made a solution, however it is not the best either for speed either for beauty. You can use double blitting with setting colorkeys for transparency. In that way the mask should have only two colors: black and white. Note that you can't use this for images with per pixel alpha (RGBA) only for RGB images. Other restriction is that it is recommended that the size of the texture and the mask image is the same (if not you should use areas for blitting).
In words, step by step:
Code sample:
#!/usr/bin/python
# -*- coding:utf8 -*-
import pygame, sys
#init pygame
pygame.init()
#init screen
screen=pygame.display.set_mode((800,600))
screen.fill((255,0,255))
#loading the images
texture=pygame.image.load("texture.jpg").convert()
texture_rect=texture.get_rect()
texture_rect.center=(200,300)
mask=pygame.Surface((texture_rect.width,texture_rect.height)) # mask should have only 2 colors: black and white
mask.fill((255,255,255))
pygame.draw.circle(mask,(0,0,0),(texture_rect.width/2,texture_rect.height/2),int(texture_rect.width*0.3))
mask_rect=mask.get_rect()
mask_rect.center=(600,300)
tmp_image=texture.copy() # make a copy of the texture to keep it unchanged for future usage
mask.set_colorkey((0,0,0)) # we want the black colored parts of the mask to be transparent
tmp_image.blit(mask,(0,0)) # blit the mask to the texture. the black parts are transparent so we see the pixels of the texture there
tmp_rect=tmp_image.get_rect()
tmp_rect.center=(400,300)
tmp_image.set_colorkey((255,255,255))
screen.blit(texture,texture_rect)
screen.blit(mask,mask_rect)
screen.blit(tmp_image,tmp_rect)
pygame.display.flip()
while 1:
event=pygame.event.wait()
if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key in [pygame.K_ESCAPE, pygame.K_q]):
sys.exit()
I recommend not to use jpg as mask because of its lossy format, I recommend bmp or png (bmp is better). Remember it not uses alpha so the edges won't be anti-aliased so it is not a nice solution in 2010 :)
Here is the screenshot of the result:
Edit: Hi again,
I made some tests with the blitting with BLEND_ADD and the results was promising. Here is the code:
import pygame, sys
#init pygame
pygame.init()
#init screen
screen=pygame.display.set_mode((800,600))
screen.fill((255,0,255))
#loading the images
texture=pygame.image.load("texture.jpg").convert_alpha()
texture_rect=texture.get_rect()
texture_rect.center=(200,300)
mask=pygame.image.load("mask2.png").convert_alpha()
mask_rect=mask.get_rect()
mask_rect.center=(600,300)
textured_mask=mask.copy()
textured_rect=textured_mask.get_rect()
textured_rect.center=400,300
textured_mask.blit(texture,(0,0),None,pygame.BLEND_ADD)
screen.blit(texture,texture_rect)
screen.blit(mask,mask_rect)
screen.blit(textured_mask,textured_rect)
pygame.display.flip()
while 1:
event=pygame.event.wait()
if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key in [pygame.K_ESCAPE, pygame.K_q]):
sys.exit()
And the result:
With this solution you can get per pixel alpha texturing. Please note that the mask should be an image with alpha channel so jpg could not be used. The best to use is png.
Texture image (texture.jpg):
Mask image (mask2.png):
If you're using images with a pre-rendered alpha and additive blending, you can get alpha-blended masks:
import pygame
import sys
screen = pygame.display.set_mode( (800, 600) )
pygame.init()
background = pygame.image.load( "background.png" )
mask = pygame.image.load( "mask.png" )
# Create a surface to hold the masked image
masked_image = pygame.surface.Surface( background.get_size(), 0, mask )
# Blit the texture normally
masked_image.blit( background, (0,0) )
# Multiply by the pre-rendered, inverted mask
masked_image.blit( mask, (0,0), None, pygame.BLEND_MULT )
# masked_image now holds the 'cutout' of your texture blended onto a black
# background, so we need to blit it as such, i.e., using additive blending.
screen.fill( (0, 0, 0) )
screen.blit( masked_image, (10, 10), None, pygame.BLEND_ADD )
pygame.display.flip()
while True:
event=pygame.event.wait()
if event.type == pygame.QUIT or (event.type == pygame.KEYDOWN and event.key in [pygame.K_ESCAPE, pygame.K_q]):
sys.exit()
Where background.png
and mask.png
are:
+ =
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With