backlinks to this page:
Github:
In this page you will find 4 code examples: 004_colorkey.py , 004_alphademo.py , 004_alphademo_pretty.py and 004_per-pixel-alphademo.py. All examples demonstrate how to work with transparency and pygame surfaces.
004_colorkey.py is simple to understand. Compare it with 003_static_blit.py on the previous page and look at the blue circle. Do you notice a difference ? Right, the ugly black corners around the blue circle are gone. This is thanks to pygame's set_colorkey command. By defining a specific color on a pygame surface as colorkey, you make this color (in our example, the black color) transparent.
There are 2 kind of image files: Those with in-build transparency , and those without. Only graphic files of the file type .png and .gif can have transparency1). Other file tpyes like the popular .jpg format can not have transparency. If you want transparency for such images you must add them manually with pygame. 004_alphademo.py shows you how to do that. Look at the slowly blinking colormonster (3rd from the left the second row). You can see the amount of alpha-value (the white text below the picture) necessary to make a picture fully visible or fully transparent.
You can also press the keys <key>Ins</key>, <key>Dec</key>, <key>Home</key>, <key>End</key>,<key>PageUp</key>, <key>PageDown</key>, <key>Num+</key>, <key>Num–</key> to manually change the rgb and alpha values in the topright images. Press the keys to see what happens.
For even more effects, you can change the Blit mode by pressing <key>ENTER</key>. This affects the mixing of rgb values from the image and those specified by the keys.
004_per-pixel-alphademo.py shows you an interesting effect by changing the alpha-value of individual pixels. Move the mouse around and use the scroll wheel.
There is only one important line in this example. To get rid of the ugly black corners of the blue ball surface we declare the color black (0.0.0) as transparent.
#make black the transparent color (red,green,blue) ball.set_colorkey((0,0,0))To make the blitting of a pygame surface faster, it is a good idea to use .convert() on the surface once all drawing on the surface is done. Note that if the surface contains transparent colors, you need to use convert.alpha() instead of .convert().
The same ballsurface is blitted on the screen (not on the background!) twice in this example: once (the left ball) before the mainloop start and once inside the mainloop. Inside the mainloop a pattern of colourful lines is drawn each frame. The lines will draw on top of the left surface, but the right surface is drawn on top of the lines.
Note that the “corners” of the ball surfaces are not simply white but transparent. The colourful lines are good visible “below” the corners of the right ball surface.
Note that in this code example, inside the mainloop all commands draw directly on the screen surface.
004_alphademo.py shall show you the possibilities of alpha-values (transparency) and image files.
Don't worry if you do not understand all of 004_alphademo.py yet - i don't understand all of it, neither. The important thing is to know how to use it. Some techniques like loading surfaces from files and using text will be explained in other pages. Also note that there are 2 ways of handling keyboard input in 004_alphademo.py.
Both methods will be discussed in more detail in →step011.
From the different blit-modes, BLEND_RGBA_MULT (mode number 8) seems to be the most meaningful one. Using this blit mode, you can make an image all blue, red or green by setting the per-pixel-alpha values for the corresponding colour. At the same time, you can set an alpha value for the whole image. This works both for images without transparency such as .jpg images but also for images with in-build transparency such as .gif or .png images.
def get_alpha_surface( surf, alpha=128, red=128, green=128, blue=128, mode=pygame.BLEND_RGBA_MULT): """ Allocate a new surface with user-defined values (0-255) for red, green, blue and alpha. Thanks to Claudio Canepa <ccanepacc@gmail.com>. """ tmp = pygame.Surface( surf.get_size(), pygame.SRCALPHA, 32) tmp.fill( (red,green,blue,alpha) ) tmp.blit(surf, (0,0), surf.get_rect(), mode) return tmp
For an example of how to use this function, see this code snippet:
tmp = get_alpha_surface(pngMonster3, a, r, g, b, mode) screen.blit(tmp, (600,10))
The different modes are integer values and can be found in the pygame documentation or by using python's
interactive interpreter:
>>>import pygame >>>help(pygame.constants)
If you have a pygame surface without in-build transparency (let's say loaded from an .jpg image) you can set an alpha-value (transparency) for the whole surface with a simple set_alpha() command as shown in this code snippet from 004_alphademo.py:
jpgMonster2.set_alpha(alpha) # alpha (0-255) for whole surface screen.blit(jpgMonster2, (400,300)) # blit on screen
<note tip>replace colormonster.jpg
with a picture of your own head. rename the picture or the relevant code line inside 005_alphademo.py
. Can you make your face all blue or all purple just by pressing keys ?</note>
<note tip>set_aplpha() allows you to create fading effects for game intros, in-game cinematic or game-over screens. Use a paint programm like Gimp, create a stunning game title (or game over message) and save it in the .jpg format. Now try to let pygame fade in or fade out of this picture (ideally while playing music, see →step010)</note>
file | in folder | download | comment |
---|---|---|---|
004_colorkey.py | pygame | Download the whole Archive with all files from Github: https://github.com/horstjens/ThePythonGameBook/archives/master | This program runs stand-alone and does not need other files |
004_alphademo.py | pygame | this program needs other files (see below) to run | |
004_alphademo_pretty.py | pygame | yipyip's version of alphademo. This program needs other files (see below) to run | |
800px-La_naissance_de_Venus.jpg ![]() | pygame/data | source: wikipedia | |
colormonster.jpg ![]() | pygame/data | a .jpg graphic an not have in-build transparency. (notice the white background) | |
colormonster.png ![]() | pygame/data | a .png (as well as .gif) graphic can have in-build transparency. Notice the transparent background | |
ente.jpg ![]() | pygame/data | a picture of a duck2) |
If you see no colourful source code below, click on “reload” on your browser. Or follow the links to github.
#!/usr/bin/env python # -*- coding: utf-8 -*- """ 004_colorkey.py dynamic blitting and colorkey url: http://thepythongamebook.com/en:part2:pygame:step004 author: horst.jens@spielend-programmieren.at licence: gpl, see http://www.gnu.org/licenses/gpl.html Blitting one surface on 2 static positions, once before the mainloop and once inside the mainloop. using colorkey to make a part of the surfaces tranparent blitting lines on the screen to create a colourful pattern like in a screensaver """ import pygame import random pygame.init() screen=pygame.display.set_mode((640,480)) background = pygame.Surface(screen.get_size()) background.fill((255,255,255)) # fill the background white (red,green,blue) background = background.convert() # faster blitting ballsurface = pygame.Surface((50,50)) # create a new surface (black by default) ballsurface.set_colorkey((0,0,0)) # make black the transparent color (red,green,blue) #pygame.draw.circle(Surface, color, pos, radius, width=0) pygame.draw.circle(ballsurface, (0,0,255), (25,25),25) # paint blue circle ballsurface = ballsurface.convert_alpha() # faster blitting, convert_alpha() because transparency screen.blit(background, (0,0)) #draw background on screen (overwriting all) ballx = 20 # left ball position bally = 240 screen.blit(ballsurface, (ballx, bally)) #draw the ball surface (lines will draw over this ball) ballx2 = 400 # right ball position bally2 = 380 clock = pygame.time.Clock() mainloop = True FPS = 30 # desired framerate in frames per second. try out other values ! playtime = 0.0 t = 0 # variable used to draw a pattern color1 = 0 color2 = 0 while mainloop: milliseconds = clock.tick(FPS) # do not go faster than this framerate playtime += milliseconds / 1000.0 for event in pygame.event.get(): if event.type == pygame.QUIT: mainloop = False # pygame window closed by user elif event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: mainloop = False # user pressed ESC # ------- draw cute pattern ------------------ pygame.draw.line(screen, (color1,255-color1,color2), (32*t,0), (0,480-24*t)) pygame.draw.line(screen, (255-color2,color2,color1), (32*t,480), (640,480-24*t)) screen.blit(ballsurface, (ballx2, bally2)) #draw the ball over the lines t += 1 # increase t if t > 20: t = 0 # reset t color1 = random.randint(0,255) # new color color2 = random.randint(0,255) # --------- end of cute pattern drawing code ---------- pygame.display.set_caption("Frame rate %.2f frames per second. Playtime: %.2f seconds" % (clock.get_fps(),playtime)) pygame.display.flip() # flip the screen 30 times a second print "This 'game' was played for %.2f seconds." % playtime
This program need other graphic files to be located in a subfolder called data
. See the file table above for details. To get the program working correctly, you best download and unpack the whole file archive (link in the file table above).
View/Edit/Download the file directly in Github: https://github.com/horstjens/ThePythonGameBook/blob/master/pygame/004_alphademo.py
#!/usr/bin/env python # -*- coding: utf-8 -*- """ 004_alphademo.py colorkey and alpha-value url: http://thepythongamebook.com/en:part2:pygame:step004 author: horst.jens@spielend-programmieren.at per-pixel-alpha code by Claudio Canepa <ccanepacc@gmail.com> licence: gpl, see http://www.gnu.org/licenses/gpl.html works with pyhton3.4 and python2.7 """ import pygame import os def get_alpha_surface( surf, alpha=128, red=128, green=128, blue=128, mode=pygame.BLEND_RGBA_MULT): """returns a copy of a surface object with user-defined values for red, green, blue and alpha. Values from 0-255. thanks to Claudio Canepa <ccanepacc@gmail.com> for this function.""" tmp = pygame.Surface( surf.get_size(), pygame.SRCALPHA, 32) tmp.fill( (red,green,blue,alpha) ) tmp.blit(surf, (0,0), surf.get_rect(), mode) return tmp def bounce(value, direction, bouncing=True, valuemin=0, valuemax=255): """bouncing a value (like alpha or color) between baluemin and valuemax. When bouncing is True, direction (usually -1 or 1) is inverted when reaching valuemin or valuemax""" value += direction # increase or decrase value by direction if value <= valuemin: value = valuemin if bouncing: direction *= -1 elif value >= valuemax: value = valuemax if bouncing: direction *= -1 return value, direction def write(msg="pygame is cool", size=24, color=(255,255,255)): myfont = pygame.font.SysFont("None", size) mytext = myfont.render(msg, True, color) mytext = mytext.convert_alpha() return mytext def alphademo(width=800, height=600): pygame.init() screen=pygame.display.set_mode((width, height)) background = pygame.Surface(screen.get_size()).convert() #background.fill((255, 255, 255)) #fill the background white venus = pygame.image.load(os.path.join("data","800px-La_naissance_de_Venus.jpg")).convert() # transform venus and blit on background in one go pygame.transform.scale(venus, (width, height), background) # --------- png image with convert.alpha() ------------------ # .png and .gif graphics can have transparency. use convert_alpha() pngMonster = pygame.image.load(os.path.join("data", "colormonster.png")).convert_alpha() pngMonster0 = pngMonster.copy() # a copy pngMonster3 = pngMonster.copy() # copy for per-pixel alpha # ---------- jpg image ------------ # using .convert() at an .png image is the same as using a .jpg # => no transparency ! jpgMonster = pygame.image.load(os.path.join("data","colormonster.jpg")).convert() jpgMonster0 = jpgMonster.copy() # copy of jpgMonster jpgMonster1 = jpgMonster.copy() # another copy to demonstrate colorkey jpgMonster1.set_colorkey((255,255,255)) # make white color transparent jpgMonster1.convert_alpha() jpgMonster2 = jpgMonster.copy() # another copy for surface alpha jpgMonster3 = jpgMonster.copy() # anoter copy for per-pixel alpha # ------- text surfaces ---------- png0text = write("png (has alpha)") png3text = write("png with pixel-alpha") jpg0text = write("jpg (no alpha)") jpg1text = write("jpg with colorkey") jpg2text = write("jpg with surface alpha") jpg3text = write("jpg with pixel-alpha") # ------- for bitmap-alpha -------- alpha = 128 # between 0 and 255. direction = 1 # change of alpha # ------- for per-pixel-alpha ----- r = 255 # red g = 255 # green b = 255 # blue a = 255 # pixel-alpha modeNr = 7 # index 7, int-value 8, name="BLEND_RGB_MULT" ,usage = pygame.BLEND_RGB_MULT paper = pygame.Surface((400,100)) # background for instructions #paper.fill((0,0,0)) # is already black, no fill necessary paper.set_alpha(128) # half-transparent modelist = [ "BLEND_ADD", "BLEND_SUB", "BLEND_MULT", "BLEND_MIN", "BLEND_MAX", "BLEND_RGBA_ADD", "BLEND_RGBA_SUB", "BLEND_RGBA_MULT", "BLEND_RGBA_MIN", "BLEND_RGBA_MAX" ] # ------- mainloop ---------- clock = pygame.time.Clock() mainloop = True effects = False while mainloop: clock.tick(30) screen.blit(background, (0,0)) # draw background every frame pygame.display.set_caption("insert/del=red:%i, home/end=green:%i, pgup/pgdwn=blue:%i, +/-=pixalpha:%i press ESC" % ( r, g, b, a)) for event in pygame.event.get(): if event.type == pygame.QUIT: mainloop = False elif event.type == pygame.KEYDOWN: # press and release key if event.key == pygame.K_ESCAPE: mainloop = False if event.key == pygame.K_RETURN or event.key == pygame.K_KP_ENTER: #modeNr += 1 #if modeNr > 9: # modeNr = 0 # cycle throug number 0 to 9 modeNr = (modeNr + 1) % len(modelist) # by yipyip mode = pygame.constants.__dict__[modelist[modeNr]] # ------ keyb is pressed ? ------- dr, dg, db, da = 0,0,0,0 # set changing to 0 for red, green, blue, pixel-alpha pressed_keys = pygame.key.get_pressed() if pressed_keys[pygame.K_PAGEUP]: db = 1 # blue up if pressed_keys[pygame.K_PAGEDOWN]: db = -1 # blue down if pressed_keys[pygame.K_HOME]: dg = 1 # green up if pressed_keys[pygame.K_END]: dg = -1 # green down if pressed_keys[pygame.K_INSERT]: dr = 1 # red up if pressed_keys[pygame.K_DELETE]: dr = -1 # red down if pressed_keys[pygame.K_KP_PLUS]: da = 1 # alpha up if pressed_keys[pygame.K_KP_MINUS]: da = -1 # alpha down # ------- change color and alpha values -------- alpha, direction = bounce(alpha, direction) # change alpha r, dr = bounce(r,dr, False) # red for per-pixel g, dg = bounce(g,dg, False) # green for per-pixel b, db = bounce(b, db, False) # blue for per-pixel a, da = bounce(a, da, False) # alpha for per-pixel # ----- blit jpgMonster0 as ist is, no alpha at all ------ screen.blit(jpgMonster0, (0, 300)) screen.blit(jpg0text,(0,550)) # ------blit jpgMonster1 with the colorkey set to white ------ screen.blit(jpgMonster1, (200,300)) screen.blit(jpg1text, (200,550)) # ----- blit jpgmonster2 with alpha for whole surface -------- jpgMonster2.set_alpha(alpha) # alpha for whole surface screen.blit(jpgMonster2, (400,300)) # blit on screen screen.blit(jpg2text,(400,550)) screen.blit(write("surface-alpha: %i" % alpha),(400,570)) # ----- blit jpgmonster3 with per-pixel alpha------- tmp = get_alpha_surface(jpgMonster3, a, r, g, b, mode) # get current alpha screen.blit(tmp, (600,300)) screen.blit(jpg3text, (600, 550)) # ----- blit pngMonster0 as it is, with transparency from image --- screen.blit(pngMonster0, (0, 10)) screen.blit(png0text, (0, 200)) # ----- blit pngMonster1 with colorkey set to black ---- # *** png already has alpha, does not need colorkey ** # ----- blit pngMonster2 with alpha for whole surface ----- # *** surface-alpha does not work if surface (png) already has alpha *** # ----- blit pngmonster3 with per-pixel alpha------- tmp = get_alpha_surface(pngMonster3, a, r, g, b, mode) # get current alpha screen.blit(tmp, (600,10)) screen.blit(png3text, (600,200)) # ---- instructions ---- screen.blit(paper, (188,150)) # semi-transparent background for instructions screen.blit(write("press [INS] / [DEL] to change red value: %i" % r,24, (255,255,255)),(190,150)) screen.blit(write("press [HOME] / [END] to change green value: %i" % g),(190,170)) screen.blit(write("press [PgUp] / [PgDwn] to chgange blue value: %i"% b), (190, 190)) screen.blit(write("press [Enter] for mode: %i (%s)" % (mode, modelist[modeNr])), (190,230)) screen.blit(write("press [+] / [-] (Keypad) to chgange alpha value: %i"% a), (190, 210)) # ------ next frame -------- pygame.display.flip() # flip the screen 30 times a second if __name__ == "__main__": alphademo()
This program need other graphic files to be located in a subfolder called data
. See the file table above for details. To get the program working correctly, you best download and unpack the whole file archive (link in the file table above).
<note tip>This verison works with python3.x only. For python 2x version, see the oode example above</note>
View/Edit/Download the file directly in Github: https://github.com/horstjens/ThePythonGameBook/blob/master/pygame/004_alphademo_pretty_python3x.py
#!/usr/bin/env python """ 004_alphademo_pretty.py Experiments with colorkey and alpha-value URL: http://thepythongamebook.com/en:part2:pygame:step004 Author: horst.jens@spielend-programmieren.at, prettifying by yipyip per-pixel-alpha code by Claudio Canepa <ccanepacc@gmail.com> updated to python 3.8 by by Áron Boros Licence: gpl, see http://www.gnu.org/licenses/gpl.html """ #### import pygame import os import itertools #### BLENDMODES = ((pygame.BLEND_ADD, "ADD"), (pygame.BLEND_SUB, "SUB"), (pygame.BLEND_MULT, "MULT"), (pygame.BLEND_MIN, "MIN"), (pygame.BLEND_MAX, "MAX"), (pygame.BLEND_RGBA_ADD, "RGBA ADD"), (pygame.BLEND_RGBA_SUB, "RGBA SUB"), (pygame.BLEND_RGBA_MULT, "RGBA MULT"), (pygame.BLEND_RGBA_MIN, "RGBA MIN"), (pygame.BLEND_RGBA_MAX, "RGBA MAX")) #### def load_pic(name, path="data"): return pygame.image.load(os.path.join(path, name)) #### def check(x, minval=0, maxval=255): return min(maxval, max(minval, x)) #### def get_alpha_surface(surface, rgba=(128, 128, 128, 128), mode=pygame.BLEND_RGBA_ADD): """ Return a copy of a surface object with user-defined values for red, green, blue and alpha. Values from 0-255. (Thanks to Claudio Canepa <ccanepacc@gmail.com>) """ #new_surface = pygame.Surface(surface.get_size(), pygame.SRCALPHA|pygame.HWSURFACE) new_surface = pygame.Surface(surface.get_size(), pygame.SRCALPHA, 32) new_surface.fill(rgba) new_surface.blit(surface, (0, 0), surface.get_rect(), mode) return new_surface #### class AlphaDemo(object): def __init__(self, width=900, height=600, fontsize=24): pygame.init() self.screen = pygame.display.set_mode((width, height), pygame.DOUBLEBUF) self.background = pygame.Surface(self.screen.get_size()).convert() self.font = pygame.font.SysFont('None', fontsize) self.clock = pygame.time.Clock() #self.background.fill((255, 255, 255)) venus = load_pic("800px-La_naissance_de_Venus.jpg").convert() # transform venus and blit pygame.transform.scale(venus, (width, height), self.background) # .png and .gif graphics can have transparency, use convert_alpha() self.png_monster = load_pic("colormonster.png").convert_alpha() # jpg image, no transparency! self.jpg_monster = load_pic("colormonster.jpg").convert() # per pixel rgba self.pp_rgba = [255, 255, 255, 128] alpha_up = range(0, 256, 4) alpha_down = alpha_up[-1::-1] # self.glob_alphas = itertools.cycle(alpha_up + alpha_down) self.glob_alphas = itertools.cycle(itertools.chain(itertools.chain(alpha_up,alpha_down))) self.step = 4 self.mode_nr = 7 def run(self): """ Mainloop """ mainloop = True while mainloop: self.clock.tick(20) # draw background every frame self.screen.blit(self.background, (0, 0)) for event in pygame.event.get(): if event.type == pygame.QUIT: mainloop = False elif event.type == pygame.KEYDOWN: if event.key == pygame.K_ESCAPE: mainloop = False self.action(pygame.key.get_pressed()) pygame.display.flip() pygame.quit() def action(self, pressed_keys): red, green, blue, alpha = self.pp_rgba if pressed_keys[pygame.K_UP]: blue = blue + self.step if pressed_keys[pygame.K_DOWN]: blue = blue - self.step if pressed_keys[pygame.K_PERIOD]: green = green + self.step if pressed_keys[pygame.K_COMMA]: green = green - self.step if pressed_keys[pygame.K_RIGHT]: red = red + self.step if pressed_keys[pygame.K_LEFT]: red = red - self.step if pressed_keys[pygame.K_MINUS]: alpha = alpha - self.step if pressed_keys[pygame.K_PLUS]: alpha = alpha + self.step if pressed_keys[pygame.K_RETURN]: self.mode_nr = (self.mode_nr + 1) % len(BLENDMODES) mode, mode_text = BLENDMODES[self.mode_nr] self.pp_rgba = list(map(check, (red, green, blue, alpha))) glob_alpha = next(self.glob_alphas) self.show_surfaces(self.png_monster.copy(), 'png', 0, 0, 200, 180, glob_alpha, self.pp_rgba, mode) self.show_surfaces(self.jpg_monster, 'jpg', 0, 300, 200, 180, glob_alpha, self.pp_rgba, mode) text = "left/right=red>%d comma/period=green>%d up/dwn=blue>%d "\ "+/-=ppalpha>%d " % tuple(self.pp_rgba) pygame.display.set_caption("%s Enter: Mode>%s" % (text, mode_text)) def show_surfaces(self, surf, pictype, x, y, x_delta, height, glob_alpha, pp_rgba, mode): yh = y + height #pure surface self.screen.blit(surf, (x, y)) self.write(x, y + height, "%s pure" % pictype) # with with colorkey ck_surf = surf.copy() ck_surf.set_colorkey((255,255,255)) x = x + x_delta self.screen.blit(ck_surf, (x, y)) self.write(x, yh, "%s colorkey" % pictype) # with alpha for whole surface alpha_surf = surf.copy() alpha_surf.set_alpha(glob_alpha) x = x + x_delta self.screen.blit(alpha_surf, (x, y)) self.write(x, yh, "%s alpha> %d" % (pictype, glob_alpha)) # with per-pixel alpha ppa_surf = surf.copy() ppa_surf = get_alpha_surface(ppa_surf, pp_rgba, mode) x = x + x_delta self.screen.blit(ppa_surf, (x, y)) self.write(x, yh, "%s, per-pixel-alpha" % pictype) def write(self, x, y, msg, color=(255,255,0)): self.screen.blit(self.font.render(msg, True, color).convert_alpha(), (x, y)) #### if __name__ == "__main__": AlphaDemo().run()