Опубликован: 12.07.2013 | Доступ: свободный | Студентов: 978 / 36 | Длительность: 37:41:00
Лекция 17:

Graphics and Animation

< Лекция 16 || Лекция 17: 12345 || Лекция 18 >

The pygame.draw.line() Function

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 Surface 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.

The pygame.draw.circle() Function

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 Surface object you provide. The third parameter is for the X and Y coordinates of the center of the circle as a tuple of two ints. The fourth parameter is an int for the radius (that is, size) of the circle in pixels. A width of 0 means that the circle will be filled in.

The pygame.draw.ellipse() Function

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 tuple of four ints is passed for the left, top, width, and height of the ellipse.

The pygame.draw.rect() Function

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 tuple of four ints for the left, top, width, and height of the rectangle. Instead of a tuple of four ints for the third parameter, you can also pass 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 decrease as you go left and up.) And the width and height will be equal to the width and height of the textRect plus 40 (because the left and top were moved back 20 pixels, so we need to make up for that space).

The pygame. Pixel Array Data Type

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 tuples that represents the Surface 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 individual pixels on a PixelArray object to a specific color.

50. del pixArray

Creating a PixelArray object from a Surface object will lock that Surface object. Locked means that no blit() function calls (described next) can be made on that Surface object. To unlock the Surface object, you must delete the PixelArray object with the del operator. If you forget to delete the Surface object, you will get an error message that says pygame.error: Surfaces must not be locked during blit.

The blit() Method for Surface Objects

52. # draw the text onto the surface
53. windowSurface.blit(text, textRect)

The blit() method will draw the contents of one Surface object onto another Surface object. Line 54 will draw the "Hello world!" text (which was drawn on the Surface object stored in the text variable) and draws it to the Surface 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. Surface objects are just stored in the computer's memory (like any other variable) and not drawn on the screen. The Surface object in windowSurface is drawn on the screen (when we call the pygame.display.update() function on line 56 below) because this was the Surface object created by the pygame.display.set_mode() function.

The second parameter to blit() specifies where on the windowSurface surface the text surface should be drawn. We will just pass the Rect object we got from calling text.get_rect() (which was stored in textRect on line 23).

The pygame.display.update() Function

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 Surface 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 Surface 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.

Events and the Game Loop

In our previous games, all of the programs print out everything immediately until they reach a input() function call. At that point, the program stops and waits for the user to type something in and press Enter. Pygame programs do not work this way. Instead, Pygame programs are constantly running through a loop called the game loop. (In this program, we execute all the lines of code in the game loop about one hundred times a second.)

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.

The pygame.event.get() Function

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 constant variables in the 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 constant variable 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.

The pygame.quit() Function

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 animated graphics that move.

Animation

In this program we have several different blocks bouncing off of the edges of the window. The blocks are different colors and sizes and move only in diagonal directions. In order to animate the blocks (that is, make them look like they are moving) we will move the blocks a few pixels over on each iteration through the game loop. By drawing new blocks that are located a little bit differently then the blocks before, we can make it look like the blocks are moving around the screen.

The Animation Program's Source Code

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)

The Animation program.

Рис. 17.6. The Animation program.
< Лекция 16 || Лекция 17: 12345 || Лекция 18 >