Scout Now This tutorial has a related video course created by the Real Python squad. Watch information technology together with the written tutorial to deepen your understanding: Make a 2D Side-Scroller Game With PyGame

When I started learning computer programming late in the terminal millennium, information technology was driven by my desire to write figurer games. I tried to figure out how to write games in every language and on every platform I learned, including Python. That's how I discovered pygame and learned how to use information technology to write games and other graphical programs. At the time, I actually wanted a primer on pygame.

By the end of this commodity, y'all'll be able to:

  • Draw items on your screen
  • Play sound effects and music
  • Handle user input
  • Implement effect loops
  • Describe how game programming differs from standard procedural Python programming

This primer assumes you have a bones understanding of writing Python programs, including user-defined functions, imports, loops, and conditionals. Y'all should likewise be familiar with how to open files on your platform. A bones agreement of object-oriented Python is helpful besides. pygame works with most versions of Python, simply Python three.six is recommended and used throughout this article.

Yous can go all of the lawmaking in this article to follow forth:

Groundwork and Setup

pygame is a Python wrapper for the SDL library, which stands for Elementary DirectMedia Layer. SDL provides cross-platform admission to your system'due south underlying multimedia hardware components, such as sound, video, mouse, keyboard, and joystick. pygame started life as a replacement for the stalled PySDL project. The cross-platform nature of both SDL and pygame ways you can write games and rich multimedia Python programs for every platform that supports them!

To install pygame on your platform, utilise the advisable pip control:

You can verify the install by loading i of the examples that comes with the library:

                                            $                python3 -m pygame.examples.aliens                          

If a game window appears, and then pygame is installed properly! If you run into problems, so the Getting Started guide outlines some known issues and caveats for all platforms.

Basic PyGame Program

Before getting downwards to specifics, let's take a wait at a bones pygame program. This program creates a window, fills the background with white, and draws a blue circle in the eye of it:

                                                              1                # Simple pygame program                                  2                                  3                # Import and initialize the pygame library                                  4                import                pygame                                  5                pygame                .                init                ()                                  6                                  vii                # Set up the cartoon window                                  8                screen                =                pygame                .                display                .                set_mode                ([                500                ,                500                ])                                  9                x                # Run until the user asks to quit                eleven                running                =                Truthful                12                while                running                :                13                14                # Did the user click the window shut push button?                fifteen                for                event                in                pygame                .                consequence                .                get                ():                xvi                if                event                .                type                ==                pygame                .                QUIT                :                17                running                =                False                18                19                # Fill up the groundwork with white                twenty                screen                .                fill up                ((                255                ,                255                ,                255                ))                21                22                # Describe a solid blueish circle in the center                23                pygame                .                draw                .                circle                (                screen                ,                (                0                ,                0                ,                255                ),                (                250                ,                250                ),                75                )                24                25                # Flip the display                26                pygame                .                display                .                flip                ()                27                28                # Washed! Fourth dimension to quit.                29                pygame                .                quit                ()                          

When yous run this program, you'll meet a window that looks like this:

A simple pygame program

Let'southward break this code downwards, department by section:

  • Lines iv and 5 import and initialize the pygame library. Without these lines, there is no pygame.

  • Line 8 sets upwardly your program's display window. You provide either a listing or a tuple that specifies the width and pinnacle of the window to create. This program uses a list to create a foursquare window with 500 pixels on each side.

  • Lines 11 and 12 fix up a game loop to control when the program ends. Y'all'll cover game loops later on in this tutorial.

  • Lines 15 to 17 scan and handle events within the game loop. You'll get to events a chip later as well. In this case, the but issue handled is pygame.QUIT, which occurs when the user clicks the window close push button.

  • Line 20 fills the window with a solid color. screen.make full() accepts either a listing or tuple specifying the RGB values for the colour. Since (255, 255, 255) was provided, the window is filled with white.

  • Line 23 draws a circle in the window, using the following parameters:

    • screen: the window on which to describe
    • (0, 0, 255): a tuple containing RGB color values
    • (250, 250): a tuple specifying the center coordinates of the circle
    • 75: the radius of the circle to depict in pixels
  • Line 26 updates the contents of the brandish to the screen. Without this phone call, zilch appears in the window!

  • Line 29 exits pygame. This only happens once the loop finishes.

That'southward the pygame version of "Hello, World." Now permit'due south dig a little deeper into the concepts behind this code.

PyGame Concepts

As pygame and the SDL library are portable across unlike platforms and devices, they both need to define and piece of work with abstractions for diverse hardware realities. Understanding those concepts and abstractions will help y'all design and develop your ain games.

Initialization and Modules

The pygame library is composed of a number of Python constructs, which include several unlike modules. These modules provide abstract access to specific hardware on your system, as well as compatible methods to work with that hardware. For example, brandish allows uniform access to your video display, while joystick allows abstruse command of your joystick.

After importing the pygame library in the example above, the beginning thing you did was initialize PyGame using pygame.init(). This part calls the split up init() functions of all the included pygame modules. Since these modules are abstractions for specific hardware, this initialization step is required and so that you lot tin can work with the aforementioned code on Linux, Windows, and Mac.

Displays and Surfaces

In improver to the modules, pygame likewise includes several Python classes, which encapsulate non-hardware dependent concepts. One of these is the Surface which, at its almost basic, defines a rectangular surface area on which y'all can draw. Surface objects are used in many contexts in pygame. Afterwards you lot'll come across how to load an image into a Surface and brandish it on the screen.

In pygame, everything is viewed on a single user-created display, which tin be a window or a full screen. The display is created using .set_mode(), which returns a Surface representing the visible part of the window. It is this Surface that y'all pass into drawing functions like pygame.draw.circle(), and the contents of that Surface are pushed to the brandish when you call pygame.display.flip().

Images and Rects

Your basic pygame program drew a shape direct onto the display's Surface, only you lot tin can likewise piece of work with images on the disk. The image module allows you to load and save images in a variety of popular formats. Images are loaded into Surface objects, which can then be manipulated and displayed in numerous ways.

As mentioned above, Surface objects are represented by rectangles, as are many other objects in pygame, such every bit images and windows. Rectangles are then heavily used that there is a special Rect class just to handle them. You lot'll be using Rect objects and images in your game to draw players and enemies, and to manage collisions between them.

Okay, that's enough theory. Let's blueprint and write a game!

Basic Game Blueprint

Before you starting time writing any code, information technology'southward e'er a practiced thought to have some design in place. Since this is a tutorial game, let's pattern some bones gameplay for it as well:

  • The goal of the game is to avoid incoming obstacles:
    • The player starts on the left side of the screen.
    • The obstacles enter randomly from the right and move left in a direct line.
  • The player tin move left, right, up, or down to avert the obstacles.
  • The player cannot motility off the screen.
  • The game ends either when the player is hit by an obstruction or when the user closes the window.

When he was describing software projects, a erstwhile colleague of mine used to say, "You don't know what y'all do until you know what you lot don't do." With that in mind, here are some things that won't be covered in this tutorial:

  • No multiple lives
  • No scorekeeping
  • No actor assail capabilities
  • No advancing levels
  • No dominate characters

You're free to try your hand at adding these and other features to your own plan.

