Elif Eventkey Pygameky Start Program Again
Sentry 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 2d Side-Scroller Game With PyGame
When I started learning reckoner programming late in the terminal millennium, it was driven by my desire to write computer games. I tried to figure out how to write games in every language and on every platform I learned, including Python. That'south how I discovered pygame and learned how to apply it to write games and other graphical programs. At the time, I really wanted a primer on pygame.
By the finish of this article, y'all'll be able to:
- Depict items on your screen
- Play sound furnishings and music
- Handle user input
- Implement event loops
- Describe how game programming differs from standard procedural Python programming
This primer assumes you have a basic understanding of writing Python programs, including user-defined functions, imports, loops, and conditionals. Y'all should also exist familiar with how to open files on your platform. A basic understanding of object-oriented Python is helpful every bit well. pygame works with most versions of Python, merely Python three.6 is recommended and used throughout this article.
You can get all of the lawmaking in this article to follow forth:
Background and Setup
pygame is a Python wrapper for the SDL library, which stands for Uncomplicated DirectMedia Layer. SDL provides cross-platform access to your organisation'southward underlying multimedia hardware components, such as sound, video, mouse, keyboard, and joystick. pygame started life equally a replacement for the stalled PySDL project. The cross-platform nature of both SDL and pygame means you can write games and rich multimedia Python programs for every platform that supports them!
To install pygame on your platform, use the appropriate pip command:
You can verify the install by loading one of the examples that comes with the library:
$ python3 -thou pygame.examples.aliens If a game window appears, then pygame is installed properly! If yous see problems, then the Getting Started guide outlines some known issues and caveats for all platforms.
Basic PyGame Program
Before getting downwards to specifics, permit's take a look at a basic pygame program. This plan creates a window, fills the background with white, and draws a bluish circle in the middle of it:
1 # Simple pygame program 2 3 # Import and initialize the pygame library 4 import pygame five pygame . init () six 7 # Set upward the drawing window 8 screen = pygame . display . set_mode ([ 500 , 500 ]) 9 10 # Run until the user asks to quit xi running = True 12 while running : thirteen 14 # Did the user click the window close button? 15 for outcome in pygame . event . get (): xvi if consequence . type == pygame . QUIT : 17 running = False 18 xix # Fill the groundwork with white 20 screen . fill (( 255 , 255 , 255 )) 21 22 # Draw a solid blue circumvolve in the centre 23 pygame . draw . circle ( screen , ( 0 , 0 , 255 ), ( 250 , 250 ), 75 ) 24 25 # Flip the display 26 pygame . display . flip () 27 28 # Done! Time to quit. 29 pygame . quit () When y'all run this program, you'll see a window that looks like this:
Let's pause this code down, section past department:
-
Lines four and 5 import and initialize the
pygamelibrary. Without these lines, in that location is nopygame. -
Line 8 sets up your program's display window. You lot provide either a listing or a tuple that specifies the width and peak of the window to create. This program uses a list to create a foursquare window with 500 pixels on each side.
-
Lines xi and 12 set a game loop to control when the programme ends. Y'all'll cover game loops subsequently on in this tutorial.
-
Lines 15 to 17 scan and handle events within the game loop. You'll become to events a flake after also. In this case, the only consequence handled is
pygame.QUIT, which occurs when the user clicks the window shut 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 color. 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 draw -
(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 circumvolve to draw in pixels
-
-
Line 26 updates the contents of the display to the screen. Without this call, nothing appears in the window!
-
Line 29 exits
pygame. This simply happens once the loop finishes.
That's the pygame version of "Howdy, World." Now let's dig a little deeper into the concepts behind this lawmaking.
PyGame Concepts
As pygame and the SDL library are portable across different platforms and devices, they both need to ascertain and work with abstractions for various hardware realities. Understanding those concepts and abstractions volition help you lot pattern and develop your ain games.
Initialization and Modules
The pygame library is composed of a number of Python constructs, which include several dissimilar modules. These modules provide abstract access to specific hardware on your organisation, every bit well as compatible methods to work with that hardware. For instance, brandish allows uniform access to your video display, while joystick allows abstract control of your joystick.
After importing the pygame library in the instance to a higher place, the first matter you did was initialize PyGame using pygame.init(). This function calls the separate init() functions of all the included pygame modules. Since these modules are abstractions for specific hardware, this initialization stride is required and so that you tin piece of work with the same lawmaking on Linux, Windows, and Mac.
Displays and Surfaces
In addition to the modules, pygame too includes several Python classes, which encapsulate non-hardware dependent concepts. Ane of these is the Surface which, at its most basic, defines a rectangular area on which you tin draw. Surface objects are used in many contexts in pygame. Later you'll see how to load an image into a Surface and display it on the screen.
In pygame, everything is viewed on a single user-created display, which tin can exist a window or a total screen. The display is created using .set_mode(), which returns a Surface representing the visible part of the window. It is this Surface that you lot 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 directly onto the display'south Surface, but you can likewise 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 to a higher place, Surface objects are represented by rectangles, every bit are many other objects in pygame, such equally images and windows. Rectangles are so heavily used that there is a special Rect class just to handle them. You lot'll exist using Rect objects and images in your game to draw players and enemies, and to manage collisions between them.
Okay, that's enough theory. Permit'southward design and write a game!
Bones Game Design
Earlier you start writing whatever code, it's always a good idea to have some design in place. Since this is a tutorial game, let's design some bones gameplay for it as well:
- The goal of the game is to avoid incoming obstacles:
- The actor starts on the left side of the screen.
- The obstacles enter randomly from the correct and move left in a directly line.
- The player can motility left, right, up, or down to avoid the obstacles.
- The player cannot move off the screen.
- The game ends either when the histrion is striking by an obstacle or when the user closes the window.
When he was describing software projects, a former colleague of mine used to say, "You don't know what you do until you know what you 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 player assail capabilities
- No advancing levels
- No boss characters
You're costless to try your manus at adding these and other features to your own plan.
Allow'southward get started!
Importing and Initializing PyGame
Subsequently you lot import pygame, you'll also need to initialize it. This allows pygame to connect its abstractions to your specific hardware:
1 # Import the pygame module two import pygame three 4 # Import pygame.locals for easier access to key coordinates five # Updated to conform to flake8 and black standards 6 from pygame.locals import ( vii K_UP , viii K_DOWN , 9 K_LEFT , x K_RIGHT , 11 K_ESCAPE , 12 KEYDOWN , xiii QUIT , 14 ) 15 sixteen # Initialize pygame 17 pygame . init () The pygame library defines many things as well modules and classes. It also defines some local constants for things similar keystrokes, mouse movements, and display attributes. You reference these constants using the syntax pygame.<Abiding>. By importing specific constants from pygame.locals, you lot can utilise the syntax <Abiding> instead. This volition save you some keystrokes and improve overall readability.
Setting Up the Brandish
Now you demand something to draw on! Create a screen to be the overall canvas:
1 # Import the pygame module two import pygame 3 4 # Import pygame.locals for easier access to central coordinates five # Updated to conform to flake8 and black standards vi from pygame.locals import ( seven K_UP , eight K_DOWN , nine K_LEFT , x K_RIGHT , eleven K_ESCAPE , 12 KEYDOWN , xiii QUIT , xiv ) 15 16 # Initialize pygame 17 pygame . init () 18 nineteen # Ascertain constants for the screen width and tiptop 20 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 )) Y'all create the screen to apply past calling pygame.display.set_mode() and passing a tuple or listing with the desired width and tiptop. In this case, the window is 800x600, as defined by 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 can command, while the OS controls the window borders and title bar.
If yous run this programme now, and then you'll meet a window pop up briefly and and then immediately disappear as the program exits. Don't blink or you might miss it! In the next department, you'll focus on the main game loop to ensure that your program exits but when given the correct input.
Setting Upward 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:
- Processes user input
- Updates the state of all game objects
- Updates the display and audio output
- Maintains the speed of the game
Every wheel of the game loop is called a frame, and the quicker y'all can do things each cycle, the faster your game will run. Frames continue to occur until some condition to exit the game is met. In your blueprint, there are 2 conditions that can end the game loop:
- The player collides with an obstacle. (You'll cover collision detection later on.)
- The player closes the window.
The beginning thing the game loop does is process user input to allow the thespian to motility around the screen. Therefore, y'all need some fashion to capture and process a variety of input. Y'all practice this using the pygame event organisation.
Processing Events
Key presses, mouse movements, and fifty-fifty joystick movements are some of the ways in which a user can provide input. All user input results in an event being generated. Events can happen at any time and often (only not ever) originate outside the plan. All events in pygame are placed in the result queue, which can then be accessed and manipulated. Dealing with events is referred to as handling them, and the code to exercise then is chosen an event handler.
Every event in pygame has an event blazon associated with it. For your game, the result types you'll focus on are keypresses and window closure. Keypress events have the outcome type KEYDOWN, and the window closure event has the type QUIT. Different event types may too have other data associated with them. For case, the KEYDOWN event type besides has a variable called key to indicate which fundamental was pressed.
You access the list of all agile events in the queue by calling pygame.event.get(). Yous then loop through this listing, inspect each event type, and respond appropriately:
27 # Variable to keep the master loop running 28 running = True 29 30 # Principal loop 31 while running : 32 # Look at every event in the queue 33 for consequence in pygame . event . become (): 34 # Did the user hit a key? 35 if consequence . type == KEYDOWN : 36 # Was it the Escape key? If so, stop the loop. 37 if event . primal == K_ESCAPE : 38 running = False 39 twoscore # Did the user click the window close push? If so, stop the loop. 41 elif event . type == QUIT : 42 running = Faux Permit'due south take a closer look at this game loop:
-
Line 28 sets upwards a control variable for the game loop. To exit the loop and the game, you set
running = Fake. The game loop starts on line 29. -
Line 31 starts the event handler, walking through every issue currently in the outcome queue. If there are no events, then the list is empty, and the handler won't do anything.
-
Lines 35 to 38 check if the current
consequence.typeis aKEYDOWNevent. If it is, then the program checks which key was pressed by looking at theevent.keyattribute. If the primal is the Esc primal, indicated byK_ESCAPE, and so it exits the game loop by settingrunning = Simulated. -
Lines 41 and 42 do a similar check for the consequence blazon called
QUIT. This event but occurs when the user clicks the window close button. The user may also use any other operating arrangement action to close the window.
When you add these lines to the previous code and run it, yous'll see a window with a blank or black screen:
The window won't disappear until yous printing the Esc cardinal, or otherwise trigger a QUIT result by closing the window.
Drawing on the Screen
In the sample programme, y'all drew on the screen using ii commands:
-
screen.make full()to fill the groundwork -
pygame.draw.circle()to draw a circumvolve
Now y'all'll learn about a third way to draw to the screen: using a Surface.
Recall that a Surface is a rectangular object on which you can describe, like a blank canvas of newspaper. The screen object is a Surface, and you can create your own Surface objects split up from the brandish screen. Allow's run into how that works:
44 # Fill the screen with white 45 screen . fill (( 255 , 255 , 255 )) 46 47 # Create a surface and pass in a tuple containing its length and width 48 surf = pygame . Surface (( fifty , fifty )) 49 50 # Give the surface a color to separate it from the background 51 surf . fill (( 0 , 0 , 0 )) 52 rect = surf . get_rect () After the screen is filled with white on line 45, a new Surface is created on line 48. This Surface is 50 pixels broad, 50 pixels tall, and assigned to surf. At this signal, you treat it just similar the screen. So on line, 51 y'all fill up it with black. Y'all can as well access its underlying Rect using .get_rect(). This is stored as rect for later on utilise.
Using .blit() and .flip()
Simply creating a new Surface isn't plenty to meet it on the screen. To do that, y'all need 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. Y'all tin can only .blit() from one Surface to another, simply since the screen is simply another Surface, that'due south non a problem. Here's how yous draw surf on the screen:
54 # This line says "Draw surf onto the screen at the center" 55 screen . blit ( surf , ( SCREEN_WIDTH / 2 , SCREEN_HEIGHT / 2 )) 56 pygame . display . flip () The .blit() call on line 55 takes two arguments:
- The
Surfaceto draw - The location at which to depict it on the source
Surface
The coordinates (SCREEN_WIDTH/2, SCREEN_HEIGHT/2) tell your program to place surf in the exact center of the screen, only it doesn't quite expect that way:
The reason why the image looks off-center is that .blit() puts the top-left corner of surf at the location given. If you want surf to be centered, and so you'll accept to do some math to shift it up and to the left. You lot tin do this by subtracting the width and height of surf from the width and top of the screen, dividing each by two to locate the centre, then passing those numbers as 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 60 # Draw surf at the new coordinates 61 screen . blit ( surf , surf_center ) 62 pygame . display . flip () Notice the phone call to pygame.brandish.flip() after the call to blit(). This updates the unabridged screen with everything that'south been drawn since the last flip. Without the call to .flip(), nothing is shown.
Sprites
In your game design, the thespian starts on the left, and obstacles come up in from the right. You tin stand for all the obstacles with Surface objects to make cartoon everything easier, but how do you lot know where to draw them? How do you know if an obstacle has collided with the role player? What happens when the obstacle flies off the screen? What if yous desire to draw background images that besides motion? What if you want your images to be animated? You tin can handle all these situations and more with sprites.
In programming terms, a sprite is a second representation of something on the screen. Substantially, it'south a picture. pygame provides a Sprite grade, which is designed to concur one or several graphical representations of any game object that y'all want to brandish on the screen. To utilise it, yous create a new class that extends Sprite. This allows y'all to employ its built-in methods.
Players
Hither'southward how yous employ Sprite objects with the current game to define the player. Insert this lawmaking after line xviii:
20 # Define a Player object by extending pygame.sprite.Sprite 21 # The surface drawn on the screen is now an aspect of 'player' 22 class Player ( pygame . sprite . Sprite ): 23 def __init__ ( cocky ): 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 lot first ascertain Role player past 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, yous define and initialize .surf to hold the prototype to display, which is currently a white box. Yous also define and initialize .rect, which you'll employ to depict the player afterward. To employ this new form, you need to create a new object and modify the drawing code besides. Aggrandize the lawmaking block below to meet information technology all together:
1 # Import the pygame module 2 import pygame 3 four # Import pygame.locals for easier access to key coordinates five # Updated to conform to flake8 and black standards 6 from pygame.locals import ( vii K_UP , 8 K_DOWN , 9 K_LEFT , 10 K_RIGHT , 11 K_ESCAPE , 12 KEYDOWN , 13 QUIT , 14 ) fifteen 16 # Define constants for the screen width and height 17 SCREEN_WIDTH = 800 18 SCREEN_HEIGHT = 600 nineteen xx # Define a thespian object past extending pygame.sprite.Sprite 21 # The surface drawn on the screen is at present an attribute of 'thespian' 22 class Player ( 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 cocky . rect = self . surf . get_rect () 28 29 # Initialize pygame 30 pygame . init () 31 32 # Create the screen object 33 # The size is determined by the constant SCREEN_WIDTH and SCREEN_HEIGHT 34 screen = pygame . display . set_mode (( SCREEN_WIDTH , SCREEN_HEIGHT )) 35 36 # Instantiate player. Right at present, this is just a rectangle. 37 player = Player () 38 39 # Variable to go along the primary loop running 40 running = True 41 42 # Main loop 43 while running : 44 # for loop through the event queue 45 for effect in pygame . event . get (): 46 # Bank check for KEYDOWN outcome 47 if issue . type == KEYDOWN : 48 # If the Esc central is pressed, so leave the main loop 49 if upshot . primal == K_ESCAPE : 50 running = False 51 # Check for QUIT event. If QUIT, then fix running to false. 52 elif effect . type == QUIT : 53 running = False 54 55 # Fill the screen with black 56 screen . fill (( 0 , 0 , 0 )) 57 58 # Describe the player on the screen 59 screen . blit ( player . surf , ( SCREEN_WIDTH / 2 , SCREEN_HEIGHT / 2 )) lx 61 # Update the display 62 pygame . brandish . flip () Run this code. You'll run into a white rectangle at roughly the middle of the screen:
What do you think would happen if yous changed line 59 to screen.blit(player.surf, role player.rect)? Endeavor it and see:
55 # Fill the screen with blackness 56 screen . make full (( 0 , 0 , 0 )) 57 58 # Draw the player on the screen 59 screen . blit ( player . surf , player . rect ) threescore 61 # Update the display 62 pygame . display . flip () When you pass a Rect to .blit(), information technology uses the coordinates of the top left corner to draw the surface. Y'all'll use this afterwards to make your thespian move!
User Input
So far, you've learned how to ready upward pygame and describe objects on the screen. Now, the existent fun starts! You'll make the player controllable using the keyboard.
Earlier, you saw that pygame.event.get() returns a list of the events in the effect queue, which you lot scan for KEYDOWN consequence types. Well, that's not the merely mode to read keypresses. pygame also provides pygame.consequence.get_pressed(), which returns a dictionary containing all the current KEYDOWN events in the queue.
Put this in your game loop right after the outcome handling loop. This returns a dictionary containing the keys pressed at the beginning of every frame:
54 # Get the set of keys pressed and check for user input 55 pressed_keys = pygame . cardinal . get_pressed () Next, you write a method in Player to accepts that lexicon. This will define the behavior of the sprite based off the keys that are pressed. Hither'south what that might look like:
29 # Move the sprite based on user keypresses xxx 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 cocky . rect . move_ip ( 0 , five ) 35 if pressed_keys [ K_LEFT ]: 36 self . rect . move_ip ( - 5 , 0 ) 37 if pressed_keys [ K_RIGHT ]: 38 self . rect . move_ip ( 5 , 0 ) K_UP, K_DOWN, K_LEFT, and K_RIGHT stand for to the pointer keys on the keyboard. If the dictionary entry for that key is True, and so that primal is down, and you move the thespian .rect in the proper direction. Hither you use .move_ip(), which stands for move in place, to move the current Rect.
Then y'all tin call .update() every frame to move the player sprite in response to keypresses. Add together this call right afterwards the call to .get_pressed():
52 # Main loop 53 while running : 54 # for loop through the event queue 55 for outcome in pygame . event . go (): 56 # Check for KEYDOWN event 57 if event . type == KEYDOWN : 58 # If the Esc central is pressed, so exit the principal loop 59 if outcome . central == K_ESCAPE : lx running = False 61 # Bank check for QUIT event. If QUIT, then fix running to false. 62 elif effect . type == QUIT : 63 running = Imitation 64 65 # Go all the keys currently pressed 66 pressed_keys = pygame . cardinal . get_pressed () 67 68 # Update the role player sprite based on user keypresses 69 actor . update ( pressed_keys ) 70 71 # Fill the screen with black 72 screen . fill up (( 0 , 0 , 0 )) Now you lot tin can move your role player rectangle effectually the screen with the arrow keys:
You may discover two pocket-size problems:
- The player rectangle can motility very fast if a primal is held down. You'll piece of work on that after.
- The thespian rectangle can move off the screen. Let's solve that one at present.
To keep the histrion on the screen, yous need to add together some logic to detect if the rect is going to move off screen. To practise that, you check whether the rect coordinates have moved across the screen's boundary. If and then, and so you instruct the program to move it dorsum to the border:
25 # Move the sprite based on user keypresses 26 def update ( cocky , pressed_keys ): 27 if pressed_keys [ K_UP ]: 28 self . rect . move_ip ( 0 , - v ) 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 ( five , 0 ) 35 36 # Keep histrion on the screen 37 if self . rect . left < 0 : 38 self . rect . left = 0 39 if self . rect . right > SCREEN_WIDTH : 40 self . rect . right = SCREEN_WIDTH 41 if self . rect . top <= 0 : 42 self . rect . top = 0 43 if cocky . rect . lesser >= SCREEN_HEIGHT : 44 self . rect . bottom = SCREEN_HEIGHT Here, instead of using .move(), you just modify the corresponding coordinates of .top, .bottom, .left, or .right straight. Test this, and you'll find the role player rectangle can no longer motion off the screen.
Now let's add together some enemies!
Enemies
What's a game without enemies? You'll employ the techniques yous've already learned to create a bones enemy course, then create a lot of them for your actor to avoid. Commencement, import the random library:
4 # Import random for random numbers 5 import random So create a new sprite class called Enemy, following the same design you used for Player:
55 # Define the enemy object past extending pygame.sprite.Sprite 56 # The surface you draw on the screen is at present an attribute of 'enemy' 57 grade Enemy ( pygame . sprite . Sprite ): 58 def __init__ ( cocky ): 59 super ( Enemy , cocky ) . __init__ () threescore self . surf = pygame . Surface (( xx , 10 )) 61 self . surf . fill (( 255 , 255 , 255 )) 62 self . rect = self . surf . get_rect ( 63 eye = ( 64 random . randint ( SCREEN_WIDTH + 20 , SCREEN_WIDTH + 100 ), 65 random . randint ( 0 , SCREEN_HEIGHT ), 66 ) 67 ) 68 self . speed = random . randint ( five , 20 ) 69 lxx # Move the sprite based on speed 71 # Remove the sprite when it passes the left edge of the screen 72 def update ( self ): 73 self . rect . move_ip ( - self . speed , 0 ) 74 if self . rect . right < 0 : 75 self . kill () There are four notable differences betwixt Enemy and Player:
-
On lines 62 to 67, y'all update
rectto be a random location forth the correct border of the screen. The center of the rectangle is merely off the screen. It's located at some position between twenty and 100 pixels away from the right edge, and somewhere betwixt the meridian and bottom edges. -
On line 68, you define
.speedas a random number between v and twenty. This specifies how fast this enemy moves towards the player. -
On lines 73 to 76, you lot define
.update(). It takes no arguments since enemies move automatically. Instead,.update()moves the enemy toward the left side of the screen at the.speeddefined when information technology was created. -
On line 74, you cheque whether the enemy has moved off-screen. To make sure the
Enemyis fully off the screen and won't merely disappear while it's nevertheless visible, you cheque that the right side of the.recthas gone past the left side of the screen. One time the enemy is off-screen, you call.kill()to forbid it from being processed further.
So, what does .kill() do? To figure this out, you have to know virtually Sprite Groups.
Sprite Groups
Some other super useful class that pygame provides is the Sprite Group. This is an object that holds a grouping of Sprite objects. And then why use information technology? Can't you merely track your Sprite objects in a listing instead? Well, y'all tin can, but the advantage of using a Group lies in the methods it exposes. These methods assistance to notice whether any Enemy has collided with the Thespian, which makes updates much easier.
Allow'southward see how to create sprite groups. You'll create two different Group objects:
- The outset
Groupingwill hold everySpritein the game. - The second
Groupwill hold only theEnemyobjects.
Here's what that looks like in code:
82 # Create the 'player' 83 player = Player () 84 85 # Create groups to concur enemy sprites and all sprites 86 # - enemies is used for standoff detection and position updates 87 # - all_sprites is used for rendering 88 enemies = pygame . sprite . Grouping () 89 all_sprites = pygame . sprite . Group () 90 all_sprites . add together ( player ) 91 92 # Variable to keep the main loop running 93 running = True When you phone call .kill(), the Sprite is removed from every Grouping to which it belongs. This removes the references to the Sprite also, which allows Python's garbage collector to repossess the memory as necessary.
Now that y'all have an all_sprites group, you can modify how objects are fatigued. Instead of calling .blit() on just Histrion, yous tin iterate over everything in all_sprites:
117 # Make full 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 information technology's an enemy or the player.
At that place's only one problem… You don't accept any enemies! You lot could create a bunch of enemies at the get-go of the game, but the game would quickly become tedious when they all left the screen a few seconds subsequently. Instead, allow'south explore how to go along 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 set intervals, you need to practise two things:
- Create a new
Enemy. - Add it to
all_spritesandenemies.
Y'all already have code that handles random events. The issue 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 just the effect types it has divers. You can ascertain your own events to handle every bit yous come across fit.
Let's run across how to create a custom event that's generated every few seconds. You tin can create a custom event by naming it:
78 # Create the screen object 79 # The size is determined by the constant SCREEN_WIDTH and SCREEN_HEIGHT 80 screen = pygame . display . set_mode (( SCREEN_WIDTH , SCREEN_HEIGHT )) 81 82 # Create a custom event for calculation a new enemy 83 ADDENEMY = pygame . USEREVENT + one 84 pygame . time . set_timer ( ADDENEMY , 250 ) 85 86 # Instantiate player. Right now, this is just a rectangle. 87 role player = Thespian () pygame defines events internally equally integers, so you demand to define a new consequence with a unique integer. The last result pygame reserves is chosen USEREVENT, then defining ADDENEMY = pygame.USEREVENT + 1 on line 83 ensures information technology's unique.
Side by side, y'all need to insert this new event into the event queue at regular intervals throughout the game. That's where the fourth dimension module comes in. Line 84 fires the new ADDENEMY effect every 250 milliseconds, or four times per second. You call .set_timer() outside the game loop since you lot only need one timer, but it will burn down throughout the entire game.
Add together the code to handle your new consequence:
100 # Main loop 101 while running : 102 # Look at every issue in the queue 103 for effect in pygame . effect . go (): 104 # Did the user hit a key? 105 if event . type == KEYDOWN : 106 # Was it the Escape key? If so, stop the loop. 107 if event . key == K_ESCAPE : 108 running = False 109 110 # Did the user click the window shut push? If so, stop the loop. 111 elif event . type == QUIT : 112 running = False 113 114 # Add a new enemy? 115 elif event . blazon == 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 set of keys pressed and check for user input 122 pressed_keys = pygame . key . get_pressed () 123 player . update ( pressed_keys ) 124 125 # Update enemy position 126 enemies . update () Whenever the event handler sees the new ADDENEMY upshot on line 115, information technology creates an Enemy and adds it to enemies and all_sprites. Since Enemy is in all_sprites, it will get drawn every frame. You besides need to phone call enemies.update() on line 126, which updates everything in enemies, to ensure they move properly:
However, that's not the only reason there'south a group for just enemies.
Standoff Detection
Your game design calls for the game to end whenever an enemy collides with the player. Checking for collisions is a basic technique of game programming, and usually requires some non-little math to determine whether two sprites volition overlap each other.
This is where a framework similar pygame comes in handy! Writing collision detection code is tedious, merely pygame has a LOT of collision detection methods bachelor for you to utilize.
For this tutorial, you lot'll use a method called .spritecollideany(), which is read as "sprite collide any." This method accepts a Sprite and a Grouping as parameters. It looks at every object in the Group and checks if its .rect intersects with the .rect of the Sprite. If and then, then it returns True. Otherwise, it returns False. This is perfect for this game since you demand to cheque if the single role player collides with one of a Group of enemies.
Here'southward what that looks like in code:
130 # Describe all sprites 131 for entity in all_sprites : 132 screen . blit ( entity . surf , entity . rect ) 133 134 # Check if any enemies have collided with the thespian 135 if pygame . sprite . spritecollideany ( player , enemies ): 136 # If so, and so remove the role player and stop the loop 137 player . kill () 138 running = False Line 135 tests whether player has collided with any of the objects in enemies. If so, then thespian.kill() is chosen to remove it from every group to which it belongs. Since the only objects beingness rendered are in all_sprites, the thespian will no longer be rendered. In one case the player has been killed, y'all demand to exit the game as well, so you gear up running = Fake to break out of the game loop on line 138.
At this point, you've got the bones elements of a game in place:
Now, let'due south dress it up a bit, make it more playable, and add some advanced capabilities to assist information technology stand up out.
Sprite Images
Alright, you have a game, just let'southward exist honest… Information technology's kind of ugly. The player and enemies are but white blocks on a black groundwork. That was state-of-the-art when Pong was new, but it just doesn't cut information technology anymore. Permit's replace all those boring white rectangles with some libation images that will make the game feel like an actual game.
Earlier, you learned that images on disk can exist loaded into a Surface with some help from the image module. For this tutorial, we made a trivial jet for the player and some missiles for the enemies. You're welcome to use this art, draw your ain, or download some free game fine art avails to use. You can click the link beneath to download the art used in this tutorial:
Altering the Object Constructors
Before you lot use images to correspond the player and enemy sprites, you need to make some changes to their constructors. The lawmaking below replaces the code used previously:
7 # Import pygame.locals for easier admission to cardinal coordinates 8 # Updated to adjust to flake8 and black standards 9 # from pygame.locals import * ten from pygame.locals import ( 11 RLEACCEL , 12 K_UP , 13 K_DOWN , 14 K_LEFT , fifteen K_RIGHT , 16 K_ESCAPE , 17 KEYDOWN , eighteen QUIT , 19 ) xx 21 # Define constants for the screen width and elevation 22 SCREEN_WIDTH = 800 23 SCREEN_HEIGHT = 600 24 25 26 # Ascertain the Thespian object by extending pygame.sprite.Sprite 27 # Instead of a surface, use an prototype for a better-looking sprite 28 grade Player ( pygame . sprite . Sprite ): 29 def __init__ ( self ): thirty super ( Player , self ) . __init__ () 31 self . surf = pygame . paradigm . load ( "jet.png" ) . catechumen () 32 self . surf . set_colorkey (( 255 , 255 , 255 ), RLEACCEL ) 33 self . rect = self . surf . get_rect () Permit'due south unpack line 31 a fleck. pygame.paradigm.load() loads an image from the deejay. You lot pass it a path to the file. It returns a Surface, and the .convert() phone call optimizes the Surface, making future .blit() calls faster.
Line 32 uses .set_colorkey() to indicate the color pygame will render as transparent. In this case, you choose white, because that's the background color of the jet image. The RLEACCEL constant is an optional parameter that helps pygame render more speedily on non-accelerated displays. This is added to the pygame.locals import statement on line 11.
Goose egg else needs to change. The paradigm is however a Surface, except at present it has a picture painted on it. You all the same use it in the same way.
Here's what similar changes to the Enemy look like:
59 # Define the enemy object by extending pygame.sprite.Sprite 60 # Instead of a surface, use an epitome for a amend-looking sprite 61 course Enemy ( pygame . sprite . Sprite ): 62 def __init__ ( self ): 63 super ( Enemy , self ) . __init__ () 64 self . surf = pygame . image . load ( "missile.png" ) . convert () 65 self . surf . set_colorkey (( 255 , 255 , 255 ), RLEACCEL ) 66 # The starting position is randomly generated, equally is the speed 67 cocky . rect = cocky . surf . get_rect ( 68 middle = ( 69 random . randint ( SCREEN_WIDTH + 20 , SCREEN_WIDTH + 100 ), seventy random . randint ( 0 , SCREEN_HEIGHT ), 71 ) 72 ) 73 self . speed = random . randint ( five , 20 ) Running the program now should show that this is the same game y'all had before, except now yous've added some nice graphics skins with images. But why end at simply making the player and enemy sprites look nice? Let's add together a few clouds going past to give the impression of a jet flying through the heaven.
Adding Background Images
For groundwork clouds, you utilize the same principles as you lot did for Histrion and Enemy:
- Create the
Cloudclass. - Add an image of a cloud to information technology.
- Create a method
.update()that moves thecloudtoward the left side of the screen. - Create a custom issue and handler to create new
cloudobjects at a fix time interval. - Add together the newly created
dejectobjects to a newGroupingcalledclouds. - Update and draw the
cloudsin your game loop.
Here's what Cloud looks similar:
83 # Define the cloud object by extending pygame.sprite.Sprite 84 # Use an image for a better-looking sprite 85 class Deject ( pygame . sprite . Sprite ): 86 def __init__ ( self ): 87 super ( Deject , self ) . __init__ () 88 self . surf = pygame . image . load ( "deject.png" ) . catechumen () 89 self . surf . set_colorkey (( 0 , 0 , 0 ), RLEACCEL ) ninety # 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 # Move the cloud based on a constant speed 99 # Remove the cloud when it passes the left edge of the screen 100 def update ( self ): 101 self . rect . move_ip ( - 5 , 0 ) 102 if self . rect . correct < 0 : 103 self . kill () That should all look very familiar. It'south pretty much the aforementioned as Enemy.
To have clouds appear at certain intervals, y'all'll use effect cosmos lawmaking similar to what you used to create new enemies. Put it right below the enemy creation event:
116 # Create custom events for adding a new enemy and a cloud 117 ADDENEMY = pygame . USEREVENT + ane 118 pygame . time . set_timer ( ADDENEMY , 250 ) 119 ADDCLOUD = pygame . USEREVENT + ii 120 pygame . time . set_timer ( ADDCLOUD , thou ) This says to look 1000 milliseconds, or 1 2d, before creating the next cloud.
Next, create a new Group to hold 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 . Group () 131 all_sprites = pygame . sprite . Grouping () 132 all_sprites . add ( player ) Next, add together a handler for the new ADDCLOUD result in the consequence handler:
137 # Main loop 138 while running : 139 # Expect at every result in the queue 140 for consequence in pygame . event . get (): 141 # Did the user hitting a key? 142 if event . blazon == KEYDOWN : 143 # Was information technology the Escape central? If and so, then stop the loop. 144 if effect . key == K_ESCAPE : 145 running = False 146 147 # Did the user click the window close button? If so, stop the loop. 148 elif event . type == QUIT : 149 running = False 150 151 # Add a new enemy? 152 elif upshot . blazon == 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 ( new_enemy ) 157 158 # Add a new deject? 159 elif result . type == ADDCLOUD : 160 # Create the new cloud and add together it to sprite groups 161 new_cloud = Deject () 162 clouds . add together ( new_cloud ) 163 all_sprites . add ( new_cloud ) Finally, brand sure the clouds are updated every frame:
167 # Update the position of enemies and clouds 168 enemies . update () 169 clouds . update () 170 171 # Fill up the screen with heaven bluish 172 screen . make full (( 135 , 206 , 250 )) Line 172 updates the original screen.fill() to fill up the screen with a pleasant sky blue colour. You tin can alter this color to something else. Maybe you desire an conflicting world with a majestic sky, a toxic wasteland in neon green, or the surface of Mars in cherry-red!
Note that each new Cloud and Enemy are added to all_sprites as well equally clouds and enemies. This is done because each grouping is used for a separate purpose:
- Rendering is done using
all_sprites. - Position updates are washed using
cloudsandenemies. - Collision detection is done using
enemies.
You lot create multiple groups so that you can alter the manner sprites move or acquit without impacting the motility or behavior of other sprites.
Game Speed
While testing the game y'all may take noticed that the enemies move a trivial fast. If not, and so that's okay, as different machines volition see dissimilar results at this point.
The reason for this is that the game loop processes frames as fast as the processor and surround volition allow. Since all the sprites move one time per frame, they can move hundreds of times each second. The number of frames handled each second is chosen the frame rate, and getting this right is the deviation between a playable game and a forgettable one.
Normally, you want equally high a frame rate as possible, only for this game, you demand to dull it down a bit for the game to exist playable. Fortunately, the module time contains a Clock which is designed exactly for this purpose.
Using Clock to establish a playable frame rate requires just two lines of lawmaking. The first 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 program has reached the end of the frame:
188 # Flip everything to the display 189 pygame . display . flip () 190 191 # Ensure program maintains a rate of xxx frames per second 192 clock . tick ( xxx ) 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. Then, it compares that number to the number of milliseconds that have passed since the last time .tick() was called. If not enough time has passed, then .tick() delays processing to ensure that it never exceeds the specified frame rate.
Passing in a smaller frame charge per unit volition result in more time in each frame for calculations, while a larger frame rate provides smoother (and maybe faster) gameplay:
Play around with this number to run into what feels best for yous!
Sound Furnishings
So far, y'all've focused on gameplay and the visual aspects of your game. Now allow'due south explore giving your game some auditory flavor likewise. pygame provides mixer to handle all sound-related activities. You'll use this module's classes and methods to provide background 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 individual audio files in a variety of formats, such equally MP3, Ogg, and Mod. You can also use Sound to hold a single sound effect to be played, in either Ogg or uncompressed WAV formats. All playback happens in the groundwork, then when you lot play a Sound, the method returns immediately equally 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 lot want to change the defaults:
106 # Setup for sounds. Defaults are expert. 107 pygame . mixer . init () 108 109 # Initialize pygame 110 pygame . init () 111 112 # Set upwards 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 nigh cases. Note that if y'all want to change the defaults, yous need to call pygame.mixer.init() before calling pygame.init(). Otherwise, the defaults will be in consequence regardless of your changes.
Afterward the organization is initialized, you can get your sounds and background music setup:
135 # Load and play background music 136 # Sound 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 sound files 142 # Sound sources: Jon Fincher 143 move_up_sound = pygame . mixer . Sound ( "Rising_putter.ogg" ) 144 move_down_sound = pygame . mixer . Sound ( "Falling_putter.ogg" ) 145 collision_sound = pygame . mixer . Sound ( "Collision.ogg" ) Lines 138 and 139 load a background audio clip and begin playing information technology. You lot can tell the sound prune to loop and never end past setting the named parameter loops=-ane.
Lines 143 to 145 load three sounds y'all'll utilize for various sound effects. The offset two are ascension and falling sounds, which are played when the player moves upward or down. The concluding is the sound used whenever there is a collision. You can add other sounds as well, such equally a sound for whenever an Enemy is created, or a concluding sound for when the game ends.
So, how exercise you use the sound effects? You want to play each audio when a sure consequence occurs. For case, when the send moves up, you want to play move_up_sound. Therefore, you add a call to .play() whenever you lot handle that effect. In the design, that ways adding the following calls to .update() for Player:
26 # Define the Player object by extending pygame.sprite.Sprite 27 # Instead of a surface, use an paradigm for a better-looking sprite 28 course Role player ( pygame . sprite . Sprite ): 29 def __init__ ( self ): 30 super ( Player , self ) . __init__ () 31 cocky . surf = pygame . image . load ( "jet.png" ) . convert () 32 self . surf . set_colorkey (( 255 , 255 , 255 ), RLEACCEL ) 33 cocky . rect = self . surf . get_rect () 34 35 # Move the sprite based on keypresses 36 def update ( cocky , pressed_keys ): 37 if pressed_keys [ K_UP ]: 38 self . rect . move_ip ( 0 , - 5 ) 39 move_up_sound . play () twoscore if pressed_keys [ K_DOWN ]: 41 cocky . rect . move_ip ( 0 , five ) 42 move_down_sound . play () For a standoff between the player and an enemy, you play the sound for when collisions are detected:
201 # Check if any enemies take collided with the player 202 if pygame . sprite . spritecollideany ( actor , enemies ): 203 # If so, and then remove the histrion 204 player . kill () 205 206 # End any moving sounds and play the collision sound 207 move_up_sound . finish () 208 move_down_sound . stop () 209 collision_sound . play () 210 211 # Stop the loop 212 running = False Here, y'all end whatever other audio effects kickoff, because in a collision the player is no longer moving. And so yous play the standoff sound and continue execution from there.
Finally, when the game is over, all sounds should stop. This is true whether the game ends due to a standoff or the user exits manually. To do this, add the following lines at the finish of the plan later the loop:
220 # All done! Stop and quit the mixer. 221 pygame . mixer . music . stop () 222 pygame . mixer . quit () Technically, these final few lines are not required, as the program ends correct afterwards this. However, if you decide later on to add an intro screen or an exit screen to your game, so there may be more code running after the game ends.
That's it! Exam it again, and you should meet something like this:
A Note on Sources
You may have noticed the annotate on lines 136-137 when the background music was loaded, list the source of the music and a link to the Artistic Eatables license. This was done because the creator of that audio required information technology. The license requirements stated that in social club 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 y'all can search for useful content:
- OpenGameArt.org: sounds, audio effects, sprites, and other artwork
- Kenney.nl: sounds, audio effects, sprites, and other artwork
- Gamer Art second: sprites and other artwork
- CC Mixter: sounds and audio effects
- Freesound: sounds and audio effects
As you brand your games and utilize downloaded content such equally art, music, or lawmaking from other sources, delight be sure that you lot are complying with the licensing terms of those sources.
Decision
Throughout this tutorial, you lot've learned how game programming with pygame differs from standard procedural programming. You've besides learned how to:
- Implement upshot loops
- Draw items on the screen
- Play sound furnishings and music
- Handle user input
To do this, y'all used a subset of the pygame modules, including the brandish, mixer and music, time, image, event, and central modules. Yous too used several pygame classes, including Rect, Surface, Sound, and Sprite. But these but scratch the surface of what pygame can do! Cheque out the official pygame documentation for a full listing of available modules and classes.
You tin can detect all of the code, graphics, and sound files for this commodity by clicking the link below:
Experience complimentary to leave comments below likewise. Happy Pythoning!
Sentry Now This tutorial has a related video course created past the Real Python team. Spotter it together with the written tutorial to deepen your understanding: Brand a 2nd Side-Scroller Game With PyGame
montgomerythempans.blogspot.com
Source: https://realpython.com/pygame-a-primer/
0 Response to "Elif Eventkey Pygameky Start Program Again"
ارسال یک نظر