Rattata Pixel Art How to Call Functions From Lists in Scratch
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:
Let'southward break this code downwards, department by section:
-
Lines iv and 5 import and initialize the
pygame
library. Without these lines, there is nopygame
. -
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:
- Processes user input
- Updates the state of all game objects
- Updates the display and sound output
- 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:
- The thespian collides with an obstruction. (You lot'll cover collision detection later.)
- 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 aKEYDOWN
upshot. If it is, and so the program checks which key was pressed by looking at theeffect.central
attribute. If the cardinal is the Esc cardinal, indicated pastK_ESCAPE
, then information technology exits the game loop past settingrunning = 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:
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:
-
screen.make full()
to fill the background -
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:
- The
Surface
to draw - 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:
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:
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:
Y'all may detect two minor problems:
- The player rectangle tin can move very fast if a key is held downward. You lot'll work on that later.
- 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
:
-
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. -
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. -
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. -
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:
- The kickoff
Group
volition hold everySprite
in the game. - The 2d
Grouping
will hold only theEnemy
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:
- Create a new
Enemy
. - Add information technology to
all_sprites
andenemies
.
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:
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:
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
:
- Create the
Cloud
class. - Add an image of a cloud to it.
- Create a method
.update()
that moves thecloud
toward the left side of the screen. - Create a custom event and handler to create new
deject
objects at a set time interval. - Add the newly created
cloud
objects to a newGroup
calledclouds
. - 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
andenemies
. - 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:
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:
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
Source: https://realpython.com/pygame-a-primer/
0 Response to "Rattata Pixel Art How to Call Functions From Lists in Scratch"
Post a Comment