Let'south go started!

Importing and Initializing PyGame

Afterward yous import pygame, yous'll also demand to initialize information technology. This allows pygame to connect its abstractions to your specific hardware:

                                                                      i                  # Import the pygame module                                      2                  import                  pygame                                      iii                                      4                  # Import pygame.locals for easier access to key coordinates                                      v                  # Updated to conform to flake8 and blackness standards                                      vi                  from                  pygame.locals                  import                  (                                      vii                  K_UP                  ,                                      viii                  K_DOWN                  ,                                      9                  K_LEFT                  ,                  10                  K_RIGHT                  ,                  11                  K_ESCAPE                  ,                  12                  KEYDOWN                  ,                  13                  QUIT                  ,                  14                  )                  fifteen                  16                  # Initialize pygame                  17                  pygame                  .                  init                  ()                              

The pygame library defines many things too modules and classes. Information technology also defines some local constants for things like keystrokes, mouse movements, and display attributes. You reference these constants using the syntax pygame.<Constant>. By importing specific constants from pygame.locals, you tin can utilize the syntax <CONSTANT> instead. This will relieve y'all some keystrokes and improve overall readability.

Setting Up the Brandish

Now you need something to draw on! Create a screen to be the overall canvas:

                                                                      ane                  # Import the pygame module                                      two                  import                  pygame                                      3                                      4                  # Import pygame.locals for easier access to key coordinates                                      5                  # Updated to accommodate to flake8 and black standards                                      6                  from                  pygame.locals                  import                  (                                      7                  K_UP                  ,                                      viii                  K_DOWN                  ,                                      9                  K_LEFT                  ,                  ten                  K_RIGHT                  ,                  xi                  K_ESCAPE                  ,                  12                  KEYDOWN                  ,                  thirteen                  QUIT                  ,                  14                  )                  15                  16                  # Initialize pygame                  17                  pygame                  .                  init                  ()                  18                  19                                      # Define constants for the screen width and pinnacle                                    xx                                      SCREEN_WIDTH                    =                    800                                    21                                      SCREEN_HEIGHT                    =                    600                                    22                  23                                      # Create the screen object                                    24                                      # The size is determined by the constant SCREEN_WIDTH and SCREEN_HEIGHT                                    25                                      screen                    =                    pygame                    .                    display                    .                    set_mode                    ((                    SCREEN_WIDTH                    ,                    SCREEN_HEIGHT                    ))                                                

You create the screen to employ by calling pygame.display.set_mode() and passing a tuple or list with the desired width and top. In this case, the window is 800x600, as defined past the constants SCREEN_WIDTH and SCREEN_HEIGHT on lines twenty and 21. This returns a Surface which represents the inside dimensions of the window. This is the portion of the window you tin control, while the Bone controls the window borders and championship bar.

If y'all run this program now, then you'll run into a window pop up briefly and and then immediately disappear equally the programme exits. Don't blink or you might miss it! In the next section, you'll focus on the main game loop to ensure that your program exits simply when given the correct input.

Setting Up the Game Loop

Every game from Pong to Fortnite uses a game loop to control gameplay. The game loop does four very of import things:

  1. Processes user input
  2. Updates the state of all game objects
  3. Updates the display and sound output
  4. Maintains the speed of the game

