Опубликован: 06.08.2013 | Доступ: свободный | Студентов: 844 / 15 | Длительность: 27:51:00
Лекция 2:

Pygame basics

< Лекция 1 || Лекция 2: 1234 || Лекция 3 >

Primitive Drawing Functions

Pygame provides several different functions for drawing different shapes onto a surface object. These shapes such as rectangles, circles, ellipses, lines, or individual pixels are often called drawing primitives. Open IDLE’s file editor and type in the following program, and save it as drawing.py.

1. import pygame, sys
2. from pygame.locals import *
4. pygame.init()
6. # set up the window
7. DISPLAYSURF = pygame.display.set_mode((500, 400), 0, 32)
8. pygame.display.set_caption('Drawing')
10. # set up the colors
11. BLACK = (  0,   0,   0)
12. WHITE = (255, 255, 255)
13. RED   = (255,   0,   0)
14. GREEN = (  0, 255,   0)
15. BLUE  = (  0,   0, 255)
17. # draw on the surface object
19. pygame.draw.polygon(DISPLAYSURF, GREEN, ((146, 0), (291, 106), (236, 277),
(56, 277), (0, 106)))
20. pygame.draw.line(DISPLAYSURF, BLUE, (60, 60), (120, 60), 4)
21. pygame.draw.line(DISPLAYSURF, BLUE, (120, 60), (60, 120))
22. pygame.draw.line(DISPLAYSURF, BLUE, (60, 120), (120, 120), 4)
23. pygame.draw.circle(DISPLAYSURF, BLUE, (300, 50), 20, 0)
24. pygame.draw.ellipse(DISPLAYSURF, RED, (300, 250, 40, 80), 1)
25. pygame.draw.rect(DISPLAYSURF, RED, (200, 150, 100, 50))
27. pixObj = pygame.PixelArray(DISPLAYSURF)
28. pixObj[480][380] = BLACK
29. pixObj[482][382] = BLACK
30. pixObj[484][384] = BLACK
31. pixObj[486][386] = BLACK
32. pixObj[488][388] = BLACK
33. del pixObj
35. # run the game loop
36. while True:
37.     for event in pygame.event.get():
38.         if event.type == QUIT:
39.             pygame.quit()
40.             sys.exit()
41.     pygame.display.update()

When this program is run, the following window is displayed until the user closes the window:


Рис. 2.6. Drawing

Notice how we make constant variables for each of the colors. Doing this makes our code more readable, because seeing GREEN in the source code is much easier to understand as representing the color green than (0, 255, 0) is.

The drawing functions are named after the shapes they draw. The parameters you pass these functions tell them which Surface object to draw on, where to draw the shape (and what size), in what color, and how wide to make the lines. You can see how these functions are called in the drawing.py program, but here is a short description of each function:

  • fill(color)– The fill() method is not a function but a method of pygame.Surface objects. It will completely fill in the entire Surface object with whatever color value you pass as for the color parameter.
  • pygame.draw.polygon(surface, color, pointlist, width) – A polygon is shape made up of only flat sides. The surface and color parameters tell the function on what surface to draw the polygon, and what color to make it. The pointlist parameter is a tuple or list of points (that is, tuple or list of two-integer tuples for XY coordinates). The polygon is drawn by drawing lines between each point and the point that comes after it in the tuple. Then a line is drawn from the last point to the first point. You can also pass a list of points instead of a tuple of points. The width parameter is optional. If you leave it out, the polygon that is drawn will be filled in, just like our green polygon on the screen is filled in with color. If you do pass an integer value for the width parameter, only the outline of the polygon will be drawn. The integer represents how many pixels width the polygon’s outline will be. Passing 1 for the width parameter will make a skinny polygon, while passing 4 or 10 or 20 will make thicker polygons. If you pass the integer 0 for the width parameter, the polygon will be filled in (just like if you left the width parameter out entirely). All of the pygame.draw drawing functions have optional width parameters at the end, and they work the same way as pygame.draw.polygon()’s width parameter. Probably a better name for the width parameter would have been thickness, since that parameter controls how thick the lines you draw are.
  • pygame.draw.line(surface, color, start_point, end_point, width) – This function draws a line between the start_point and end_point parameters.
  • pygame.draw.lines(surface, color, closed, pointlist, width) – This function draws a series of lines from one point to the next, much like pygame.draw.polygon(). The only difference is that if you pass False for the closed parameter, there will not be a line from the last point in the pointlist parameter to the first point. If you pass True, then it will draw a line from the last point to the first.
  • pygame.draw.circle(surface, color, center_point, radius, width) – This function draws a circle. The center of the circle is at the center_point parameter. The integer passed for the radius parameter sets the size of the circle. The radius of a circle is the distance from the center to the edge. (The radius of a circle is always half of the diameter.) Passing 20 for the radius parameter will draw a circle that has a radius of 20 pixels.
  • pygame.draw.ellipse(surface, color, bounding_rectangle, width) – This function draws an ellipse (which is like a squashed or stretched circle). This function has all the usual parameters, but in order to tell the function how large and where to draw the ellipse, you must specify the bounding rectangle of the ellipse. A bounding rectangle is the smallest rectangle that can be drawn around a shape. Here’s an example of an ellipse and its bounding rectangle:

    The bounding_rectangle parameter can be a pygame.Rect object or a tuple of four integers. Note that you do not specify the center point for the ellipse like you do for the pygame.draw.circle() function.
  • pygame.draw.rect(surface, color, rectangle_tuple, width) – This function draws a rectangle. The rectangle_tuple is either a tuple of four integers (for the XY coordinates of the top left corner, and the width and height) or a pygame.Rect object can be passed instead. If the rectangle_tuple has the same size for the width and height, a square will be drawn.

