The Python Game Book

code games. learn Python.

User Tools

Site Tools




Step 004 - Colorkey and Alpha Values

screenshot screenshot screenshot screenshot

In this page you will find 4 code examples: , , and All examples demonstrate how to work with transparency and pygame surfaces. is simple to understand. Compare it with 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. 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. shows you an interesting effect by changing the alpha-value of individual pixels. Move the mouse around and use the scroll wheel.

Code Discussion


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)
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().

Blitting on the Screen

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.


Code Discussion shall show you the possibilities of alpha-values (transparency) and image files.

Don't worry if you do not understand all of 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

  • pressed_keys : to indicate of a specific key is pressed at this moment.
  • key_pressed : to check if a specific key was (once) pressed and released.

Both methods will be discussed in more detail in →step011.

Blend Modes

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 <>.
    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

Alpha Value for the Whole Surface

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

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 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>

Source Code on Github

file in folder download comment pygame Download the whole Archive with all files from Github:
This program runs stand-alone and does not need other files pygame this program needs other files (see below) to run pygame yipyip's version of alphademo. This program needs other files (see below) to run
pygame/data source: wikipedia
pygame/data a .jpg graphic an not have in-build transparency. (notice the white background)
pygame/data a .png (as well as .gif) graphic can have in-build transparency. Notice the transparent background
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 -*-
dynamic blitting and colorkey
licence: gpl, see

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
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), color, pos, radius, width=0), (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:

#!/usr/bin/env python
# -*- coding: utf-8 -*-

    colorkey and alpha-value
    per-pixel-alpha code by Claudio Canepa <>
    licence: gpl, see
    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 <>
       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):
    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
    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_RGBA_MAX" ]
    # -------  mainloop ----------
    clock = pygame.time.Clock()
    mainloop = True
    effects = False
    while mainloop:
        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))
        # ------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(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__":

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:

#!/usr/bin/env python

Experiments with colorkey and alpha-value
Author:, prettifying by yipyip
per-pixel-alpha code by Claudio Canepa <>
updated to python 3.8 by by Áron Boros
Licence: gpl, see


import pygame
import os
import itertools


              (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 <>)
    #new_surface = pygame.Surface(surface.get_size(), pygame.SRCALPHA|pygame.HWSURFACE)
    new_surface = pygame.Surface(surface.get_size(), pygame.SRCALPHA, 32)
    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):

        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 = True
        while mainloop:
            # 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


    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()
        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()
        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__":

that does not mean that such files always have a transparent color!
a duck is called “Ente” in German
en/pygame/step004.txt · Last modified: 2020/06/27 11:34 by horst