Every bicycle of the game loop is called a frame, and the quicker you tin can practice things each cycle, the faster your game will run. Frames continue to occur until some condition to go out the game is met. In your design, there are two conditions that can end the game loop:

  1. The thespian collides with an obstruction. (You lot'll cover collision detection later.)
  2. The thespian closes the window.

The start thing the game loop does is process user input to allow the player to move effectually the screen. Therefore, you demand some way to capture and process a diverseness of input. Y'all do this using the pygame event system.

Processing Events

Key presses, mouse movements, and even joystick movements are some of the ways in which a user can provide input. All user input results in an result existence generated. Events tin happen at whatsoever time and often (but not always) originate outside the plan. All events in pygame are placed in the event queue, which tin then exist accessed and manipulated. Dealing with events is referred to as handling them, and the code to do so is called an event handler.

Every event in pygame has an event type associated with it. For your game, the event types you lot'll focus on are keypresses and window closure. Keypress events have the consequence type KEYDOWN, and the window closure event has the type QUIT. Unlike event types may besides have other data associated with them. For example, the KEYDOWN event blazon as well has a variable called central to indicate which primal was pressed.

You access the list of all active events in the queue by calling pygame.issue.go(). Y'all and then loop through this listing, inspect each effect type, and respond accordingly:

                                                  27                  # Variable to proceed the chief loop running                  28                  running                  =                  Truthful                  29                  30                  # Main loop                  31                  while                  running                  :                  32                  # Await at every consequence in the queue                  33                  for                  event                  in                  pygame                  .                  result                  .                  go                  ():                  34                  # Did the user hit a key?                  35                  if                  event                  .                  type                  ==                  KEYDOWN                  :                  36                  # Was it the Escape central? If so, finish the loop.                  37                  if                  result                  .                  key                  ==                  K_ESCAPE                  :                  38                  running                  =                  Simulated                  39                  40                  # Did the user click the window close push? If so, stop the loop.                  41                  elif                  upshot                  .                  type                  ==                  QUIT                  :                  42                  running                  =                  False                              

Let'southward accept a closer look at this game loop:

  • Line 28 sets upwardly a control variable for the game loop. To go out the loop and the game, you set running = False. The game loop starts on line 29.

  • Line 31 starts the effect handler, walking through every outcome currently in the event queue. If there are no events, then the list is empty, and the handler won't practise anything.

  • Lines 35 to 38 check if the current event.blazon is a KEYDOWN upshot. If it is, and so the program checks which key was pressed by looking at the effect.central attribute. If the cardinal is the Esc cardinal, indicated past K_ESCAPE, then information technology exits the game loop past setting running = Simulated.

  • Lines 41 and 42 do a like check for the effect type called QUIT. This outcome simply occurs when the user clicks the window close push. The user may also utilize any other operating organization activeness to close the window.

When you add these lines to the previous code and run information technology, yous'll see a window with a blank or black screen:

An empty, but persistent, pygame window

The window won't disappear until y'all printing the Esc cardinal, or otherwise trigger a QUIT effect past closing the window.

Drawing on the Screen

In the sample program, y'all drew on the screen using two commands:

  1. screen.make full() to fill the background
  2. pygame.draw.circle() to draw a circumvolve

Now yous'll learn nigh a third way to draw to the screen: using a Surface.

Remember that a Surface is a rectangular object on which yous tin draw, like a blank sheet of paper. The screen object is a Surface, and you can create your own Surface objects separate from the brandish screen. Allow's run across how that works:

                                                  44                  # Fill the screen with white                  45                  screen                  .                  make full                  ((                  255                  ,                  255                  ,                  255                  ))                  46                  47                  # Create a surface and pass in a tuple containing its length and width                  48                  surf                  =                  pygame                  .                  Surface                  ((                  fifty                  ,                  50                  ))                  49                  l                  # Give the surface a color to separate information technology from the groundwork                  51                  surf                  .                  fill                  ((                  0                  ,                  0                  ,                  0                  ))                  52                  rect                  =                  surf                  .                  get_rect                  ()                              

Afterwards the screen is filled with white on line 45, a new Surface is created on line 48. This Surface is 50 pixels wide, 50 pixels tall, and assigned to surf. At this bespeak, you care for it just like the screen. Then on line, 51 you fill it with black. You can besides access its underlying Rect using .get_rect(). This is stored as rect for later use.

Using .blit() and .flip()

But creating a new Surface isn't enough to see it on the screen. To exercise that, you demand to blit the Surface onto another Surface. The term blit stands for Block Transfer, and .blit() is how you copy the contents of one Surface to another. You can but .blit() from i Surface to another, only since the screen is but some other Surface, that's not a problem. Here'south how you lot draw surf on the screen:

                                                  54                  # This line says "Describe surf onto the screen at the heart"                  55                  screen                  .                  blit                  (                  surf                  ,                  (                  SCREEN_WIDTH                  /                  2                  ,                  SCREEN_HEIGHT                  /                  2                  ))                  56                  pygame                  .                  brandish                  .                  flip                  ()                              

The .blit() call on line 55 takes 2 arguments:

  1. The Surface to draw
  2. The location at which to depict it on the source Surface

The coordinates (SCREEN_WIDTH/two, SCREEN_HEIGHT/2) tell your plan to place surf in the exact eye of the screen, simply it doesn't quite wait that fashion:

Blitting a surface onto the screen

The reason why the image looks off-middle is that .blit() puts the meridian-left corner of surf at the location given. If you lot want surf to be centered, then y'all'll have to practise some math to shift information technology up and to the left. You tin exercise this past subtracting the width and acme of surf from the width and pinnacle of the screen, dividing each past two to locate the center, and and so passing those numbers equally arguments to screen.blit():

                                                  54                  # Put the center of surf at the center of the display                  55                  surf_center                  =                  (                  56                  (                  SCREEN_WIDTH                  -                  surf                  .                  get_width                  ())                  /                  2                  ,                  57                  (                  SCREEN_HEIGHT                  -                  surf                  .                  get_height                  ())                  /                  2                  58                  )                  59                  sixty                  # Draw surf at the new coordinates                  61                  screen                  .                  blit                  (                  surf                  ,                  surf_center                  )                  62                  pygame                  .                  display                  .                  flip                  ()                              

Notice the telephone call to pygame.display.flip() later on the call to blit(). This updates the entire screen with everything that's been drawn since the last flip. Without the telephone call to .flip(), zero is shown.

Sprites

In your game design, the player starts on the left, and obstacles come up in from the right. Y'all can represent all the obstacles with Surface objects to make drawing everything easier, but how do you know where to draw them? How do you lot know if an obstacle has collided with the thespian? What happens when the obstacle flies off the screen? What if you desire to depict background images that also move? What if you lot want your images to exist animated? You can handle all these situations and more with sprites.

In programming terms, a sprite is a 2D representation of something on the screen. Essentially, information technology'southward a picture. pygame provides a Sprite grade, which is designed to agree 1 or several graphical representations of whatsoever game object that you want to brandish on the screen. To utilize it, you create a new class that extends Sprite. This allows you to use its built-in methods.

Players

Here's how y'all use Sprite objects with the current game to ascertain the player. Insert this code after line xviii:

                                                  20                  # Ascertain a Player object by extending pygame.sprite.Sprite                  21                  # The surface drawn on the screen is now an attribute of 'player'                  22                  class                  Actor                  (                  pygame                  .                  sprite                  .                  Sprite                  ):                  23                  def                  __init__                  (                  self                  ):                  24                  super                  (                  Actor                  ,                  self                  )                  .                  __init__                  ()                  25                  self                  .                  surf                  =                  pygame                  .                  Surface                  ((                  75                  ,                  25                  ))                  26                  self                  .                  surf                  .                  fill                  ((                  255                  ,                  255                  ,                  255                  ))                  27                  self                  .                  rect                  =                  self                  .                  surf                  .                  get_rect                  ()                              

You offset define Player by extending pygame.sprite.Sprite on line 22. Then .__init__() uses .super() to call the .__init__() method of Sprite. For more info on why this is necessary, you can read Supercharge Your Classes With Python super().

Next, you define and initialize .surf to hold the image to display, which is currently a white box. You lot as well define and initialize .rect, which you'll use to draw the role player later. To use this new class, you need to create a new object and change the drawing code every bit well. Expand the lawmaking block below to see it all together:

                                                                      one                  # Import the pygame module                                      two                  import                  pygame                                      3                                      4                  # Import pygame.locals for easier admission to primal coordinates                                      5                  # Updated to conform to flake8 and black standards                                      6                  from                  pygame.locals                  import                  (                                      7                  K_UP                  ,                                      8                  K_DOWN                  ,                                      nine                  K_LEFT                  ,                  x                  K_RIGHT                  ,                  xi                  K_ESCAPE                  ,                  12                  KEYDOWN                  ,                  xiii                  QUIT                  ,                  14                  )                  fifteen                  16                  # Ascertain constants for the screen width and height                  17                  SCREEN_WIDTH                  =                  800                  xviii                  SCREEN_HEIGHT                  =                  600                  19                  20                                      # Define a player object by extending pygame.sprite.Sprite                                    21                                      # The surface drawn on the screen is at present an attribute of 'actor'                                    22                                      form                    Thespian                    (                    pygame                    .                    sprite                    .                    Sprite                    ):                                    23                                      def                    __init__                    (                    self                    ):                                    24                                      super                    (                    Player                    ,                    self                    )                    .                    __init__                    ()                                    25                                      self                    .                    surf                    =                    pygame                    .                    Surface                    ((                    75                    ,                    25                    ))                                    26                                      cocky                    .                    surf                    .                    fill                    ((                    255                    ,                    255                    ,                    255                    ))                                    27                                      self                    .                    rect                    =                    self                    .                    surf                    .                    get_rect                    ()                                    28                  29                  # Initialize pygame                  thirty                  pygame                  .                  init                  ()                  31                  32                  # Create the screen object                  33                  # The size is adamant by the constant SCREEN_WIDTH and SCREEN_HEIGHT                  34                  screen                  =                  pygame                  .                  display                  .                  set_mode                  ((                  SCREEN_WIDTH                  ,                  SCREEN_HEIGHT                  ))                  35                  36                                      # Instantiate thespian. Right now, this is just a rectangle.                                    37                                      actor                    =                    Player                    ()                                    38                  39                  # Variable to keep the main loop running                  forty                  running                  =                  True                  41                  42                  # Main loop                  43                  while                  running                  :                  44                  # for loop through the consequence queue                  45                  for                  outcome                  in                  pygame                  .                  upshot                  .                  get                  ():                  46                  # Check for KEYDOWN consequence                  47                  if                  event                  .                  type                  ==                  KEYDOWN                  :                  48                  # If the Esc key is pressed, then leave the main loop                  49                  if                  event                  .                  central                  ==                  K_ESCAPE                  :                  50                  running                  =                  Fake                  51                  # Check for QUIT event. If QUIT, then set running to imitation.                  52                  elif                  event                  .                  blazon                  ==                  QUIT                  :                  53                  running                  =                  Imitation                  54                  55                  # Fill up the screen with blackness                  56                  screen                  .                  fill                  ((                  0                  ,                  0                  ,                  0                  ))                  57                  58                                      # Draw the role player on the screen                                    59                                      screen                    .                    blit                    (                    actor                    .                    surf                    ,                    (                    SCREEN_WIDTH                    /                    2                    ,                    SCREEN_HEIGHT                    /                    2                    ))                                    60                  61                  # Update the display                  62                  pygame                  .                  brandish                  .                  flip                  ()                              

Run this code. You'll see a white rectangle at roughly the centre of the screen:

Basic player sprite being drawn

What do you think would happen if you changed line 59 to screen.blit(player.surf, player.rect)? Endeavour it and see:

                                                  55                  # Fill the screen with black                  56                  screen                  .                  fill                  ((                  0                  ,                  0                  ,                  0                  ))                  57                  58                  # Draw the player on the screen                  59                                      screen                    .                    blit                    (                    player                    .                    surf                    ,                    role player                    .                    rect                    )                                    60                  61                  # Update the brandish                  62                  pygame                  .                  display                  .                  flip                  ()                              

When you pass a Rect to .blit(), it uses the coordinates of the acme left corner to depict the surface. Yous'll employ this later to make your role player move!

User Input

And then far, you lot've learned how to set up pygame and draw objects on the screen. Now, the real fun starts! Yous'll make the role player controllable using the keyboard.

Earlier, you saw that pygame.event.get() returns a list of the events in the effect queue, which you scan for KEYDOWN issue types. Well, that'south not the only fashion to read keypresses. pygame besides provides pygame.event.get_pressed(), which returns a dictionary containing all the current KEYDOWN events in the queue.

Put this in your game loop right later the outcome handling loop. This returns a dictionary containing the keys pressed at the commencement of every frame:

                                                  54                  # Get the gear up of keys pressed and cheque for user input                  55                  pressed_keys                  =                  pygame                  .                  key                  .                  get_pressed                  ()                              

Next, you lot write a method in Player to accepts that lexicon. This will define the behavior of the sprite based off the keys that are pressed. Here'due south what that might look like:

                                                  29                  # Move the sprite based on user keypresses                  30                  def                  update                  (                  self                  ,                  pressed_keys                  ):                  31                  if                  pressed_keys                  [                  K_UP                  ]:                  32                  self                  .                  rect                  .                  move_ip                  (                  0                  ,                  -                  5                  )                  33                  if                  pressed_keys                  [                  K_DOWN                  ]:                  34                  self                  .                  rect                  .                  move_ip                  (                  0                  ,                  5                  )                  35                  if                  pressed_keys                  [                  K_LEFT                  ]:                  36                  self                  .                  rect                  .                  move_ip                  (                  -                  5                  ,                  0                  )                  37                  if                  pressed_keys                  [                  K_RIGHT                  ]:                  38                  self                  .                  rect                  .                  move_ip                  (                  five                  ,                  0                  )                              

K_UP, K_DOWN, K_LEFT, and K_RIGHT correspond to the arrow keys on the keyboard. If the dictionary entry for that key is True, then that central is downwards, and you move the histrion .rect in the proper direction. Hither you use .move_ip(), which stands for movement in place, to motion the current Rect.

So yous can call .update() every frame to motility the actor sprite in response to keypresses. Add this call right after the call to .get_pressed():

                                                  52                  # Main loop                  53                  while                  running                  :                  54                  # for loop through the event queue                  55                  for                  upshot                  in                  pygame                  .                  issue                  .                  get                  ():                  56                  # Cheque for KEYDOWN event                  57                  if                  event                  .                  type                  ==                  KEYDOWN                  :                  58                  # If the Esc cardinal is pressed, so get out the primary loop                  59                  if                  event                  .                  key                  ==                  K_ESCAPE                  :                  sixty                  running                  =                  False                  61                  # Check for QUIT event. If QUIT, and then set running to fake.                  62                  elif                  event                  .                  type                  ==                  QUIT                  :                  63                  running                  =                  Imitation                  64                  65                  # Become all the keys currently pressed                  66                  pressed_keys                  =                  pygame                  .                  key                  .                  get_pressed                  ()                  67                  68                                      # Update the player sprite based on user keypresses                                    69                                      player                    .                    update                    (                    pressed_keys                    )                                    70                  71                  # Fill the screen with blackness                  72                  screen                  .                  fill up                  ((                  0                  ,                  0                  ,                  0                  ))                              

At present you can move your role player rectangle effectually the screen with the arrow keys:

Keypresses moving a sprite in pygame

Y'all may detect two minor problems:

  1. The player rectangle tin can move very fast if a key is held downward. You lot'll work on that later.
  2. The player rectangle can move off the screen. Let'south solve that one now.

To go on the actor on the screen, yous need to add some logic to observe if the rect is going to move off screen. To do that, you lot check whether the rect coordinates have moved beyond the screen'south boundary. If so, then you instruct the program to move information technology dorsum to the edge:

                                                  25                  # Move the sprite based on user keypresses                  26                  def                  update                  (                  self                  ,                  pressed_keys                  ):                  27                  if                  pressed_keys                  [                  K_UP                  ]:                  28                  self                  .                  rect                  .                  move_ip                  (                  0                  ,                  -                  5                  )                  29                  if                  pressed_keys                  [                  K_DOWN                  ]:                  30                  self                  .                  rect                  .                  move_ip                  (                  0                  ,                  5                  )                  31                  if                  pressed_keys                  [                  K_LEFT                  ]:                  32                  self                  .                  rect                  .                  move_ip                  (                  -                  5                  ,                  0                  )                  33                  if                  pressed_keys                  [                  K_RIGHT                  ]:                  34                  self                  .                  rect                  .                  move_ip                  (                  5                  ,                  0                  )                  35                  36                                      # Continue player on the screen                                    37                                      if                    self                    .                    rect                    .                    left                    <                    0                    :                                    38                                      self                    .                    rect                    .                    left                    =                    0                                    39                                      if                    self                    .                    rect                    .                    correct                    >                    SCREEN_WIDTH                    :                                    40                                      self                    .                    rect                    .                    right                    =                    SCREEN_WIDTH                                    41                                      if                    self                    .                    rect                    .                    acme                    <=                    0                    :                                    42                                      self                    .                    rect                    .                    top                    =                    0                                    43                                      if                    self                    .                    rect                    .                    bottom                    >=                    SCREEN_HEIGHT                    :                                    44                                      self                    .                    rect                    .                    lesser                    =                    SCREEN_HEIGHT                                                

Here, instead of using .move(), you just change the corresponding coordinates of .pinnacle, .bottom, .left, or .right directly. Examination this, and y'all'll find the role player rectangle can no longer move off the screen.

At present let's add some enemies!

Enemies

What's a game without enemies? You lot'll use the techniques you've already learned to create a basic enemy class, and so create a lot of them for your player to avoid. Get-go, import the random library:

                                                                      4                  # Import random for random numbers                                      5                  import                  random                              

Then create a new sprite class chosen Enemy, following the same pattern you used for Player:

                                                  55                  # Define the enemy object by extending pygame.sprite.Sprite                  56                  # The surface you lot draw on the screen is now an attribute of 'enemy'                  57                  class                  Enemy                  (                  pygame                  .                  sprite                  .                  Sprite                  ):                  58                  def                  __init__                  (                  cocky                  ):                  59                  super                  (                  Enemy                  ,                  self                  )                  .                  __init__                  ()                  60                  self                  .                  surf                  =                  pygame                  .                  Surface                  ((                  20                  ,                  x                  ))                  61                  cocky                  .                  surf                  .                  fill                  ((                  255                  ,                  255                  ,                  255                  ))                  62                  self                  .                  rect                  =                  self                  .                  surf                  .                  get_rect                  (                  63                  centre                  =                  (                  64                  random                  .                  randint                  (                  SCREEN_WIDTH                  +                  20                  ,                  SCREEN_WIDTH                  +                  100                  ),                  65                  random                  .                  randint                  (                  0                  ,                  SCREEN_HEIGHT                  ),                  66                  )                  67                  )                  68                  cocky                  .                  speed                  =                  random                  .                  randint                  (                  5                  ,                  20                  )                  69                  lxx                  # Move the sprite based on speed                  71                  # Remove the sprite when information technology passes the left edge of the screen                  72                  def                  update                  (                  self                  ):                  73                  self                  .                  rect                  .                  move_ip                  (                  -                  cocky                  .                  speed                  ,                  0                  )                  74                  if                  self                  .                  rect                  .                  right                  <                  0                  :                  75                  self                  .                  kill                  ()                              

At that place are iv notable differences between Enemy and Role player:

  1. On lines 62 to 67, yous update rect to be a random location forth the right edge of the screen. The center of the rectangle is only off the screen. Information technology'south located at some position betwixt xx and 100 pixels away from the right edge, and somewhere between the top and bottom edges.

  2. On line 68, you ascertain .speed every bit a random number between 5 and 20. This specifies how fast this enemy moves towards the player.

  3. On lines 73 to 76, you define .update(). It takes no arguments since enemies move automatically. Instead, .update() moves the enemy toward the left side of the screen at the .speed defined when it was created.

  4. On line 74, you check whether the enemy has moved off-screen. To make sure the Enemy is fully off the screen and won't just disappear while it's yet visible, you cheque that the right side of the .rect has gone past the left side of the screen. Once the enemy is off-screen, you telephone call .kill() to foreclose it from being candy further.

So, what does .impale() practice? To figure this out, you have to know about Sprite Groups.

Sprite Groups

Another super useful class that pygame provides is the Sprite Group. This is an object that holds a group of Sprite objects. So why use information technology? Can't you just rail your Sprite objects in a listing instead? Well, y'all can, but the reward of using a Grouping lies in the methods it exposes. These methods aid to detect whether whatever Enemy has collided with the Player, which makes updates much easier.

Let'southward see how to create sprite groups. Yous'll create two different Group objects:

  1. The kickoff Group volition hold every Sprite in the game.
  2. The 2d Grouping will hold only the Enemy objects.

Here'south what that looks like in code:

                                            82                # Create the 'role player'                83                player                =                Player                ()                84                85                                  # Create groups to hold enemy sprites and all sprites                                86                                  # - enemies is used for collision detection and position updates                                87                                  # - all_sprites is used for rendering                                88                                  enemies                  =                  pygame                  .                  sprite                  .                  Group                  ()                                89                                  all_sprites                  =                  pygame                  .                  sprite                  .                  Group                  ()                                90                                  all_sprites                  .                  add                  (                  role player                  )                                91                92                # Variable to keep the primary loop running                93                running                =                True                          

When you call .kill(), the Sprite is removed from every Group to which information technology belongs. This removes the references to the Sprite as well, which allows Python'due south garbage collector to repossess the memory every bit necessary.

At present that you take an all_sprites group, you can alter how objects are drawn. Instead of calling .blit() on just Player, y'all can iterate over everything in all_sprites:

                                            117                # Fill the screen with black                118                screen                .                fill                ((                0                ,                0                ,                0                ))                119                120                                  # Draw all sprites                                121                                  for                  entity                  in                  all_sprites                  :                                122                                  screen                  .                  blit                  (                  entity                  .                  surf                  ,                  entity                  .                  rect                  )                                123                124                # Flip everything to the display                125                pygame                .                display                .                flip                ()                          

Now, anything put into all_sprites will be drawn with every frame, whether it's an enemy or the actor.

There's just one trouble… Yous don't have any enemies! You could create a bunch of enemies at the beginning of the game, only the game would chop-chop get boring when they all left the screen a few seconds afterward. Instead, let'south explore how to keep a steady supply of enemies coming as the game progresses.

Custom Events

The design calls for enemies to appear at regular intervals. This means that at gear up intervals, y'all demand to do two things:

  1. Create a new Enemy.
  2. Add information technology to all_sprites and enemies.

You already take lawmaking that handles random events. The outcome loop is designed to look for random events occurring every frame and deal with them appropriately. Luckily, pygame doesn't restrict y'all to using only the outcome types it has divers. You tin define your own events to handle as yous see fit.

Allow's run across how to create a custom consequence that'southward generated every few seconds. You can create a custom issue by naming it:

                                            78                # Create the screen object                79                # The size is adamant by the abiding SCREEN_WIDTH and SCREEN_HEIGHT                lxxx                screen                =                pygame                .                display                .                set_mode                ((                SCREEN_WIDTH                ,                SCREEN_HEIGHT                ))                81                82                                  # Create a custom consequence for adding a new enemy                                83                                  ADDENEMY                  =                  pygame                  .                  USEREVENT                  +                  one                                84                                  pygame                  .                  time                  .                  set_timer                  (                  ADDENEMY                  ,                  250                  )                                85                86                # Instantiate actor. Correct now, this is just a rectangle.                87                player                =                Role player                ()                          

pygame defines events internally equally integers, so y'all need to ascertain a new consequence with a unique integer. The last event pygame reserves is called USEREVENT, so defining ADDENEMY = pygame.USEREVENT + 1 on line 83 ensures it's unique.

Side by side, you need to insert this new event into the result queue at regular intervals throughout the game. That's where the time module comes in. Line 84 fires the new ADDENEMY event every 250 milliseconds, or 4 times per second. You call .set_timer() outside the game loop since you merely need i timer, but information technology volition fire throughout the entire game.

Add the lawmaking to handle your new consequence:

                                            100                # Main loop                101                while                running                :                102                # Wait at every upshot in the queue                103                for                issue                in                pygame                .                event                .                get                ():                104                # Did the user hitting a central?                105                if                event                .                type                ==                KEYDOWN                :                106                # Was it the Escape key? If so, finish the loop.                107                if                outcome                .                key                ==                K_ESCAPE                :                108                running                =                False                109                110                # Did the user click the window shut button? If so, stop the loop.                111                elif                issue                .                type                ==                QUIT                :                112                running                =                Fake                113                114                                  # Add a new enemy?                                115                                  elif                  outcome                  .                  type                  ==                  ADDENEMY                  :                                116                                  # Create the new enemy and add it to sprite groups                                117                                  new_enemy                  =                  Enemy                  ()                                118                                  enemies                  .                  add                  (                  new_enemy                  )                                119                                  all_sprites                  .                  add                  (                  new_enemy                  )                                120                121                # Get the fix of keys pressed and check for user input                122                pressed_keys                =                pygame                .                central                .                get_pressed                ()                123                player                .                update                (                pressed_keys                )                124                125                                  # Update enemy position                                126                                  enemies                  .                  update                  ()                                          

Whenever the issue handler sees the new ADDENEMY upshot on line 115, it creates an Enemy and adds information technology to enemies and all_sprites. Since Enemy is in all_sprites, it will get drawn every frame. You also need to call enemies.update() on line 126, which updates everything in enemies, to ensure they move properly:

Enemies flying by in pygame

Withal, that's not the only reason there'south a grouping for simply enemies.

Collision Detection

Your game design calls for the game to end whenever an enemy collides with the player. Checking for collisions is a bones technique of game programming, and usually requires some not-trivial math to make up one's mind whether two sprites will overlap each other.

This is where a framework similar pygame comes in handy! Writing collision detection lawmaking is tedious, but pygame has a LOT of collision detection methods available for you to employ.

For this tutorial, you lot'll use a method called .spritecollideany(), which is read every bit "sprite collide whatever." This method accepts a Sprite and a Group as parameters. It looks at every object in the Group and checks if its .rect intersects with the .rect of the Sprite. If so, then it returns True. Otherwise, information technology returns False. This is perfect for this game since yous need to check if the single thespian collides with i of a Group of enemies.

Here'due south what that looks like in lawmaking:

                                            130                # Describe all sprites                131                for                entity                in                all_sprites                :                132                screen                .                blit                (                entity                .                surf                ,                entity                .                rect                )                133                134                                  # Bank check if whatever enemies have collided with the player                                135                                  if                  pygame                  .                  sprite                  .                  spritecollideany                  (                  role player                  ,                  enemies                  ):                                136                                  # If and so, so remove the player and end the loop                                137                                  player                  .                  kill                  ()                                138                                  running                  =                  False                                          

Line 135 tests whether player has collided with whatever of the objects in enemies. If so, and then player.kill() is chosen to remove information technology from every grouping to which information technology belongs. Since the just objects existence rendered are in all_sprites, the player volition no longer be rendered. In one case the player has been killed, you need to exit the game as well, so you set up running = False to break out of the game loop on line 138.

At this point, you lot've got the basic elements of a game in place:

Pygame window

Now, permit's apparel it upwardly a bit, make information technology more than playable, and add some advanced capabilities to help it stand up out.

Sprite Images

Alright, you have a game, simply let's exist honest… It's kind of ugly. The player and enemies are just white blocks on a black background. That was land-of-the-art when Pong was new, but it just doesn't cut information technology anymore. Let's supersede all those boring white rectangles with some cooler images that volition make the game feel similar an actual game.

Earlier, you learned that images on disk tin can be loaded into a Surface with some assistance from the epitome module. For this tutorial, we made a lilliputian jet for the role player and some missiles for the enemies. Yous're welcome to utilize this art, describe your own, or download some free game fine art avails to use. Y'all tin can click the link below to download the art used in this tutorial:

Altering the Object Constructors

Before you utilise images to stand for the thespian and enemy sprites, you need to make some changes to their constructors. The lawmaking beneath replaces the code used previously:

                                                                      7                  # Import pygame.locals for easier access to key coordinates                                      viii                  # Updated to conform to flake8 and black standards                                      9                  # from pygame.locals import *                  10                  from                  pygame.locals                  import                  (                  eleven                                      RLEACCEL                    ,                                    12                  K_UP                  ,                  13                  K_DOWN                  ,                  xiv                  K_LEFT                  ,                  fifteen                  K_RIGHT                  ,                  16                  K_ESCAPE                  ,                  17                  KEYDOWN                  ,                  xviii                  QUIT                  ,                  xix                  )                  20                  21                  # Define constants for the screen width and height                  22                  SCREEN_WIDTH                  =                  800                  23                  SCREEN_HEIGHT                  =                  600                  24                  25                  26                  # Ascertain the Player object past extending pygame.sprite.Sprite                  27                  # Instead of a surface, apply an image for a better-looking sprite                  28                  class                  Player                  (                  pygame                  .                  sprite                  .                  Sprite                  ):                  29                  def                  __init__                  (                  self                  ):                  30                  super                  (                  Player                  ,                  self                  )                  .                  __init__                  ()                  31                                      self                    .                    surf                    =                    pygame                    .                    image                    .                    load                    (                    "jet.png"                    )                    .                    convert                    ()                                    32                                      self                    .                    surf                    .                    set_colorkey                    ((                    255                    ,                    255                    ,                    255                    ),                    RLEACCEL                    )                                    33                  self                  .                  rect                  =                  self                  .                  surf                  .                  get_rect                  ()                              

Let's unpack line 31 a bit. pygame.image.load() loads an paradigm from the deejay. You lot pass it a path to the file. It returns a Surface, and the .convert() call optimizes the Surface, making future .blit() calls faster.

Line 32 uses .set_colorkey() to indicate the color pygame will render every bit transparent. In this case, y'all choose white, because that's the background color of the jet paradigm. The RLEACCEL constant is an optional parameter that helps pygame render more than quickly on non-accelerated displays. This is added to the pygame.locals import argument on line 11.

Nothing else needs to change. The paradigm is even so a Surface, except at present it has a movie painted on it. You still use information technology in the same mode.

Here's what similar changes to the Enemy look like:

                                                  59                  # Define the enemy object by extending pygame.sprite.Sprite                  threescore                  # Instead of a surface, use an image for a better-looking sprite                  61                  class                  Enemy                  (                  pygame                  .                  sprite                  .                  Sprite                  ):                  62                  def                  __init__                  (                  self                  ):                  63                  super                  (                  Enemy                  ,                  self                  )                  .                  __init__                  ()                  64                                      self                    .                    surf                    =                    pygame                    .                    prototype                    .                    load                    (                    "missile.png"                    )                    .                    convert                    ()                                    65                                      self                    .                    surf                    .                    set_colorkey                    ((                    255                    ,                    255                    ,                    255                    ),                    RLEACCEL                    )                                    66                  # The starting position is randomly generated, every bit is the speed                  67                  cocky                  .                  rect                  =                  self                  .                  surf                  .                  get_rect                  (                  68                  center                  =                  (                  69                  random                  .                  randint                  (                  SCREEN_WIDTH                  +                  20                  ,                  SCREEN_WIDTH                  +                  100                  ),                  lxx                  random                  .                  randint                  (                  0                  ,                  SCREEN_HEIGHT                  ),                  71                  )                  72                  )                  73                  self                  .                  speed                  =                  random                  .                  randint                  (                  5                  ,                  20                  )                              

Running the program now should show that this is the aforementioned game yous had before, except at present y'all've added some overnice graphics skins with images. But why stop at just making the role player and enemy sprites look nice? Let'due south add a few clouds going past to give the impression of a jet flying through the sky.

Calculation Groundwork Images

For background clouds, yous utilize the aforementioned principles as you did for Player and Enemy:

  1. Create the Cloud class.
  2. Add an image of a cloud to it.
  3. Create a method .update() that moves the cloud toward the left side of the screen.
  4. Create a custom event and handler to create new deject objects at a set time interval.
  5. Add the newly created cloud objects to a new Group called clouds.
  6. Update and depict the clouds in your game loop.

Here's what Cloud looks like:

                                                                      83                  # Define the cloud object by extending pygame.sprite.Sprite                                      84                  # Use an image for a ameliorate-looking sprite                                      85                  form                  Cloud                  (                  pygame                  .                  sprite                  .                  Sprite                  ):                                      86                  def                  __init__                  (                  cocky                  ):                                      87                  super                  (                  Deject                  ,                  self                  )                  .                  __init__                  ()                                      88                  cocky                  .                  surf                  =                  pygame                  .                  epitome                  .                  load                  (                  "cloud.png"                  )                  .                  convert                  ()                                      89                  cocky                  .                  surf                  .                  set_colorkey                  ((                  0                  ,                  0                  ,                  0                  ),                  RLEACCEL                  )                                      90                  # The starting position is randomly generated                                      91                  self                  .                  rect                  =                  self                  .                  surf                  .                  get_rect                  (                                      92                  center                  =                  (                                      93                  random                  .                  randint                  (                  SCREEN_WIDTH                  +                  20                  ,                  SCREEN_WIDTH                  +                  100                  ),                                      94                  random                  .                  randint                  (                  0                  ,                  SCREEN_HEIGHT                  ),                                      95                  )                                      96                  )                                      97                                      98                  # Movement the cloud based on a constant speed                                      99                  # Remove the cloud when information technology passes the left edge of the screen                  100                  def                  update                  (                  self                  ):                  101                  self                  .                  rect                  .                  move_ip                  (                  -                  5                  ,                  0                  )                  102                  if                  cocky                  .                  rect                  .                  right                  <                  0                  :                  103                  self                  .                  kill                  ()                              

That should all look very familiar. It'due south pretty much the same as Enemy.

To take clouds announced at sure intervals, you'll employ event creation code similar to what you used to create new enemies. Put it right beneath the enemy creation outcome:

                                                  116                  # Create custom events for adding a new enemy and a cloud                  117                  ADDENEMY                  =                  pygame                  .                  USEREVENT                  +                  1                  118                  pygame                  .                  time                  .                  set_timer                  (                  ADDENEMY                  ,                  250                  )                  119                                      ADDCLOUD                    =                    pygame                    .                    USEREVENT                    +                    2                                    120                                      pygame                    .                    time                    .                    set_timer                    (                    ADDCLOUD                    ,                    1000                    )                                                

This says to wait 1000 milliseconds, or one second, before creating the next cloud.

Next, create a new Group to concur each newly created cloud:

                                                  125                  # Create groups to agree enemy sprites, cloud sprites, and all sprites                  126                  # - enemies is used for collision detection and position updates                  127                  # - clouds is used for position updates                  128                  # - all_sprites is used for rendering                  129                  enemies                  =                  pygame                  .                  sprite                  .                  Group                  ()                  130                                      clouds                    =                    pygame                    .                    sprite                    .                    Grouping                    ()                                    131                  all_sprites                  =                  pygame                  .                  sprite                  .                  Group                  ()                  132                  all_sprites                  .                  add                  (                  actor                  )                              

Next, add together a handler for the new ADDCLOUD effect in the upshot handler:

                                                  137                  # Primary loop                  138                  while                  running                  :                  139                  # Look at every consequence in the queue                  140                  for                  effect                  in                  pygame                  .                  event                  .                  get                  ():                  141                  # Did the user hitting a central?                  142                  if                  event                  .                  type                  ==                  KEYDOWN                  :                  143                  # Was information technology the Escape fundamental? If so, then stop the loop.                  144                  if                  event                  .                  key                  ==                  K_ESCAPE                  :                  145                  running                  =                  Simulated                  146                  147                  # Did the user click the window close push button? If so, stop the loop.                  148                  elif                  event                  .                  type                  ==                  QUIT                  :                  149                  running                  =                  Imitation                  150                  151                  # Add a new enemy?                  152                  elif                  event                  .                  type                  ==                  ADDENEMY                  :                  153                  # Create the new enemy and add it to sprite groups                  154                  new_enemy                  =                  Enemy                  ()                  155                  enemies                  .                  add                  (                  new_enemy                  )                  156                  all_sprites                  .                  add together                  (                  new_enemy                  )                  157                  158                                      # Add a new deject?                                    159                                      elif                    event                    .                    type                    ==                    ADDCLOUD                    :                                    160                                      # Create the new cloud and add together it to sprite groups                                    161                                      new_cloud                    =                    Cloud                    ()                                    162                                      clouds                    .                    add                    (                    new_cloud                    )                                    163                                      all_sprites                    .                    add                    (                    new_cloud                    )                                                

Finally, make sure the clouds are updated every frame:

                                                  167                  # Update the position of enemies and clouds                  168                  enemies                  .                  update                  ()                  169                                      clouds                    .                    update                    ()                                    170                  171                  # Fill the screen with heaven blue                  172                                      screen                    .                    fill up                    ((                    135                    ,                    206                    ,                    250                    ))                                                

Line 172 updates the original screen.fill() to fill the screen with a pleasant heaven blue color. You can change this color to something else. Maybe you want an alien world with a purple sky, a toxic wasteland in neon light-green, or the surface of Mars in red!

Annotation that each new Deject and Enemy are added to all_sprites too as clouds and enemies. This is washed because each grouping is used for a split purpose:

  • Rendering is washed using all_sprites.
  • Position updates are washed using clouds and enemies.
  • Collision detection is done using enemies.

You create multiple groups and then that y'all can change the way sprites move or behave without impacting the motion or behavior of other sprites.

Game Speed

While testing the game y'all may have noticed that the enemies movement a little fast. If not, then that's okay, equally unlike machines will run into different results at this point.

The reason for this is that the game loop processes frames every bit fast every bit the processor and environment will allow. Since all the sprites move once per frame, they can motility hundreds of times each second. The number of frames handled each second is called the frame rate, and getting this right is the divergence between a playable game and a forgettable one.

Normally, you want as high a frame rate as possible, but for this game, y'all need to slow information technology downwards a bit for the game to be playable. Fortunately, the module time contains a Clock which is designed exactly for this purpose.

Using Clock to establish a playable frame rate requires simply ii lines of code. The starting time creates a new Clock before the game loop begins:

                                            106                # Setup the clock for a decent framerate                107                clock                =                pygame                .                time                .                Clock                ()                          

The second calls .tick() to inform pygame that the plan has reached the end of the frame:

                                            188                # Flip everything to the display                189                pygame                .                display                .                flip                ()                190                191                                  # Ensure program maintains a charge per unit of thirty frames per 2nd                                192                                  clock                  .                  tick                  (                  30                  )                                          

The argument passed to .tick() establishes the desired frame rate. To do this, .tick() calculates the number of milliseconds each frame should take, based on the desired frame rate. And so, it compares that number to the number of milliseconds that have passed since the terminal time .tick() was chosen. If not plenty time has passed, and so .tick() delays processing to ensure that it never exceeds the specified frame charge per unit.

Passing in a smaller frame rate will issue in more fourth dimension in each frame for calculations, while a larger frame rate provides smoother (and possibly faster) gameplay:

Setting the frame rate in pygame

Play effectually with this number to meet what feels best for y'all!

Audio Effects

So far, you've focused on gameplay and the visual aspects of your game. Now let'southward explore giving your game some auditory season also. pygame provides mixer to handle all sound-related activities. You'll use this module's classes and methods to provide groundwork music and sound effects for various actions.

The name mixer refers to the fact that the module mixes various sounds into a cohesive whole. Using the music sub-module, you can stream private sound files in a diversity of formats, such every bit MP3, Ogg, and Modern. You can likewise employ Sound to hold a single audio effect to exist played, in either Ogg or uncompressed WAV formats. All playback happens in the background, so when you lot play a Sound, the method returns immediately as the audio plays.

As with most things pygame, using mixer starts with an initialization step. Luckily, this is already handled by pygame.init(). You only need to call pygame.mixer.init() if you want to change the defaults:

                                            106                                  # Setup for sounds. Defaults are adept.                                107                                  pygame                  .                  mixer                  .                  init                  ()                                108                109                # Initialize pygame                110                pygame                .                init                ()                111                112                # Set up the clock for a decent framerate                113                clock                =                pygame                .                time                .                Clock                ()                          

pygame.mixer.init() accepts a number of arguments, but the defaults piece of work fine in virtually cases. Note that if y'all desire to change the defaults, you lot need to telephone call pygame.mixer.init() before calling pygame.init(). Otherwise, the defaults volition be in effect regardless of your changes.

Afterwards the system is initialized, you can get your sounds and background music setup:

                                            135                # Load and play background music                136                # Audio source: http://ccmixter.org/files/Apoxode/59262                137                # License: https://creativecommons.org/licenses/past/3.0/                138                pygame                .                mixer                .                music                .                load                (                "Apoxode_-_Electric_1.mp3"                )                139                pygame                .                mixer                .                music                .                play                (                loops                =-                1                )                140                141                # Load all audio files                142                # Sound sources: Jon Fincher                143                move_up_sound                =                pygame                .                mixer                .                Sound                (                "Rising_putter.ogg"                )                144                move_down_sound                =                pygame                .                mixer                .                Audio                (                "Falling_putter.ogg"                )                145                collision_sound                =                pygame                .                mixer                .                Sound                (                "Collision.ogg"                )                          

Lines 138 and 139 load a groundwork sound clip and begin playing it. Yous can tell the sound clip to loop and never end past setting the named parameter loops=-1.

Lines 143 to 145 load three sounds you lot'll use for diverse sound effects. The first ii are rising and falling sounds, which are played when the thespian moves up or down. The final is the sound used whenever there is a collision. You can add other sounds as well, such every bit a audio for whenever an Enemy is created, or a final sound for when the game ends.

So, how do y'all employ the audio furnishings? Yous desire to play each sound when a certain effect occurs. For instance, when the ship moves upward, you desire to play move_up_sound. Therefore, you add together a call to .play() whenever you handle that event. In the pattern, that ways adding the following calls to .update() for Player:

                                            26                # Ascertain the Histrion object by extending pygame.sprite.Sprite                27                # Instead of a surface, apply an epitome for a improve-looking sprite                28                course                Player                (                pygame                .                sprite                .                Sprite                ):                29                def                __init__                (                self                ):                xxx                super                (                Actor                ,                self                )                .                __init__                ()                31                self                .                surf                =                pygame                .                image                .                load                (                "jet.png"                )                .                convert                ()                32                cocky                .                surf                .                set_colorkey                ((                255                ,                255                ,                255                ),                RLEACCEL                )                33                self                .                rect                =                self                .                surf                .                get_rect                ()                34                35                # Move the sprite based on keypresses                36                def                update                (                self                ,                pressed_keys                ):                37                if                pressed_keys                [                K_UP                ]:                38                cocky                .                rect                .                move_ip                (                0                ,                -                5                )                39                                  move_up_sound                  .                  play                  ()                                40                if                pressed_keys                [                K_DOWN                ]:                41                self                .                rect                .                move_ip                (                0                ,                5                )                42                                  move_down_sound                  .                  play                  ()                                          

For a collision between the player and an enemy, you play the sound for when collisions are detected:

                                            201                # Bank check if any enemies accept collided with the player                202                if                pygame                .                sprite                .                spritecollideany                (                actor                ,                enemies                ):                203                # If so, so remove the player                204                histrion                .                impale                ()                205                206                # Stop any moving sounds and play the collision sound                207                                  move_up_sound                  .                  stop                  ()                                208                                  move_down_sound                  .                  terminate                  ()                                209                                  collision_sound                  .                  play                  ()                                210                211                # Finish the loop                212                running                =                False                          

Here, y'all terminate whatsoever other sound effects start, considering in a standoff the actor is no longer moving. And so you play the standoff sound and continue execution from there.

Finally, when the game is over, all sounds should cease. This is truthful whether the game ends due to a collision or the user exits manually. To practise this, add the following lines at the stop of the plan later on the loop:

                                            220                # All washed! Terminate and quit the mixer.                221                pygame                .                mixer                .                music                .                cease                ()                222                pygame                .                mixer                .                quit                ()                          

Technically, these last few lines are not required, equally the program ends correct later on this. However, if you decide afterwards on to add an intro screen or an leave screen to your game, and then in that location may be more code running later on the game ends.

That's it! Exam it once more, and you should come across something like this:

Pygame window

A Note on Sources

You may have noticed the annotate on lines 136-137 when the background music was loaded, listing the source of the music and a link to the Creative Commons license. This was done because the creator of that sound required it. The license requirements stated that in order to utilize the sound, both proper attribution and a link to the license must be provided.

Here are some sources for music, sound, and fine art that you lot can search for useful content:

  • OpenGameArt.org: sounds, sound effects, sprites, and other artwork
  • Kenney.nl: sounds, sound effects, sprites, and other artwork
  • Gamer Art 2nd: sprites and other artwork
  • CC Mixter: sounds and sound effects
  • Freesound: sounds and sound effects

Equally y'all make your games and employ downloaded content such as art, music, or lawmaking from other sources, delight be certain that you are complying with the licensing terms of those sources.

Conclusion

Throughout this tutorial, yous've learned how game programming with pygame differs from standard procedural programming. You've also learned how to:

  • Implement event loops
  • Draw items on the screen
  • Play sound furnishings and music
  • Handle user input

To practice this, yous used a subset of the pygame modules, including the brandish, mixer and music, time, image, result, and key modules. Y'all besides used several pygame classes, including Rect, Surface, Sound, and Sprite. Simply these but scratch the surface of what pygame can practise! Check out the official pygame documentation for a total list of bachelor modules and classes.

Yous can detect all of the code, graphics, and sound files for this article by clicking the link beneath:

Feel free to exit comments below every bit well. Happy Pythoning!

Scout Now This tutorial has a related video grade created by the Real Python team. Watch it together with the written tutorial to deepen your understanding: Brand a second Side-Scroller Game With PyGame