Россия |
Graphics and Animation
Variables Store References to Objects
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 Surface 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.
Colors in Pygame
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 primary colors of light: red, green and blue. By combining different amounts of these three colors you can form any other color. In Python, we represent colors with tuples of three integers. The first value in the tuple is how much red is in the color. A value of 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 tuple (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 tuple (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 tuple in the 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 constant variables. It's just easier to type 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) |
Fonts, and the pygame.font.SysFont() Function
18. # set up fonts 19. basicFont = pygame.font.SysFont(None, 48)
A font is a complete set of letters, numbers, symbols, and characters of a single style. Here is an example of the same sentence printed in different fonts:
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 system font. The second parameter will be the size of the font. In our call on line 19, we want the font size to be 48 points.
The render() Method for Font Objects
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 method called render(). This method will create a Surface 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 blocky. On line 22, we pass True to say we want to use anti-aliasing. Figure 17.4 is an example of what a line (when we enlarge the individual pixels) looks like with and without anti-aliasing:
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).
Attributes
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:
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.
The get_rect() Methods for pygame.font.Font and pygame.Surface Objects
Notice that both the Font object (stored in the text variable) and the Surface object (stored in windowSurface variable) both have a method called 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 Surface object.
Also, remember that pygame is a module that we import, and inside the pygame module are the font and surface modules. Inside those modules are the Font and Surface data types. The Pygame programmers made the modules begin with a lowercase letter, and the data types begin with an uppercase letter. This makes it easier to distinguish the data types and the modules that the data types can be found in.
Constructor Functions and the type() function.
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 proper name for strings in Python is str.)
You can always find out what the proper name of a value's data type with 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 crash.) Notice that the return value from the 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.
The fill() Method for Surface Objects
27. # draw the white background onto the surface 28. windowSurface.fill(WHITE)
This is the first drawing function call in our program. We want to fill the entire surface stored in windowSurface with the color white. The fill() function will completely cover the entire surface with the color we pass as the parameter. (In this case, we pass 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 Surface object, but the Surface object will not be drawn on the user's screen until the pygame.display.update() function is called. This is because drawing on the Surface object (which is stored in the computer's memory) is much faster than drawing to the computer screen. It is much more efficient to draw onto the screen once and only after all of our drawing functions to draw to the surface.
The pygame.draw.polygon() Function
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 tuple of tuples you pass it represents the XY coordinates of the points to draw in order. The last tuple will automatically connect to the first tuple to complete the shape.
Polygons only have straight lines for sides (circles and ellipses are not polygons). Figure 17.5 has some examples of polygons.