pygame.PixelArray Objects

Unfortunately, there isn’t a single function you can call that will set a single pixel to a color (unless you call pygame.draw.line() with the same start and end point). The Pygame framework needs to run some code behind the scenes before and after drawing to a Surface object. If it had to do this for every single pixel you wanted to set, your program would run much slower. (By my quick testing, drawing pixels this way is two or three times slower).

Instead, you should create a pygame.PixelArray object (we’ll call them PixelArray objects for short) of a Surface object and then set individual pixels. Creating a PixelArray object of a Surface object will "lock" the Surface object. While a Surface object is locked, the drawing functions can still be called on it, but it cannot have images like PNG or JPG images drawn on it with the blit() method. (The blit() method is explained later in this chapter).

If you want to see if a Surface object is locked, the get_locked() Surface method will return True if it is locked and False if it is not.

The PixelArray object that is returned from pygame.PixelArray() can have individual pixels set by accessing them with two indexes. For example, line 28’s pixObj[480][380] = BLACK will set the pixel at X coordinate 480 and Y coordinate 380 to be black (remember that the BLACK variable stores the color tuple (0, 0, 0)).

To tell Pygame that you are finished drawing individual pixels, delete the PixelArray object with a del statement. This is what line 33 does. Deleting the PixelArray object will "unlock" the Surface object so that you can once again draw images on it. If you forget to delete the PixelArray object, the next time you try to blit (that is, draw) an image to the Surface the program will raise an error that says, "pygame.error: Surfaces must not be locked during blit".

The pygame.display.update() Function

After you are done calling the drawing functions to make the display Surface object look the way you want, you must call pygame.display.update() to make the display Surface actually appear on the user’s monitor.

The one thing that you must remember is that pygame.display.update() will only make the display Surface (that is, the Surface object that was returned from the call to pygame.display.set_mode()) appear on the screen. If you want the images on other Surface objects to appear on the screen, you must "blit" them (that is, copy them) to the display Surface object with the blit() method (which is explained next in the "Drawing Images" section).


Now that we know how to get the Pygame framework to draw to the screen, let’s learn how to make animated pictures. A game with only still, unmoving images would be fairly dull. (Sales of my game "Look At This Rock" have been disappointing.) Animated images are the result of drawing an image on the screen, then a split second later drawing a slightly different image on the screen. Imagine the program’s window was 6 pixels wide and 1 pixel tall, with all the pixels white except for a black pixel at 4, 0. It would look like this:

Рис. 2.7.

If you changed the window so that 3, 0 was black and 4,0 was white, it would look like this:

Рис. 2.8.

To the user, it looks like the black pixel has "moved" over to the left. If you redrew the window to have the black pixel at 2, 0, it would continue to look like the black pixel is moving left:

Рис. 2.9.

It may look like the black pixel is moving, but this is just an illusion. To the computer, it is just showing three different images that each just happen to have one black pixel. Consider if the three following images were rapidly shown on the screen:

Рис. 2.10.

To the user, it would look like the cat is moving towards the squirrel. But to the computer, they’re just a bunch of pixels. The trick to making believable looking animation is to have your program draw a picture to the window, wait a fraction of a second, and then draw a slightly different picture.

Here is an example program demonstrating a simple animation. Type this code into IDLE’s file editor and save it as catanimation.py. It will also require the image file cat.png to be in the same folder as the catanimation.py file. You can download this image from http://invpy.com/cat.png. This code is available at http://invpy.com/catanimation.py.

1. import pygame, sys
2. from pygame.locals import *
4. pygame.init()
6. FPS = 30 # frames per second setting
7. fpsClock = pygame.time.Clock()
9. # set up the window
10. DISPLAYSURF = pygame.display.set_mode((400, 300), 0, 32)
11. pygame.display.set_caption('Animation')
13. WHITE = (255, 255, 255)
14. catImg = pygame.image.load('cat.png')
15. catx = 10
16. caty = 10
17. direction = 'right'
19. while True: # the main game loop
22.     if direction == 'right':
23.         catx += 5
24.         if catx == 280:
25.             direction = 'down'
26.     elif direction == 'down':
27.         caty += 5
28.         if caty == 220:
29.             direction = 'left'
30.     elif direction == 'left':
31.         catx -= 5
32.         if catx == 10:
33.             direction = 'up'
34.     elif direction == 'up':
35.         caty -= 5
36.         if caty == 10:
37.             direction = 'right'
39.     DISPLAYSURF.blit(catImg, (catx, caty))
41.     for event in pygame.event.get():
42.         if event.type == QUIT:
43.             pygame.quit()
44.             sys.exit()
46.     pygame.display.update()
47.     fpsClock.tick(FPS)

Look at that animated cat go! This program will be much more of a commercial success than my game, "Look At This Rock 2: A Different Rock".

< Лекция 1 || Лекция 2: 1234 || Лекция 3 >
Константин Шилов
Константин Шилов
Павел Лафицкий
Павел Лафицкий