pygame.font.Font Data Type
pygame.Surface Data Type
pygame.Rect Data Type
pygame.PixelArray Data Type
type() Function
blit () Method for Surface Objects
So far, all of our games have only used text. Text is displayed on the screen as output, and the player types in text from the keyboard as input. This is simple, and an easy way to learn programming. But in this chapter, we will make some more exciting games with advanced graphics and sound using the Pygame library. Chapters 17, 18, and 19 will
A software library is code that is not meant to be run by itself, but included in other programs to add new features. By using a library a programmer doesn't have to write the entire program, but can make use of the work that another programmer has done before them. Pygame is a
Pygame does not come with Python. Like Python, Pygame is available for free. You will have to download and install Pygame, which is as easy as downloading and installing the Python interpreter. In a web browser, go to the URL http://pygame.org and click on the "Downloads" link on the left side of the web site. This book assumes you have the Windows operating system, but Pygame works the same for every operating system. You need to download the Pygame installer for your operating system and the version of Python you have installed (3.1).
You do not want to download the "source" for Pygame, but rather the Pygame for your operating system. For Windows, download the pygame-1.9.1.win32-py3.1.msi file. (This is Pygame for Python 3.1 on Windows. If you installed a different version of Python (such as 2.5 or 2.4) download the .msi file for your version of Python.) The current version of Pygame at the time this book was written is 1.9.1. If you see a newer version on the website, download and install the newer Pygame. For Mac OS X and Linux, follow the directions on the download page for installation instructions.
(рис 17.1) The pygame.org website
On Windows,
>>> import pygame
If nothing appears after you hit the Enter key, then you know Pygame has successfully been installed. If the error ImportError: No module named pygame appears, then try to install Pygame again (and make sure you typed import pygame correctly).
This chapter has five small programs that
A video tutorial of how to install Pygame is available from this book's website at http://inventwithpython.com/videos/.
We are going to create a new "Hello World!" program, just like you created at the beginning of the book. This time, we will use Pygame to make "Hello world!" appear in a graphical user interface (GUI, which is pronounced "gooey") window. A
Pygame does not work well with the interactive shell because it relies on a game loop (we will describe game loops later). Because of this, you can only write Pygame programs and cannot send commands to Pygame one at a time through the interactive shell.
Pygame programs also do not use the input() function. There is no text input and output. Instead, the program displays output in a window by drawing graphics and text to the window. Pygame program's input comes from the keyboard and the mouse through things called events, which we will go over in the next chapter. However, if our program has bugs that cause Python to display an error message, the error message will show up in the console window.
You can also use print() calls to display text in the console window, however in Pygame the print() function is only used for
You can also look up information about how to use the Pygame library by visiting the web site http://pygame.org/docs/ref/.
Type in the following code into the file editor, and save it as pygameHelloWorld.py. Or you can download this source code by going to this book's website at http://inventwithpython.com/chapter17
pygameHelloWorld.py
This code can be downloaded from http://inventwithpython.com/pygameHelloWorld.py If you get errors after typing this code in, compare it to the book's code with the online diff tool at http://inventwithpython.com/diff or email the author at al@inventwithpython.com
1. import pygame, sys
2. from pygame.locals import *
3 .
4. # set up pygame
5. pygame.init()
6 .
7. # set up the window
8. windowSurface = pygame.display.set_mode((500, 400), 0, 32)
9. pygame.display.set_caption('Hello world!')
10 .
11. # set up the colors
12. BLACK = (0, 0, 0)
13. WHITE = (255, 255, 255)
14. RED = (255, 0, 0)
15. GREEN = (0, 255, 0)
16. BLUE = (0, 0, 2 55)
17 .
18. # set up fonts
19. basicFont = pygame.font.SysFont(None, 48)
20 .
21. # set up the text
22. text = basicFont.render('Hello world!', True, WHITE, BLUE)
23. textRect = text.get_rect()
24. textRect.centerx = windowSurface.get_rect().centerx
25. textRect.centery = windowSurface.get_rect().centery
26 .
27. # draw the white background onto the surface
28. windowSurface.fill(WHITE) 29 .
30. # draw a green polygon onto the surface
31. pygame.draw.polygon(windowSurface, GREEN, ((146, 0),
(291, 106), (236, 277), (56, 277), (0, 106))) 32 .
33. # draw some blue lines onto the surface
34. pygame.draw.line(windowSurface, BLUE, (60, 60), (120, 60), 4)
35. pygame.draw.line(windowSurface, BLUE, (12 0, 60), (60, 120) )
36. pygame.draw.line(windowSurface, BLUE, (60, 120), (12 0, 120), 4)
37 .
38. # draw a blue circle onto the surface
39. pygame.draw.circle(windowSurface, BLUE, (300, 50), 20, 0)
40 .
41. # draw a red ellipse onto the surface
42. pygame.draw.ellipse(windowSurface, RED, (300, 250, 40,80), 1)
43 .
44. # draw the text's background rectangle onto the surface
45. pygame.draw.rect(windowSurface, RED, (textRect.left - 20, textRect.top - 20, textRect.width + 40, textRect.height + 40) )
46 .
47. # get a pixel array of the surface
48. pixArray = pygame.PixelArray(windowSurface)
49. pixArray[480] [380] = BLACK
50. del pixArray
51.
52. # draw the text onto the surface
53. windowSurface.blit(text, textRect)
54 .
55. # draw the window onto the screen
56. pygame.display.update()
57.
58. # run the game loop
59. while True:
60. for event in pygame.event.get():
61. if event.type == QUIT:
62. pygame.quit()
63. sys.exit()
When you run this program, you should see a new GUI window appear which looks like Figure 17.2.
What is nice about using a GUI instead of a console is that the text can appear anywhere in the window, not just after the previous text we have printed. The text can be any color or size.
One thing you may notice is that Pygame uses a lot of ( and ), instead of [ and ]. The main difference is that once you create a
(рис 17.2) The "Hello World" program.
Let's go over each of these lines of code and find out what they do.
1. import pygame, sys 2. from pygame.locals import *
First we need to import the pygame module so we can call the functions in the Pygame pygame and sys modules.
The second line imports the pygame.locals module. This module contains many QUIT or K_ESCAPE (which we will explain later). However, using the form from moduleName import * we can import the pygame.locals module but not have to type pygame.locals in front of each time we use the module's functions and variables in our program. The * symbol means we should import everything inside the module.
The pygame.locals module contains some from sys import * instead of import sys in your program, you could call exit() instead of sys.exit() in your code. (But most of the time it is better to use the full function name so that you know which module the exit() is in.)
4. # set up pygame 5. pygame.init()
The Pygame pygame.init() after importing the pygame module but before calling any other Pygame functions.
7. # set up the window
8. windowSurface = pygame.display.set_mode((500, 400), 0, 32)
9. pygame.display.set_caption('Hello world!')
Line 8 creates a GUI window for our program by calling the set_mode() method in the pygame.display module. (The display module is a module inside the pygame module. Pygame is so advanced that even the pygame module has its own modules!)
Just to avoid confusion, you should know the difference between the window that is created is different and the Windows operating system. The
There are three parameters to the set_mode() method. The first parameter is a
We want the window to be 500 pixels wide and 400 pixels high, so we use the (500, 400) for the first parameter. To get the total number of pixels in our window, multiply the width and the height. Our window is made up of 20,000 pixels, and it doesn't even take up the entire computer screen!
The second parameter is for advanced GUI window options. You won't really need this for your games, so you can always just pass 0 for this parameter. The third parameter is another advanced option called the
The set_caption() call returns a pygame. object (which we will call objects for short). Objects are values of a data type that have methods as well as data. For example, strings are objects in Python because they have data (the string itself) and methods (such as lower() and split()). You can store objects in variables just like any other value. The object represents the window and we will include the windowSurface variable in all of our calls to drawing functions.
You should know that variables never hold objects (including lists and dictionaries), they only hold references to objects. This is exactly the same way that variables never hold lists but only hold references to lists. The difference between holding the object and holding a reference to the object is that if you copy the variable to a second variable, any changes made to object in one of the variables will also change the object in the other variable. This is because both variables hold references to the same object because only a copy of the reference was made, not a copy of the object.
Here is an example with lists (just like in the Hangman chapter). Type the following into the interactive shell:
>>> x = ['a', 'b', 'c'] >>> y = x >>> x[2] = 'Hello!' >>> print(y) ['a', 'b', 'Hello!']
Notice that changing the x list has also changed the y list, because they both contain references to the same list. y made a copy of the reference in x, not a copy of the list.
The same applies to objects. Consider the following code:
>>> import pygame >>> pygame.init() >>> windowSurface = pygame.display.set_mode((500, 500), 0, 32) >>> secondSurface = windowSurface
windowSurface and secondSurface contain references to the same object. Any changes made to windowSurface will change the same object that secondSurface references. The same is true that any changes to windowSurface will change windowSurface.
11. # set up the colors 12. BLACK = (0, 0, 0) 13. WHITE = (255, 255, 255) 14. RED = (255, 0, 0) 15. GREEN = (0, 255, 0) 16. BLUE = (0, 0, 2 55)
There are three 0 means there is no red in this color, and a value of 255 means there is a maximum amount of red in the color. The second value is for green and the third value is for blue.
For example, we will create the (0, 0, 0) and store it in a variable named BLACK. With no amount of red, green, or blue, the resulting color is completely black. The color black is the absence of any color.
On line 13, we use the (255, 255, 255) for a maximum amount of red, green, and blue to result in white. The color white is the full combination of red, green, and blue. We store this WHITE variable. (255, 0, 0) represents the maximum amount of red but no amount of green and blue, so the resulting color is red. Similarly, (0, 255, 0) is green and (0, 0, 255) is blue.
These variable names are in all capitals because they are BLACK in our code than (0, 0, 0) every time we want to specify the color black, so we set up these color variables at the start of our program.
If you want to make a color lighter, try adding an equal amount from all three values. For example, the RGB value for gray is (128, 128, 128). You can get the RGB value for a lighter gray by adding 20 to each value to get (148, 148, 148). You can get the RGB value for a darker gray by subtracting 20 from each value to get (108, 108, 108). And you can get the RGB value for a slightly redder gray by adding 20 to only the red value to get (148, 128, 128). Table 17.1 has some common colors and their RGB values.
| Color | RGB Values |
|---|---|
| Aqua | (0, 255, 255) |
| Black | (0, 0, 0) |
| Blue | (0, 0, 255) |
| Cornflower Blue | (100, 149, 237) |
| Fuchsia | (255, 0, 255) |
| Gray | (128, 128, 128) |
| Green | (0, 128, 0) |
| Lime | (0, 255, 0) |
| Maroon | (128, 0, 0) |
| Navy Blue | (0, 0, 128) |
| Olive | (128, 128, 0) |
| Purple | (128, 0, 128) |
| Red | (255, 0, 0) |
| Silver | (192, 192, 192) |
| Teal | (0, 128, 128) |
| White | (255, 255, 255) |
| Yellow | (255, 255, 0) |
18. # set up fonts 19. basicFont = pygame.font.SysFont(None, 48)
(рис 17.3) Examples of different fonts.
A font is a complete set of letters, numbers, symbols, and characters of a single style. Here is an example of the same
In our earlier games, we only told Python to print out text. The color, size, and font that was used to display this text was completely determined by whatever font your operating system uses for console windows. Our programs could not change the font at all. However, since we will be drawing out letters to a GUI window we need to tell Pygame exactly what font to use when drawing the text.
On line 19 we create a pygame.font.Font object (which we will just call Font objects for short) by calling the pygame.font.SysFont() function. The first parameter is the name of the font, but we will pass the None value to use the default
21. # set up the text
22. text = basicFont.render('Hello world!', True, WHITE, BLUE)
23. textRect = text.get_rect()
The Font object that we have stored in the basicFont variable has a render(). This method will create a object with the text drawn on it. The first parameter to render() is the string of the text to draw. The second parameter is a boolean for whether or not we want anti-aliasing. Anti-aliasing is a technique for making a drawing look less True to say we want to use anti-aliasing. Figure 17.4 is an example of what a line (when we
Anti-aliasing can make your text and lines look blurry but smoother. It takes a little more computation time to do anti-aliasing, so although the graphics may look better, your program may run slower (but only just a little).
(рис 17.4) An aliased line and an anti-aliased line.
24. textRect.centerx = windowSurface.get_rect().centerx 25. textRect.centery = windowSurface.get_rect().centery
The pygame.Rect data type (which we will just call Rect for short) makes working with rectangle-shaped things easy. To create a new Rect object call the function pygame.Rect(). The parameters are integers for the XY coordinates of the top left corner, followed by the width and height. These integers are in number of pixels.
The function name with the parameters looks like this: pygame.Rect(left, top, width, height)
Just like methods are functions that are associated with an object, attributes are variables that are associated with an object. The Rect data type (that is, the data type of all Rect objects) has many attributes that describe the rectangle they represent. Here is a list of attributes of a Rect object named myRect:
| pygame.Rect Attribute | Description |
|---|---|
myRect.left
| The int value of the X-coordinate of the left side of the rectangle. |
myRect.right
| The int value of the X-coordinate of the right side of the rectangle. |
myRect.top
| The int value of the Y-coordinate of the |
myRect.bottom
| The int value of the Y-coordinate of the bottom side of the rectangle. |
myRect.centerx
| The int value of the X-coordinate of the center of the rectangle. |
myRect.centery
| The int value of the Y-coordinate of the center of the rectangle. |
myRect.width
| The int value of the width of the rectangle. |
myRect.height
| The int value of the height of the rectangle. |
myRect.size
| A |
myRect.topleft
| A |
myRect.topright
| A |
myRect.bottomleft
| A |
myRect.bottomright
| A |
myRect.midleft
| A |
myRect.midright
| A |
myRect.midtop
| A |
myRect.midbottom
| A |
The great thing about Rect objects is that if you modify any of these variables, all the other variables will automatically modify themselves as well. For example, if you create a Rect object that is 20 pixels wide and 20 pixels high, and has the top left corner at the coordinates (30, 40), then the X-coordinate of the right side will automatically be set to 50 (because 20 + 30 = 50). However, if you change the left attribute with the line myRect.left = 100, then Pygame will automatically change the right attribute to 120 (because 20 + 100 = 120). Every other attribute for that Rect object will also be updated as well.
Notice that both the Font object (stored in the text variable) and the object (stored in windowSurface variable) both have a get_rect(). Technically, these are two different methods. But the programmers of Pygame gave them the same name because they both do the same thing and return Rect objects that represent the size and position of the Font or object.
Also, remember that pygame is a module that we import, and inside the pygame module are the font and modules. Inside those modules are the Font and data types. The Pygame programmers made the modules begin with a
We create a pygame.Rect object by calling a function named pygame.Rect(). The pygame.Rect() function has the same name as the pygame.Rect data type.
Functions that have the same name as their data type and create objects or values of this data type are called constructor functions
The int() and str() functions are also constructor functions. The int() function returns an int version of whatever you pass it, whether it is int(5) or int('5'). (The str.)
You can always find out what the type() function. For example, try typing the following into the interactive shell:
>>> type('This is a string')
<type 'str'>
>>> type(5)
<type 'int'>
>>> spam = 'Another string'
>>> type(spam)
<type 'str'>
>>> import pygame
>>> pygame.init()
>>> myRect = pygame.Rect(10, 10, 40, 50)
>>> type(myRect)
<type 'pygame.Rect'>
>>> pygame.quit()
(You need to call the pygame.quit() function when you are done with typing Pygame functions into the interactive shell. Otherwise you may cause Python to type() function is not a string, but a value of a data type called "type"!
Try typing this into the interactive shell:
>>> type(type('This is a string')) I
<type 'type'> I
For the most part, you don't need to know about data types and the type() function when programming games. But it can be very useful if you need to find out the data type of the value stored in a variable in your program.
27. # draw the white background onto the surface 28. windowSurface.fill(WHITE)
This is the first drawing windowSurface with the color white. The fill() function will completely cover the entire BLACK to make the background black.)
An important thing to know about Pygame is that the window on the screen will not change when we call the fill() method or any of the other drawing functions. These will draw on the object, but the object will not be drawn on the user's screen until the pygame.display.update() function is called. This is because drawing on the object (which is stored in the computer's memory) is much faster than drawing to the computer screen. It is much more
30. # draw a green polygon onto the surface 31. pygame.draw.polygon(windowSurface, GREEN, ((146, 0), (291, 106), (236, 277), (56, 277), (0, 106)))
A polygon is any multisided shape with sides that are only straight lines. The pygame.draw.polygon() function can draw any shape that you give it and fill the inside space of the polygon. The
(рис 17.5) Examples of Polygons.
Polygons only have straight lines for sides (circles and ellipses are not polygons). Figure 17.5 has some examples of polygons.
33. # draw some blue lines onto the surface 34. pygame.draw.line(windowSurface, BLUE, (60, 60), (120, 60), 4) 35. pygame.draw.line(windowSurface, BLUE, (12 0, 60), (60, 120) ) 36. pygame.draw.line(windowSurface, BLUE, (60, 120), (12 0, 120), 4)
The pygame.draw.line() function will draw a line on the object that you provide. Notice that the last parameter (the width of the line) is optional. If you pass 4 for the width, the line will be four pixels thick. If you do not specify the width parameter it will take on the default value of 1.
38. # draw a blue circle onto the surface 39. pygame.draw.circle(windowSurface, BLUE, (300, 50), 20, 0)
The pygame.draw.circle() function will draw a circle on the object you provide. The third parameter is for the X and Y coordinates of the center of the circle as a int for the radius (that is, size) of the circle in pixels. A width of 0 means that the circle will be filled in.
41. # draw a red ellipse onto the surface 42. pygame.draw.ellipse(windowSurface, RED, (300, 250, 40, 80), 1)
The pygame.draw.ellipse() function will draw an ellipse. It is similar to the pygame.draw.circle() function, except that instead of specifying the center of the circle, a
44. # draw the text's background rectangle onto the surface 45. pygame.draw.rect(windowSurface, RED, (textRect.left - 20, textRect.top - 20, textRect.width + 40, textRect.height + 40) )
The pygame.draw.rect() function will draw a rectangle. The third parameter is a Rect object. In line 45, we want the rectangle we draw to be 20 pixels around all the sides of the text. This is why we want the drawn rectangle's left and top to be the left and top of textRect minus 20. (Remember, we subtract because coordinates textRect plus 40 (because the left and top were moved back 20 pixels, so we need to make up for that space).
47. # get a pixel array of the surface 48. pixArray = pygame.PixelArray(windowSurface) 49. pixArray[480] [380] = BLACK
On line 48 we create a pygame.PixelArray object (which we will just call a PixelArray object for short). The PixelArray object is a list of lists of color object you passed it. We passed windowSurface object when we called the PixelArray() constructor function on line 48, so assigning BLACK to pixArray[480][380] will change the pixel at the coordinates (480, 380) to be a black pixel. Pygame will automatically modify the windowSurface object with this change.
The first index in the PixelArray object is for the X-coordinate. The second index is for the Y-coordinate. PixelArray objects make it easy to set PixelArray object to a specific color.
50. del pixArray
Creating a PixelArray object from a object will lock that object. Locked means that no object. To unlock the object, you must delete the PixelArray object with the del operator. If you forget to delete the object, you will get an error message that says pygame..
52. # draw the text onto the surface 53. windowSurface.blit(text, textRect)
The method will draw the contents of one object onto another object. Line 54 will draw the "Hello world!" text (which was drawn on the object stored in the text variable) and draws it to the object stored in the windowSurface variable.
Remember that the text object had the "Hello world!" text drawn on it on line 22 by the render() method. objects are just stored in the computer's memory (like any other variable) and not drawn on the screen. The object in windowSurface is drawn on the screen (when we call the pygame.display.update() function on line 56 below) because this was the object created by the pygame.display.set_mode() function.
The second parameter to specifies where on the windowSurface text Rect object we got from calling text.get_rect() (which was stored in textRect on line 23).
55. # draw the window onto the screen 56. pygame.display.update()
In Pygame, nothing is drawn to the screen until the pygame.display.update() function is called. This is done because drawing to the screen is a slow operation for the computer compared to drawing on the objects while they are in memory. You do not want to draw to the screen after each drawing function is called, but only draw the screen once after all the drawing functions have been called.
You will need to call pygame.display.update() each time you want to update the screen to display the contents of the object returned by pygame.display.set_mode(). (In this program, that object is the one stored in windowSurface.) This will become more important in our next program which covers animation.
In our previous games, all of the programs print out everything immediately until they reach a input()
The game loop is a loop that constantly checks for new events, updates the state of the window, and draws the window on the screen. Events are values of the pygame.event.Event data type that are generated by Pygame whenever the user presses a key, clicks or moves the mouse, or makes some other event occur. Calling pygame.event.get() retrieves any new pygame.event.Event objects that have been generated since the last call to pygame.event.get().
58. # run the game loop 59. while True:
This is the start of our game loop. The condition for the while statement is set to True so that we loop forever. The only time we exit the loop is if an event causes the program to terminate.
60. for event in pygame.event.get(): 61. if event.type == QUIT:
The pygame.event.get() function returns a list of pygame.event.Event objects. This list has every single event that has occurred since the last time pygame.event.get() was called. All pygame.event.Event objects have an attribute called type which tell us what type of event it is. (A list of event types is given in the next chapter. In this chapter we only deal with the QUIT event.)
Pygame comes supplied with its own pygame.locals module. Remember that we have imported the pygame.locals module with the line from pygame.locals import *, which means we do not have to type pygame.locals in front of the variables and functions in that module.
On line 60 we set up a for loop to check each pygame.event.Event object in the list returned by pygame.event.get(). If the type attribute of the event is equal to the value of the QUIT (which is provided by the pygame.locals module), then we know the user has closed the window and wants to terminate the program.
Pygame generates the QUIT event when the user clicks on the X button at the top right of the program's window. It is also generated if the computer is shutting down and tries to terminate all the programs running. For whatever reason the QUIT event was generated, we know that we should run any code that we want to happen to stop the program. You could choose to ignore the QUIT event entirely, but that may cause the program to be confusing to the user.
62. pygame.quit() 63. sys.exit()
If the QUIT event has been generated, then we can know that the user has tried to close the window. In that case, we should call the exit functions for both Pygame (pygame.quit() ) and Python (sys.exit() ).
This has been the simple "Hello world!" program from Pygame. We've covered many new topics that we didn't have to deal with in our previous games. Even though they are more complicated, the Pygame programs can also be much more fun and engaging than our previous text games. Let's learn how to create games with
In this program we have several different blocks
Type the following program into the file editor and save it as animation.py. You can also download this source code from http://inventwithpython.com/chapter17.
animation.py
This code can be downloaded from http://inventwithpython.com/animation.py
If you get errors after typing this code in, compare it to the book's code with the online
diff tool at http://inventwithpython.com/diff or email the author at
al@inventwithpython.com
1. import pygame, sys, time
2. from pygame.locals import * 3 .
4. # set up pygame
5. pygame.init() 6 .
7. # set up the window
8. WINDOWWIDTH = 400
9. WINDOWHEIGHT = 400
10. windowSurface = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT), 0, 32)
11. pygame.display.set_caption('Animation')
12.
13. # set up direction variables
14. DOWNLEFT = 1
15. DOWNRIGHT = 3
16. UPLEFT = 7
17. UPRIGHT = 9 18.
19. MOVESPEED = 4 20.
21. # set up the colors
22. BLACK = (0, 0, 0)
23. RED = (255, 0, 0)
24. GREEN = (0, 255, 0)
25. BLUE = (0, 0, 255)
26.
27. # set up the block data structure
28. b1 = {'rect':pygame.Rect(300, 80, 50, 100), 'color':RED, 'dir':UPRIGHT}
29. b2 = {'rect':pygame.Rect(200, 200, 20, 20), 'color':GREEN, 'dir':UPLEFT}
30. b3 = {'rect':pygame.Rect(100, 150, 60, 60), 'color':BLUE, 'dir':DOWNLEFT}
31. blocks = [b1, b2, b3] 32.
33. # run the game loop
34. while True:
35. # check for the QUIT event
36. for event in pygame.event.get():
37. if event.type == QUIT:
38. pygame.quit()
39. sys.exit() 40.
41. # draw the black background onto the surface
42. windowSurface.fill(BLACK)
43.
44. for b in blocks:
45. # move the block data structure
46. if b['dir'] == DOWNLEFT:
47. b['rect'].left -= MOVESPEED
48. b['rect'].top += MOVESPEED
49. if b['dir'] == DOWNRIGHT:
50. b['rect'].left += MOVESPEED
51. b['rect'].top += MOVESPEED
52. if b['dir'] == UPLEFT:
53. b['rect'].left -= MOVESPEED
54. b['rect'].top -= MOVESPEED
55. if b['dir'] == UPRIGHT:
56. b['rect'].left += MOVESPEED
57. b['rect'].top -= MOVESPEED
58.
59. # check if the block has move out of the window
60. if b ['rect'] .top < 0:
61. # block has moved past the top
62. if b['dir'] == UPLEFT:
63. b['dir'] = DOWNLEFT
64. if b['dir'] == UPRIGHT:
65. b['dir'] = DOWNRIGHT
66. if b [ 'rect'] .bottom > WINDOWHEIGHT:
67. # block has moved past the bottom
68. if b['dir'] == DOWNLEFT:
69. b['dir'] = UPLEFT
70. if b['dir'] == DOWNRIGHT:
71. b['dir'] = UPRIGHT
72. if b ['rect'] .left < 0:
73 . # block has moved past the left side
74. if b['dir'] == DOWNLEFT:
75. b['dir'] = DOWNRIGHT
76. if b['dir'] == UPLEFT:
77. b['dir'] = UPRIGHT
78. if b [ 'rect'] .right > WINDOWWIDTH:
79. # block has moved past the right side
80. if b['dir'] == DOWNRIGHT:
81. b['dir'] = DOWNLEFT
82. if b['dir'] == UPRIGHT:
83. b['dir'] = UPLEFT 84 .
85. # draw the block onto the surface
86. pygame.draw.rect(windowSurface, b['color'], b ['rect' ])
87 .
88. # draw the window onto the screen
89. pygame.display.update()
90. time.sleep(0.02)
(рис 17.6) The Animation program.
In this program, we will have three different colored
Each block will move in one of four
The new direction that a block moves after it bounces depends on two things: which direction it was moving before the
We can represent the blocks with a Rect object to represent the position and size of the block, a Rect object. Also in each iteration we will draw all the blocks on the screen at their
(рис 17.7) The diagram of how blocks will bounce.
1. import pygame, sys, time
In this program, we also want to import the time module.
7. # set up the window 8. WINDOWWIDTH = 400 9. WINDOWHEIGHT = 400 10. windowSurface = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT), 0, 32)
In this program the size of the window's width and height is used for more than just the call to set_mode(). We will use a
If we did not use the 400. If any unrelated values in the program were also 400, we might think it was for the width or height and also accidentally change it too. This would put a bug in our program. Since the window width and height never change during the program's execution, a
11. pygame.display.set_caption('Animation')
For this program, we will set the caption at the top of the window to 'Animation' with a call to pygame.display.set_caption().
13. Setting Up Constant Variables for Direction 14. # set up direction variables 15. DOWNLEFT = 1 16. DOWNRIGHT = 3 17. UPLEFT = 7 18. UPRIGHT = 9
We will use the keys on the number pad of the keyboard to remind us which belongs to which direction. This will be similar to our 1 is down and left, 3 is down and right, 7 is up and left, and 'Animation' 9 is up and right. However, it may be hard to remember this, so instead we will use
We could use any values we wanted to for these directions, as long as we had different values for each direction. For example, we could use the string 'downleft' to represent the down and left 'downleft' string (for example, as 'fownleft'), the computer would not 'downleft' instead of 'fownleft'. This bug would cause our program to behave strangely.
But if we use FOWNLEFT instead of the name DOWNLEFT, Python would notice that there is no such variable named FOWNLEFT and
19. MOVESPEED = 4
We will use a
21. # set up the colors 22. BLACK = (0, 0, 0) 23. RED = (255, 0, 0) 24. GREEN = (0, 255, 0) 25. BLUE = (0, 0, 2 55)
We set up 0 to 255. Unlike our "Hello World" program, this program doesn't use the white color, so we left it out.
Again, the use of GREEN for the color green. But if we later look at this program, it is easier to know that GREEN stands for the color green rather than a bunch of int values in a
27. # set up the block data structure
28. b1 = {'rect' :pygame.Rect(300 , 80, 50, 100), 'color' :RED, 'dir':UPRIGHT}
We will set up a dictionary to be the 'rect' (with a Rect object for a value), 'color' (with a 'dir' (with one of our direction
We will store one of these b1. This block will have its top left corner located at an X-coordinate of 300 and Y-coordinate of 80. It will have a width of 50 pixels and a height of 100 pixels. Its color will be red (so we'll use our RED (255, 0, 0) stored in it). And its direction will be set to UPRIGHT.
29. b2 = {'rect':pygame.Rect(200, 200, 20, 20), 'color':GREEN, 'dir':UPLEFT}
30. b3 = {'rect':pygame.Rect(10 0, 150, 60, 60), 'color':BLUE, 'dir':DOWNLEFT}
Here we create two more similar
31. blocks = [b1, b2, b3]
On line 31 we put all of these rectangles.
rectangles is a list. rectangles[0] would be the dictionary r1. rectangles[0]['color'] would be the 'color' key in r1 (which we stored the value in RED in), so the expression rectangles[0]['color'] would evaluate to (255, 0, 0). In this way we can refer to any of the values in any of the block rectangles.
33 . # run the game loop 34. while True:
Inside the game loop, we want to move all of the blocks around the screen in the direction that they are going, then windowSurface
pygame.display.update() to draw the pygame.event.get() to check if the QUIT event has been generated by the user closing the window.
The for loop to check all of the events in the list returned by pygame.event.get() is the same as in our "Hello World!" program, so we will skip its
41. # draw the black background onto the surface 42. windowSurface.fill(BLACK)
Before we draw any of the blocks on the windowSurface
44. for b in blocks:
We want to update the position of each block, so we must loop through the rectangles list and perform the same code on each block's
45. # move the block data structure 46. if b['dir'] == DOWNLEFT: 47. b['rect'].left -= MOVESPEED 48. b [ 'rect'] .top += MOVESPEED 49. if b['dir'] == DOWNRIGHT: 50. b['rect'].left += MOVESPEED 51. b [ 'rect'] .top += MOVESPEED 52. if b['dir'] == UPLEFT: 53. b['rect'].left -= MOVESPEED 54. b [ 'rect'] .top -= MOVESPEED 55. if b['dir'] == UPRIGHT: 56. b ['rect'] .left += MOVESPEED 57. b['rect'].top -= MOVESPEED
The new value that we want to set the left and top attributes to depends on the direction the block is moving. Remember that the X-coordinates start at 0 on the very left edge of the window, and increase as you go right. The Y-coordinates start at 0 on the very top of the window, and increase as you go down. So if the direction of the block (which, remember, is stored in the 'dir' key) is either DOWNLEFT or DOWNRIGHT, we want to increase the top attribute. If the direction is UPLEFT or UPRIGHT, we want to top attribute.
If the direction of the block is DOWNRIGHT or UPRIGHT, we want to increase the left attribute. If the direction is DOWNLEFT or UPLEFT, we want to decrease the left attribute.
We could have also modified right instead of the left attribute, or the bottom attribute instead of the top attribute, because Pygame will update the Rect object either way. Either way, we want to change the value of these attributes by the integer stored in MOVESPEED, which stores how many pixels over we will move the block.
59. # check if the block has move out of the window 60. if b ['rect'] .top < 0: 61. # block has moved past the top 62. if b['dir'] == UPLEFT: 63. b['dir'] = DOWNLEFT 64. if b['dir'] == UPRIGHT: 65. b['dir'] = DOWNRIGHT
After we have moved the block, we want to check if the block has gone past the edge of the window. If it has, we want to "'dir' key. When the direction is set, the block will move in the new direction on the next iteration of the game loop.
We need to check if the block has moved passed each of the four edges of the window. In the above if statement, we decide the block has moved past the top edge of the window if the block's Rect object's top attribute is less than 0. If it is, then we need to change the direction based on what direction the block was moving.
Look at the UPLEFT or UPRIGHT directions. If the block was moving in the UPLEFT direction, the new direction (according to our DOWNLEFT. If the block was moving in the UPRIGHT direction, the new direction will be DOWNRIGHT.
66. if b['rect'].bottom > WINDOWHEIGHT: 67. # block has moved past the bottom 68. if b['dir'] == DOWNLEFT: 69. b['dir'] = UPLEFT 70. if b['dir'] == DOWNRIGHT: 71. b['dir'] = UPRIGHT
Here we see if the block has moved past the bottom edge of the window by checking if the bottom attribute (not the top attribute) is greater than the value in WINDOWHEIGHT. Remember that the Y-coordinates start at 0 at the top of the window and increase to WINDOWHEIGHT because we passed WINDOWHEIGHT as the height in our call to pygame.display.set_mode().
The rest of the code changes the direction based on what our
72. if b ['rect'] .left < 0: 73. # block has moved past the left side 74. if b['dir'] == DOWNLEFT: 75. b['dir'] = DOWNRIGHT 76. if b['dir'] == UPLEFT: 77. b['dir'] = UPRIGHT
This is similar to the above code, but checks if the left side of the block has moved to the left of the left edge of the window. Remember, the X-coordinates start at 0 on the left edge of the window and increase to WINDOWWIDTH on the right edge of the window.
78. if b [ 'rect'] .right > WINDOWWIDTH: 79. # block has moved past the right side 80. if b['dir'] == DOWNRIGHT: 81. b['dir'] = DOWNLEFT 82. if b['dir'] == UPRIGHT: 83. b['dir'] = UPLEFT
This code is similar to the previous pieces of code, but it checks if the block has moved past the
85. # draw the block onto the surface 86. pygame.draw.rect(windowSurface, b['color'], b ['rect' ])
Now that we have moved the block (and set a new direction if the block has windowSurface pygame.draw.rect() function. We pass windowSurface, because that is the object we want to draw on. We pass the b['color'] value, because this is the color we want to use. Then we pass b['rect'], because that Rect object has the information about the position and size of the rectangle we want to draw.
This is the last line of the for loop. We want to run the moving,
88. # draw the window onto the screen 89. pygame.display.update() 90. time.sleep(0.02)
After we have run this code on each of the blocks in the blocks list, we want to finally call pygame.display.update() so that the windowSurface QUIT event has been generated by the Pygame library (which happens if the player closes the window or shuts down their computer). In that case we terminate the program.
The call to the time.sleep() function is there because the computer can move, time.sleep(0.02) line and running the program to see this.) This call to time.sleep() will stop the program for 20
Just for fun, let's make some small # in front of line 90 (the time.sleep(0.2) line) of our animation program. This will cause Python to ignore this line because it is now a comment. Now try running the program.
Without the time.sleep()
Remove the # from the front of line 90 so that the line is no longer a comment and becomes part of the program again. This time, comment out line 42 (the windowSurface.fill(BLACK) line) by adding a # to the front of the line. Now run the program.
Without the call to windowSurface.fill(BLACK), we do not black out the entire window before drawing the rectangles in their new position. This will cause trails of rectangles to appear on the screen instead of
Remember that the blocks are not really moving. We are just redrawing the entire window over and over again. On each iteration through the game loop, we redraw the entire window with new blocks that are located a few pixels over each time. When the program runs very fast, we make it is just one block each time. In order to see that we are just redrawing the blocks over and over again, change line 90 to time.sleep(1.0). This will make the program (and the drawing) fifty times slower than normal. You will see each drawing being replaced by the next drawing every second.
This chapter has presented a whole new way of creating drawBoard() function to be displayed on the screen. Our animation program is very similar. The blocks variable held a list of
But without calls to input(), how do we get input from the player? In our next chapter, we will cover how our program can know when the player presses any key on the keyboard. We will also learn of a concept called
pygame.font.Font Data Type
pygame.Surface Data Type
pygame.Rect Data Type
pygame.PixelArray Data Type
type() Function
blit () Method for Surface Objects
So far, all of our games have only used text. Text is displayed on the screen as output, and the player types in text from the keyboard as input. This is simple, and an easy way to learn programming. But in this chapter, we will make some more exciting games with advanced graphics and sound using the Pygame library. Chapters 17, 18, and 19 will
A software library is code that is not meant to be run by itself, but included in other programs to add new features. By using a library a programmer doesn't have to write the entire program, but can make use of the work that another programmer has done before them. Pygame is a
Pygame does not come with Python. Like Python, Pygame is available for free. You will have to download and install Pygame, which is as easy as downloading and installing the Python interpreter. In a web browser, go to the URL http://pygame.org and click on the "Downloads" link on the left side of the web site. This book assumes you have the Windows operating system, but Pygame works the same for every operating system. You need to download the Pygame installer for your operating system and the version of Python you have installed (3.1).
You do not want to download the "source" for Pygame, but rather the Pygame for your operating system. For Windows, download the pygame-1.9.1.win32-py3.1.msi file. (This is Pygame for Python 3.1 on Windows. If you installed a different version of Python (such as 2.5 or 2.4) download the .msi file for your version of Python.) The current version of Pygame at the time this book was written is 1.9.1. If you see a newer version on the website, download and install the newer Pygame. For Mac OS X and Linux, follow the directions on the download page for installation instructions.
(рис 17.1) The pygame.org website
On Windows,
>>> import pygame
If nothing appears after you hit the Enter key, then you know Pygame has successfully been installed. If the error ImportError: No module named pygame appears, then try to install Pygame again (and make sure you typed import pygame correctly).
This chapter has five small programs that
A video tutorial of how to install Pygame is available from this book's website at http://inventwithpython.com/videos/.
We are going to create a new "Hello World!" program, just like you created at the beginning of the book. This time, we will use Pygame to make "Hello world!" appear in a graphical user interface (GUI, which is pronounced "gooey") window. A
Pygame does not work well with the interactive shell because it relies on a game loop (we will describe game loops later). Because of this, you can only write Pygame programs and cannot send commands to Pygame one at a time through the interactive shell.
Pygame programs also do not use the input() function. There is no text input and output. Instead, the program displays output in a window by drawing graphics and text to the window. Pygame program's input comes from the keyboard and the mouse through things called events, which we will go over in the next chapter. However, if our program has bugs that cause Python to display an error message, the error message will show up in the console window.
You can also use print() calls to display text in the console window, however in Pygame the print() function is only used for
You can also look up information about how to use the Pygame library by visiting the web site http://pygame.org/docs/ref/.
Type in the following code into the file editor, and save it as pygameHelloWorld.py. Or you can download this source code by going to this book's website at http://inventwithpython.com/chapter17
pygameHelloWorld.py
This code can be downloaded from http://inventwithpython.com/pygameHelloWorld.py If you get errors after typing this code in, compare it to the book's code with the online diff tool at http://inventwithpython.com/diff or email the author at al@inventwithpython.com
1. import pygame, sys
2. from pygame.locals import *
3 .
4. # set up pygame
5. pygame.init()
6 .
7. # set up the window
8. windowSurface = pygame.display.set_mode((500, 400), 0, 32)
9. pygame.display.set_caption('Hello world!')
10 .
11. # set up the colors
12. BLACK = (0, 0, 0)
13. WHITE = (255, 255, 255)
14. RED = (255, 0, 0)
15. GREEN = (0, 255, 0)
16. BLUE = (0, 0, 2 55)
17 .
18. # set up fonts
19. basicFont = pygame.font.SysFont(None, 48)
20 .
21. # set up the text
22. text = basicFont.render('Hello world!', True, WHITE, BLUE)
23. textRect = text.get_rect()
24. textRect.centerx = windowSurface.get_rect().centerx
25. textRect.centery = windowSurface.get_rect().centery
26 .
27. # draw the white background onto the surface
28. windowSurface.fill(WHITE) 29 .
30. # draw a green polygon onto the surface
31. pygame.draw.polygon(windowSurface, GREEN, ((146, 0),
(291, 106), (236, 277), (56, 277), (0, 106))) 32 .
33. # draw some blue lines onto the surface
34. pygame.draw.line(windowSurface, BLUE, (60, 60), (120, 60), 4)
35. pygame.draw.line(windowSurface, BLUE, (12 0, 60), (60, 120) )
36. pygame.draw.line(windowSurface, BLUE, (60, 120), (12 0, 120), 4)
37 .
38. # draw a blue circle onto the surface
39. pygame.draw.circle(windowSurface, BLUE, (300, 50), 20, 0)
40 .
41. # draw a red ellipse onto the surface
42. pygame.draw.ellipse(windowSurface, RED, (300, 250, 40,80), 1)
43 .
44. # draw the text's background rectangle onto the surface
45. pygame.draw.rect(windowSurface, RED, (textRect.left - 20, textRect.top - 20, textRect.width + 40, textRect.height + 40) )
46 .
47. # get a pixel array of the surface
48. pixArray = pygame.PixelArray(windowSurface)
49. pixArray[480] [380] = BLACK
50. del pixArray
51.
52. # draw the text onto the surface
53. windowSurface.blit(text, textRect)
54 .
55. # draw the window onto the screen
56. pygame.display.update()
57.
58. # run the game loop
59. while True:
60. for event in pygame.event.get():
61. if event.type == QUIT:
62. pygame.quit()
63. sys.exit()
When you run this program, you should see a new GUI window appear which looks like Figure 17.2.
What is nice about using a GUI instead of a console is that the text can appear anywhere in the window, not just after the previous text we have printed. The text can be any color or size.
One thing you may notice is that Pygame uses a lot of ( and ), instead of [ and ]. The main difference is that once you create a
(рис 17.2) The "Hello World" program.
Let's go over each of these lines of code and find out what they do.
1. import pygame, sys 2. from pygame.locals import *
First we need to import the pygame module so we can call the functions in the Pygame pygame and sys modules.
The second line imports the pygame.locals module. This module contains many QUIT or K_ESCAPE (which we will explain later). However, using the form from moduleName import * we can import the pygame.locals module but not have to type pygame.locals in front of each time we use the module's functions and variables in our program. The * symbol means we should import everything inside the module.
The pygame.locals module contains some from sys import * instead of import sys in your program, you could call exit() instead of sys.exit() in your code. (But most of the time it is better to use the full function name so that you know which module the exit() is in.)
4. # set up pygame 5. pygame.init()
The Pygame pygame.init() after importing the pygame module but before calling any other Pygame functions.
7. # set up the window
8. windowSurface = pygame.display.set_mode((500, 400), 0, 32)
9. pygame.display.set_caption('Hello world!')
Line 8 creates a GUI window for our program by calling the set_mode() method in the pygame.display module. (The display module is a module inside the pygame module. Pygame is so advanced that even the pygame module has its own modules!)
Just to avoid confusion, you should know the difference between the window that is created is different and the Windows operating system. The
There are three parameters to the set_mode() method. The first parameter is a
We want the window to be 500 pixels wide and 400 pixels high, so we use the (500, 400) for the first parameter. To get the total number of pixels in our window, multiply the width and the height. Our window is made up of 20,000 pixels, and it doesn't even take up the entire computer screen!
The second parameter is for advanced GUI window options. You won't really need this for your games, so you can always just pass 0 for this parameter. The third parameter is another advanced option called the
The set_caption() call returns a pygame. object (which we will call objects for short). Objects are values of a data type that have methods as well as data. For example, strings are objects in Python because they have data (the string itself) and methods (such as lower() and split()). You can store objects in variables just like any other value. The object represents the window and we will include the windowSurface variable in all of our calls to drawing functions.
You should know that variables never hold objects (including lists and dictionaries), they only hold references to objects. This is exactly the same way that variables never hold lists but only hold references to lists. The difference between holding the object and holding a reference to the object is that if you copy the variable to a second variable, any changes made to object in one of the variables will also change the object in the other variable. This is because both variables hold references to the same object because only a copy of the reference was made, not a copy of the object.
Here is an example with lists (just like in the Hangman chapter). Type the following into the interactive shell:
>>> x = ['a', 'b', 'c'] >>> y = x >>> x[2] = 'Hello!' >>> print(y) ['a', 'b', 'Hello!']
Notice that changing the x list has also changed the y list, because they both contain references to the same list. y made a copy of the reference in x, not a copy of the list.
The same applies to objects. Consider the following code:
>>> import pygame >>> pygame.init() >>> windowSurface = pygame.display.set_mode((500, 500), 0, 32) >>> secondSurface = windowSurface
windowSurface and secondSurface contain references to the same object. Any changes made to windowSurface will change the same object that secondSurface references. The same is true that any changes to windowSurface will change windowSurface.
11. # set up the colors 12. BLACK = (0, 0, 0) 13. WHITE = (255, 255, 255) 14. RED = (255, 0, 0) 15. GREEN = (0, 255, 0) 16. BLUE = (0, 0, 2 55)
There are three 0 means there is no red in this color, and a value of 255 means there is a maximum amount of red in the color. The second value is for green and the third value is for blue.
For example, we will create the (0, 0, 0) and store it in a variable named BLACK. With no amount of red, green, or blue, the resulting color is completely black. The color black is the absence of any color.
On line 13, we use the (255, 255, 255) for a maximum amount of red, green, and blue to result in white. The color white is the full combination of red, green, and blue. We store this WHITE variable. (255, 0, 0) represents the maximum amount of red but no amount of green and blue, so the resulting color is red. Similarly, (0, 255, 0) is green and (0, 0, 255) is blue.
These variable names are in all capitals because they are BLACK in our code than (0, 0, 0) every time we want to specify the color black, so we set up these color variables at the start of our program.
If you want to make a color lighter, try adding an equal amount from all three values. For example, the RGB value for gray is (128, 128, 128). You can get the RGB value for a lighter gray by adding 20 to each value to get (148, 148, 148). You can get the RGB value for a darker gray by subtracting 20 from each value to get (108, 108, 108). And you can get the RGB value for a slightly redder gray by adding 20 to only the red value to get (148, 128, 128). Table 17.1 has some common colors and their RGB values.
| Color | RGB Values |
|---|---|
| Aqua | (0, 255, 255) |
| Black | (0, 0, 0) |
| Blue | (0, 0, 255) |
| Cornflower Blue | (100, 149, 237) |
| Fuchsia | (255, 0, 255) |
| Gray | (128, 128, 128) |
| Green | (0, 128, 0) |
| Lime | (0, 255, 0) |
| Maroon | (128, 0, 0) |
| Navy Blue | (0, 0, 128) |
| Olive | (128, 128, 0) |
| Purple | (128, 0, 128) |
| Red | (255, 0, 0) |
| Silver | (192, 192, 192) |
| Teal | (0, 128, 128) |
| White | (255, 255, 255) |
| Yellow | (255, 255, 0) |
18. # set up fonts 19. basicFont = pygame.font.SysFont(None, 48)
(рис 17.3) Examples of different fonts.
A font is a complete set of letters, numbers, symbols, and characters of a single style. Here is an example of the same
In our earlier games, we only told Python to print out text. The color, size, and font that was used to display this text was completely determined by whatever font your operating system uses for console windows. Our programs could not change the font at all. However, since we will be drawing out letters to a GUI window we need to tell Pygame exactly what font to use when drawing the text.
On line 19 we create a pygame.font.Font object (which we will just call Font objects for short) by calling the pygame.font.SysFont() function. The first parameter is the name of the font, but we will pass the None value to use the default
21. # set up the text
22. text = basicFont.render('Hello world!', True, WHITE, BLUE)
23. textRect = text.get_rect()
The Font object that we have stored in the basicFont variable has a render(). This method will create a object with the text drawn on it. The first parameter to render() is the string of the text to draw. The second parameter is a boolean for whether or not we want anti-aliasing. Anti-aliasing is a technique for making a drawing look less True to say we want to use anti-aliasing. Figure 17.4 is an example of what a line (when we
Anti-aliasing can make your text and lines look blurry but smoother. It takes a little more computation time to do anti-aliasing, so although the graphics may look better, your program may run slower (but only just a little).
(рис 17.4) An aliased line and an anti-aliased line.
24. textRect.centerx = windowSurface.get_rect().centerx 25. textRect.centery = windowSurface.get_rect().centery
The pygame.Rect data type (which we will just call Rect for short) makes working with rectangle-shaped things easy. To create a new Rect object call the function pygame.Rect(). The parameters are integers for the XY coordinates of the top left corner, followed by the width and height. These integers are in number of pixels.
The function name with the parameters looks like this: pygame.Rect(left, top, width, height)
Just like methods are functions that are associated with an object, attributes are variables that are associated with an object. The Rect data type (that is, the data type of all Rect objects) has many attributes that describe the rectangle they represent. Here is a list of attributes of a Rect object named myRect:
| pygame.Rect Attribute | Description |
|---|---|
myRect.left
| The int value of the X-coordinate of the left side of the rectangle. |
myRect.right
| The int value of the X-coordinate of the right side of the rectangle. |
myRect.top
| The int value of the Y-coordinate of the |
myRect.bottom
| The int value of the Y-coordinate of the bottom side of the rectangle. |
myRect.centerx
| The int value of the X-coordinate of the center of the rectangle. |
myRect.centery
| The int value of the Y-coordinate of the center of the rectangle. |
myRect.width
| The int value of the width of the rectangle. |
myRect.height
| The int value of the height of the rectangle. |
myRect.size
| A |
myRect.topleft
| A |
myRect.topright
| A |
myRect.bottomleft
| A |
myRect.bottomright
| A |
myRect.midleft
| A |
myRect.midright
| A |
myRect.midtop
| A |
myRect.midbottom
| A |
The great thing about Rect objects is that if you modify any of these variables, all the other variables will automatically modify themselves as well. For example, if you create a Rect object that is 20 pixels wide and 20 pixels high, and has the top left corner at the coordinates (30, 40), then the X-coordinate of the right side will automatically be set to 50 (because 20 + 30 = 50). However, if you change the left attribute with the line myRect.left = 100, then Pygame will automatically change the right attribute to 120 (because 20 + 100 = 120). Every other attribute for that Rect object will also be updated as well.
Notice that both the Font object (stored in the text variable) and the object (stored in windowSurface variable) both have a get_rect(). Technically, these are two different methods. But the programmers of Pygame gave them the same name because they both do the same thing and return Rect objects that represent the size and position of the Font or object.
Also, remember that pygame is a module that we import, and inside the pygame module are the font and modules. Inside those modules are the Font and data types. The Pygame programmers made the modules begin with a
We create a pygame.Rect object by calling a function named pygame.Rect(). The pygame.Rect() function has the same name as the pygame.Rect data type.
Functions that have the same name as their data type and create objects or values of this data type are called constructor functions
The int() and str() functions are also constructor functions. The int() function returns an int version of whatever you pass it, whether it is int(5) or int('5'). (The str.)
You can always find out what the type() function. For example, try typing the following into the interactive shell:
>>> type('This is a string')
<type 'str'>
>>> type(5)
<type 'int'>
>>> spam = 'Another string'
>>> type(spam)
<type 'str'>
>>> import pygame
>>> pygame.init()
>>> myRect = pygame.Rect(10, 10, 40, 50)
>>> type(myRect)
<type 'pygame.Rect'>
>>> pygame.quit()
(You need to call the pygame.quit() function when you are done with typing Pygame functions into the interactive shell. Otherwise you may cause Python to type() function is not a string, but a value of a data type called "type"!
Try typing this into the interactive shell:
>>> type(type('This is a string')) I
<type 'type'> I
For the most part, you don't need to know about data types and the type() function when programming games. But it can be very useful if you need to find out the data type of the value stored in a variable in your program.
27. # draw the white background onto the surface 28. windowSurface.fill(WHITE)
This is the first drawing windowSurface with the color white. The fill() function will completely cover the entire BLACK to make the background black.)
An important thing to know about Pygame is that the window on the screen will not change when we call the fill() method or any of the other drawing functions. These will draw on the object, but the object will not be drawn on the user's screen until the pygame.display.update() function is called. This is because drawing on the object (which is stored in the computer's memory) is much faster than drawing to the computer screen. It is much more
30. # draw a green polygon onto the surface 31. pygame.draw.polygon(windowSurface, GREEN, ((146, 0), (291, 106), (236, 277), (56, 277), (0, 106)))
A polygon is any multisided shape with sides that are only straight lines. The pygame.draw.polygon() function can draw any shape that you give it and fill the inside space of the polygon. The
(рис 17.5) Examples of Polygons.
Polygons only have straight lines for sides (circles and ellipses are not polygons). Figure 17.5 has some examples of polygons.
33. # draw some blue lines onto the surface 34. pygame.draw.line(windowSurface, BLUE, (60, 60), (120, 60), 4) 35. pygame.draw.line(windowSurface, BLUE, (12 0, 60), (60, 120) ) 36. pygame.draw.line(windowSurface, BLUE, (60, 120), (12 0, 120), 4)
The pygame.draw.line() function will draw a line on the object that you provide. Notice that the last parameter (the width of the line) is optional. If you pass 4 for the width, the line will be four pixels thick. If you do not specify the width parameter it will take on the default value of 1.
38. # draw a blue circle onto the surface 39. pygame.draw.circle(windowSurface, BLUE, (300, 50), 20, 0)
The pygame.draw.circle() function will draw a circle on the object you provide. The third parameter is for the X and Y coordinates of the center of the circle as a int for the radius (that is, size) of the circle in pixels. A width of 0 means that the circle will be filled in.
41. # draw a red ellipse onto the surface 42. pygame.draw.ellipse(windowSurface, RED, (300, 250, 40, 80), 1)
The pygame.draw.ellipse() function will draw an ellipse. It is similar to the pygame.draw.circle() function, except that instead of specifying the center of the circle, a
44. # draw the text's background rectangle onto the surface 45. pygame.draw.rect(windowSurface, RED, (textRect.left - 20, textRect.top - 20, textRect.width + 40, textRect.height + 40) )
The pygame.draw.rect() function will draw a rectangle. The third parameter is a Rect object. In line 45, we want the rectangle we draw to be 20 pixels around all the sides of the text. This is why we want the drawn rectangle's left and top to be the left and top of textRect minus 20. (Remember, we subtract because coordinates textRect plus 40 (because the left and top were moved back 20 pixels, so we need to make up for that space).
47. # get a pixel array of the surface 48. pixArray = pygame.PixelArray(windowSurface) 49. pixArray[480] [380] = BLACK
On line 48 we create a pygame.PixelArray object (which we will just call a PixelArray object for short). The PixelArray object is a list of lists of color object you passed it. We passed windowSurface object when we called the PixelArray() constructor function on line 48, so assigning BLACK to pixArray[480][380] will change the pixel at the coordinates (480, 380) to be a black pixel. Pygame will automatically modify the windowSurface object with this change.
The first index in the PixelArray object is for the X-coordinate. The second index is for the Y-coordinate. PixelArray objects make it easy to set PixelArray object to a specific color.
50. del pixArray
Creating a PixelArray object from a object will lock that object. Locked means that no object. To unlock the object, you must delete the PixelArray object with the del operator. If you forget to delete the object, you will get an error message that says pygame..
52. # draw the text onto the surface 53. windowSurface.blit(text, textRect)
The method will draw the contents of one object onto another object. Line 54 will draw the "Hello world!" text (which was drawn on the object stored in the text variable) and draws it to the object stored in the windowSurface variable.
Remember that the text object had the "Hello world!" text drawn on it on line 22 by the render() method. objects are just stored in the computer's memory (like any other variable) and not drawn on the screen. The object in windowSurface is drawn on the screen (when we call the pygame.display.update() function on line 56 below) because this was the object created by the pygame.display.set_mode() function.
The second parameter to specifies where on the windowSurface text Rect object we got from calling text.get_rect() (which was stored in textRect on line 23).
55. # draw the window onto the screen 56. pygame.display.update()
In Pygame, nothing is drawn to the screen until the pygame.display.update() function is called. This is done because drawing to the screen is a slow operation for the computer compared to drawing on the objects while they are in memory. You do not want to draw to the screen after each drawing function is called, but only draw the screen once after all the drawing functions have been called.
You will need to call pygame.display.update() each time you want to update the screen to display the contents of the object returned by pygame.display.set_mode(). (In this program, that object is the one stored in windowSurface.) This will become more important in our next program which covers animation.
In our previous games, all of the programs print out everything immediately until they reach a input()
The game loop is a loop that constantly checks for new events, updates the state of the window, and draws the window on the screen. Events are values of the pygame.event.Event data type that are generated by Pygame whenever the user presses a key, clicks or moves the mouse, or makes some other event occur. Calling pygame.event.get() retrieves any new pygame.event.Event objects that have been generated since the last call to pygame.event.get().
58. # run the game loop 59. while True:
This is the start of our game loop. The condition for the while statement is set to True so that we loop forever. The only time we exit the loop is if an event causes the program to terminate.
60. for event in pygame.event.get(): 61. if event.type == QUIT:
The pygame.event.get() function returns a list of pygame.event.Event objects. This list has every single event that has occurred since the last time pygame.event.get() was called. All pygame.event.Event objects have an attribute called type which tell us what type of event it is. (A list of event types is given in the next chapter. In this chapter we only deal with the QUIT event.)
Pygame comes supplied with its own pygame.locals module. Remember that we have imported the pygame.locals module with the line from pygame.locals import *, which means we do not have to type pygame.locals in front of the variables and functions in that module.
On line 60 we set up a for loop to check each pygame.event.Event object in the list returned by pygame.event.get(). If the type attribute of the event is equal to the value of the QUIT (which is provided by the pygame.locals module), then we know the user has closed the window and wants to terminate the program.
Pygame generates the QUIT event when the user clicks on the X button at the top right of the program's window. It is also generated if the computer is shutting down and tries to terminate all the programs running. For whatever reason the QUIT event was generated, we know that we should run any code that we want to happen to stop the program. You could choose to ignore the QUIT event entirely, but that may cause the program to be confusing to the user.
62. pygame.quit() 63. sys.exit()
If the QUIT event has been generated, then we can know that the user has tried to close the window. In that case, we should call the exit functions for both Pygame (pygame.quit() ) and Python (sys.exit() ).
This has been the simple "Hello world!" program from Pygame. We've covered many new topics that we didn't have to deal with in our previous games. Even though they are more complicated, the Pygame programs can also be much more fun and engaging than our previous text games. Let's learn how to create games with
In this program we have several different blocks
Type the following program into the file editor and save it as animation.py. You can also download this source code from http://inventwithpython.com/chapter17.
animation.py
This code can be downloaded from http://inventwithpython.com/animation.py
If you get errors after typing this code in, compare it to the book's code with the online
diff tool at http://inventwithpython.com/diff or email the author at
al@inventwithpython.com
1. import pygame, sys, time
2. from pygame.locals import * 3 .
4. # set up pygame
5. pygame.init() 6 .
7. # set up the window
8. WINDOWWIDTH = 400
9. WINDOWHEIGHT = 400
10. windowSurface = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT), 0, 32)
11. pygame.display.set_caption('Animation')
12.
13. # set up direction variables
14. DOWNLEFT = 1
15. DOWNRIGHT = 3
16. UPLEFT = 7
17. UPRIGHT = 9 18.
19. MOVESPEED = 4 20.
21. # set up the colors
22. BLACK = (0, 0, 0)
23. RED = (255, 0, 0)
24. GREEN = (0, 255, 0)
25. BLUE = (0, 0, 255)
26.
27. # set up the block data structure
28. b1 = {'rect':pygame.Rect(300, 80, 50, 100), 'color':RED, 'dir':UPRIGHT}
29. b2 = {'rect':pygame.Rect(200, 200, 20, 20), 'color':GREEN, 'dir':UPLEFT}
30. b3 = {'rect':pygame.Rect(100, 150, 60, 60), 'color':BLUE, 'dir':DOWNLEFT}
31. blocks = [b1, b2, b3] 32.
33. # run the game loop
34. while True:
35. # check for the QUIT event
36. for event in pygame.event.get():
37. if event.type == QUIT:
38. pygame.quit()
39. sys.exit() 40.
41. # draw the black background onto the surface
42. windowSurface.fill(BLACK)
43.
44. for b in blocks:
45. # move the block data structure
46. if b['dir'] == DOWNLEFT:
47. b['rect'].left -= MOVESPEED
48. b['rect'].top += MOVESPEED
49. if b['dir'] == DOWNRIGHT:
50. b['rect'].left += MOVESPEED
51. b['rect'].top += MOVESPEED
52. if b['dir'] == UPLEFT:
53. b['rect'].left -= MOVESPEED
54. b['rect'].top -= MOVESPEED
55. if b['dir'] == UPRIGHT:
56. b['rect'].left += MOVESPEED
57. b['rect'].top -= MOVESPEED
58.
59. # check if the block has move out of the window
60. if b ['rect'] .top < 0:
61. # block has moved past the top
62. if b['dir'] == UPLEFT:
63. b['dir'] = DOWNLEFT
64. if b['dir'] == UPRIGHT:
65. b['dir'] = DOWNRIGHT
66. if b [ 'rect'] .bottom > WINDOWHEIGHT:
67. # block has moved past the bottom
68. if b['dir'] == DOWNLEFT:
69. b['dir'] = UPLEFT
70. if b['dir'] == DOWNRIGHT:
71. b['dir'] = UPRIGHT
72. if b ['rect'] .left < 0:
73 . # block has moved past the left side
74. if b['dir'] == DOWNLEFT:
75. b['dir'] = DOWNRIGHT
76. if b['dir'] == UPLEFT:
77. b['dir'] = UPRIGHT
78. if b [ 'rect'] .right > WINDOWWIDTH:
79. # block has moved past the right side
80. if b['dir'] == DOWNRIGHT:
81. b['dir'] = DOWNLEFT
82. if b['dir'] == UPRIGHT:
83. b['dir'] = UPLEFT 84 .
85. # draw the block onto the surface
86. pygame.draw.rect(windowSurface, b['color'], b ['rect' ])
87 .
88. # draw the window onto the screen
89. pygame.display.update()
90. time.sleep(0.02)
(рис 17.6) The Animation program.
In this program, we will have three different colored
Each block will move in one of four
The new direction that a block moves after it bounces depends on two things: which direction it was moving before the
We can represent the blocks with a Rect object to represent the position and size of the block, a Rect object. Also in each iteration we will draw all the blocks on the screen at their
(рис 17.7) The diagram of how blocks will bounce.
1. import pygame, sys, time
In this program, we also want to import the time module.
7. # set up the window 8. WINDOWWIDTH = 400 9. WINDOWHEIGHT = 400 10. windowSurface = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT), 0, 32)
In this program the size of the window's width and height is used for more than just the call to set_mode(). We will use a
If we did not use the 400. If any unrelated values in the program were also 400, we might think it was for the width or height and also accidentally change it too. This would put a bug in our program. Since the window width and height never change during the program's execution, a
11. pygame.display.set_caption('Animation')
For this program, we will set the caption at the top of the window to 'Animation' with a call to pygame.display.set_caption().
13. Setting Up Constant Variables for Direction 14. # set up direction variables 15. DOWNLEFT = 1 16. DOWNRIGHT = 3 17. UPLEFT = 7 18. UPRIGHT = 9
We will use the keys on the number pad of the keyboard to remind us which belongs to which direction. This will be similar to our 1 is down and left, 3 is down and right, 7 is up and left, and 'Animation' 9 is up and right. However, it may be hard to remember this, so instead we will use
We could use any values we wanted to for these directions, as long as we had different values for each direction. For example, we could use the string 'downleft' to represent the down and left 'downleft' string (for example, as 'fownleft'), the computer would not 'downleft' instead of 'fownleft'. This bug would cause our program to behave strangely.
But if we use FOWNLEFT instead of the name DOWNLEFT, Python would notice that there is no such variable named FOWNLEFT and
19. MOVESPEED = 4
We will use a
21. # set up the colors 22. BLACK = (0, 0, 0) 23. RED = (255, 0, 0) 24. GREEN = (0, 255, 0) 25. BLUE = (0, 0, 2 55)
We set up 0 to 255. Unlike our "Hello World" program, this program doesn't use the white color, so we left it out.
Again, the use of GREEN for the color green. But if we later look at this program, it is easier to know that GREEN stands for the color green rather than a bunch of int values in a
27. # set up the block data structure
28. b1 = {'rect' :pygame.Rect(300 , 80, 50, 100), 'color' :RED, 'dir':UPRIGHT}
We will set up a dictionary to be the 'rect' (with a Rect object for a value), 'color' (with a 'dir' (with one of our direction
We will store one of these b1. This block will have its top left corner located at an X-coordinate of 300 and Y-coordinate of 80. It will have a width of 50 pixels and a height of 100 pixels. Its color will be red (so we'll use our RED (255, 0, 0) stored in it). And its direction will be set to UPRIGHT.
29. b2 = {'rect':pygame.Rect(200, 200, 20, 20), 'color':GREEN, 'dir':UPLEFT}
30. b3 = {'rect':pygame.Rect(10 0, 150, 60, 60), 'color':BLUE, 'dir':DOWNLEFT}
Here we create two more similar
31. blocks = [b1, b2, b3]
On line 31 we put all of these rectangles.
rectangles is a list. rectangles[0] would be the dictionary r1. rectangles[0]['color'] would be the 'color' key in r1 (which we stored the value in RED in), so the expression rectangles[0]['color'] would evaluate to (255, 0, 0). In this way we can refer to any of the values in any of the block rectangles.
33 . # run the game loop 34. while True:
Inside the game loop, we want to move all of the blocks around the screen in the direction that they are going, then windowSurface
pygame.display.update() to draw the pygame.event.get() to check if the QUIT event has been generated by the user closing the window.
The for loop to check all of the events in the list returned by pygame.event.get() is the same as in our "Hello World!" program, so we will skip its
41. # draw the black background onto the surface 42. windowSurface.fill(BLACK)
Before we draw any of the blocks on the windowSurface
44. for b in blocks:
We want to update the position of each block, so we must loop through the rectangles list and perform the same code on each block's
45. # move the block data structure 46. if b['dir'] == DOWNLEFT: 47. b['rect'].left -= MOVESPEED 48. b [ 'rect'] .top += MOVESPEED 49. if b['dir'] == DOWNRIGHT: 50. b['rect'].left += MOVESPEED 51. b [ 'rect'] .top += MOVESPEED 52. if b['dir'] == UPLEFT: 53. b['rect'].left -= MOVESPEED 54. b [ 'rect'] .top -= MOVESPEED 55. if b['dir'] == UPRIGHT: 56. b ['rect'] .left += MOVESPEED 57. b['rect'].top -= MOVESPEED
The new value that we want to set the left and top attributes to depends on the direction the block is moving. Remember that the X-coordinates start at 0 on the very left edge of the window, and increase as you go right. The Y-coordinates start at 0 on the very top of the window, and increase as you go down. So if the direction of the block (which, remember, is stored in the 'dir' key) is either DOWNLEFT or DOWNRIGHT, we want to increase the top attribute. If the direction is UPLEFT or UPRIGHT, we want to top attribute.
If the direction of the block is DOWNRIGHT or UPRIGHT, we want to increase the left attribute. If the direction is DOWNLEFT or UPLEFT, we want to decrease the left attribute.
We could have also modified right instead of the left attribute, or the bottom attribute instead of the top attribute, because Pygame will update the Rect object either way. Either way, we want to change the value of these attributes by the integer stored in MOVESPEED, which stores how many pixels over we will move the block.
59. # check if the block has move out of the window 60. if b ['rect'] .top < 0: 61. # block has moved past the top 62. if b['dir'] == UPLEFT: 63. b['dir'] = DOWNLEFT 64. if b['dir'] == UPRIGHT: 65. b['dir'] = DOWNRIGHT
After we have moved the block, we want to check if the block has gone past the edge of the window. If it has, we want to "'dir' key. When the direction is set, the block will move in the new direction on the next iteration of the game loop.
We need to check if the block has moved passed each of the four edges of the window. In the above if statement, we decide the block has moved past the top edge of the window if the block's Rect object's top attribute is less than 0. If it is, then we need to change the direction based on what direction the block was moving.
Look at the UPLEFT or UPRIGHT directions. If the block was moving in the UPLEFT direction, the new direction (according to our DOWNLEFT. If the block was moving in the UPRIGHT direction, the new direction will be DOWNRIGHT.
66. if b['rect'].bottom > WINDOWHEIGHT: 67. # block has moved past the bottom 68. if b['dir'] == DOWNLEFT: 69. b['dir'] = UPLEFT 70. if b['dir'] == DOWNRIGHT: 71. b['dir'] = UPRIGHT
Here we see if the block has moved past the bottom edge of the window by checking if the bottom attribute (not the top attribute) is greater than the value in WINDOWHEIGHT. Remember that the Y-coordinates start at 0 at the top of the window and increase to WINDOWHEIGHT because we passed WINDOWHEIGHT as the height in our call to pygame.display.set_mode().
The rest of the code changes the direction based on what our
72. if b ['rect'] .left < 0: 73. # block has moved past the left side 74. if b['dir'] == DOWNLEFT: 75. b['dir'] = DOWNRIGHT 76. if b['dir'] == UPLEFT: 77. b['dir'] = UPRIGHT
This is similar to the above code, but checks if the left side of the block has moved to the left of the left edge of the window. Remember, the X-coordinates start at 0 on the left edge of the window and increase to WINDOWWIDTH on the right edge of the window.
78. if b [ 'rect'] .right > WINDOWWIDTH: 79. # block has moved past the right side 80. if b['dir'] == DOWNRIGHT: 81. b['dir'] = DOWNLEFT 82. if b['dir'] == UPRIGHT: 83. b['dir'] = UPLEFT
This code is similar to the previous pieces of code, but it checks if the block has moved past the
85. # draw the block onto the surface 86. pygame.draw.rect(windowSurface, b['color'], b ['rect' ])
Now that we have moved the block (and set a new direction if the block has windowSurface pygame.draw.rect() function. We pass windowSurface, because that is the object we want to draw on. We pass the b['color'] value, because this is the color we want to use. Then we pass b['rect'], because that Rect object has the information about the position and size of the rectangle we want to draw.
This is the last line of the for loop. We want to run the moving,
88. # draw the window onto the screen 89. pygame.display.update() 90. time.sleep(0.02)
After we have run this code on each of the blocks in the blocks list, we want to finally call pygame.display.update() so that the windowSurface QUIT event has been generated by the Pygame library (which happens if the player closes the window or shuts down their computer). In that case we terminate the program.
The call to the time.sleep() function is there because the computer can move, time.sleep(0.02) line and running the program to see this.) This call to time.sleep() will stop the program for 20
Just for fun, let's make some small # in front of line 90 (the time.sleep(0.2) line) of our animation program. This will cause Python to ignore this line because it is now a comment. Now try running the program.
Without the time.sleep()
Remove the # from the front of line 90 so that the line is no longer a comment and becomes part of the program again. This time, comment out line 42 (the windowSurface.fill(BLACK) line) by adding a # to the front of the line. Now run the program.
Without the call to windowSurface.fill(BLACK), we do not black out the entire window before drawing the rectangles in their new position. This will cause trails of rectangles to appear on the screen instead of
Remember that the blocks are not really moving. We are just redrawing the entire window over and over again. On each iteration through the game loop, we redraw the entire window with new blocks that are located a few pixels over each time. When the program runs very fast, we make it is just one block each time. In order to see that we are just redrawing the blocks over and over again, change line 90 to time.sleep(1.0). This will make the program (and the drawing) fifty times slower than normal. You will see each drawing being replaced by the next drawing every second.
This chapter has presented a whole new way of creating drawBoard() function to be displayed on the screen. Our animation program is very similar. The blocks variable held a list of
But without calls to input(), how do we get input from the player? In our next chapter, we will cover how our program can know when the player presses any key on the keyboard. We will also learn of a concept called
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.