Опубликован: 12.07.2013 | Уровень: специалист | Доступ: платный
Лекция 20:

Dodger

Аннотация: In this chapter, we will use that knowledge to create a graphical game with sound that receives input from the keyboard and mouse.

Topics Covered In This Chapter:

  • The pygame.FULLSCREEN flag
  • Pygame Constant Variables for Keyboard Keys
  • The move_ip() Method for Rect objects
  • The pygame.mouse.set_pos() Function
  • Implementing Cheat Codes in Your Games
  • Modifying the Dodger Game

The last three chapters have gone over the Pygame software library and demonstrated how to use its many features. (You don't need to read those chapters before reading this chapter, though it may make this chapter easier to understand.) In this chapter, we will use that knowledge to create a graphical game with sound that receives input from the keyboard and mouse.

The Dodger game has the player control a small man (which we call the player's character) who must dodge a whole bunch of baddies that fall from the top of the screen. The longer the player can keep dodging the baddies, the higher the score they will get.

Just for fun, we will also add some cheat modes to the game. If the player holds down the "x" key, every baddie's speed will be reduced to a super slow rate. If the player holds down the "z" key, the baddies will reverse their direction and travel up the screen instead of downwards.

Review of the Basic Pygame Data Types

Let's review some of the basic data types used in the Pygame library:

  • pygame.Rect - Rect objects represent a rectangular space's location and size. The location can be determined by the Rect object's topleft attribute (or the topright, bottomleft, and bottomright attributes). These corner attributes are a tuple of integers for the X and Y coordinates. The size can be determined by the width and height attributes, which are integers of how many pixels long or high the rectangle area is. Rect objects have a colliderect() method to check if they are intersecting with another Rect object.
  • pygame.Surface - Surface objects are areas of colored pixels. Surface objects represent a rectangular image, while Rect objects only represent a rectangular space and location. Surface objects have a blit() method that is used to draw the image on one Surface object onto another Surface object. The Surface object returned by the pygame.display.set_mode() function is special because anything drawn on that Surface object will be displayed on the user's screen.
  • Remember that Surface have things drawn on them, but we cannot see this because it only exists in the computer's memory. We can only see a Surface object when it is "blitted" (that is, drawn) on the screen. This is just the same as it is with any other piece of data. If you think about it, you cannot see the string that is stored in a variable until the variable is printed to the screen.
  • pygame.event.Event - The Event data type in the pygame.event module generates Event objects whenever the user provides keyboard, mouse, or another kind of input. The pygame.event.get() function returns a list of Event objects. You can check what type of event the Event object is by checking its type attribute. QUIT, KEYDOWN, and MOUSEBUTTONUP are examples of some event types.
  • pygame.font.Font - The pygame.font module has the Font data type which represent the typeface used for text in Pygame. You can create a Font object by calling the pygame.font.SysFont() constructor function. The arguments to pass are a string of the font name and an integer of the font size, however it is common to pass None for the font name to get the default system font. For example, the common function call to create a Font object is pygame.font.SysFont(None, 48).
  • pygame.time.Clock - The Clock object in the pygame.time module are very helpful for keeping our games from running as fast as possible. (This is often too fast for the player to keep up with the computer, and makes the games not fun.) The Clock object has a tick() method, which we pass how many frames per second (fps) we want the game to run at. The higher the fps, the faster the game runs. Normally we use 40 fps. Notice that the pygame.time module is a different module than the time module which contains the sleep() function.

Type in the following code and save it to a file named dodger.py. This game also requires some other image and sound files which you can download from the URL http://inventwithpython.com/resources.

Dodger's Source Code

You can download this code from the URL http://inventwithpython.com/chapter20.

dodger.py

This code can be downloaded from http://inventwithpython.com/dodger.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, random, sys
2.  from pygame.locals import * 
3.
4. WINDOWWIDTH = 600
5. WINDOWHEIGHT = 600
6. TEXTCOLOR = (255, 255, 255)
7. BACKGROUNDCOLOR = (0, 0, 0)
8. FPS = 40
9. BADDIEMINSIZE = 10
10. BADDIEMAXSIZE = 40
11. BADDIEMINSPEED = 1
12. BADDIEMAXSPEED = 8
13. ADDNEWBADDIERATE = 6
14.  PLAYERMOVERATE = 5 
15.
16. def terminate():
17.     pygame.quit()
18.      sys.exit() 
19.
20. def waitForPlayerToPressKey():
21.     while True:
22.          for event in pygame.event.get():
23.              if event.type == QUIT:
24.                 terminate()
25.              if event.type == KEYDOWN:
26.                  if event.key == K_ESCAPE: # pressing escape quits
27.                     terminate()
28.                 return 
29.
30. def playerHasHitBaddie(playerRect, baddies):
31.      for b in baddies:
32.          if playerRect.colliderect(b['rect']):
33.             return True
34.     return False 
35.
36. def drawText(text, font, surface, x, y):
37.     textobj = font.render(text, 1, TEXTCOLOR)
38.     textrect = textobj.get_rect()
39.     textrect.topleft = (x, y)
40.     surface.blit(textobj, textrect) 41.
42. # set up pygame, the window, and the mouse cursor
43. pygame.init()
44. mainClock = pygame.time.Clock()
45. windowSurface = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
46. pygame.display.set_caption('Dodger')
47. pygame.mouse.set_visible(False) 48.
49. # set up fonts
50. font = pygame.font.SysFont(None, 48) 
51.
52. # set up sounds
53. gameOverSound = pygame.mixer.Sound('gameover.wav')
54. pygame.mixer.music.load('background.mid') 
55.
56. # set up images
57. playerImage = pygame.image.load('player.png')
58. playerRect = playerImage.get_rect()
59. baddieImage = pygame.image.load('baddie.png') 
60.
61. # show the "Start" screen
62. drawText('Dodger', font, windowSurface, (WINDOWWIDTH / 3), (WINDOWHEIGHT / 3))
63. drawText('Press a key to start.', font, windowSurface, (WINDOWWIDTH / 3) - 30, (WINDOWHEIGHT / 3) + 50)
64. pygame.display.update()
65. waitForPlayerToPressKey() 
66.
67.
68. topScore = 0
69. while True:
70.     # set up the start of the game
71.     baddies = []
72.     score = 0
73.     playerRect.topleft = (WINDOWWIDTH / 2, WINDOWHEIGHT -50)
74.     moveLeft = moveRight = moveUp = moveDown = False
75.     reverseCheat = slowCheat = False
76.     baddieAddCounter = 0
77.     pygame.mixer.music.play(-1, 0.0) 78.
79.     while True: # the game loop runs while the game part is playing
80.         score += 1 # increase score 81.
82.         for event in pygame.event.get():
83.             if event.type == QUIT:
84.                 terminate() 85.
86.             if event.type == KEYDOWN:
87.                 if event.key == ord('z'):
88.                     reverseCheat = True
89.                 if event.key == ord('x'):
90.                     slowCheat = True
91.                 if event.key == K_LEFT or event.key == ord ('a'):
92.                     moveRight = False
93.                     moveLeft = True
94.                 if event.key == K_RIGHT or event.key == ord('d'):
95.                     moveLeft = False
96.                     moveRight = True
97.                 if event.key == K_UP or event.key == ord ('w'):
98.                     moveDown = False
99.                     moveUp = True
100.                 if event.key == K_DOWN or event.key == ord ('s'):
101.                     moveUp = False
102.                     moveDown = True 
103.
104.             if event.type == KEYUP:
105.                 if event.key == ord('z'):
106.                     reverseCheat = False
107.                     score = 0
108.                 if event.key == ord('x'):
109.                     slowCheat = False
110.                     score = 0
111.                 if event.key == K_ESCAPE:
112.                         terminate() 113.
114.                 if event.key == K_LEFT or event.key == ord ('a'):
115.                     moveLeft = False
116.                 if event.key == K_RIGHT or event.key == ord('d'):
117.                     moveRight = False
118.                 if event.key == K_UP or event.key == ord ('w'):
119.                     moveUp = False
120.                 if event.key == K_DOWN or event.key == ord ('s'):
121.                     moveDown = False 
122.
123.             if event.type == MOUSEMOTION:
124.                 # If the mouse moves, move the player
where the cursor is. 
125.                                     playerRect.move_ip(event.pos[0] -
playerRect.centerx, event.pos[1] - playerRect.centery) 
126.
127.         # Add new baddies at the top of the screen, if needed.
128.         if not reverseCheat and not slowCheat:
129.             baddieAddCounter += 1
130.         if baddieAddCounter == ADDNEWBADDIERATE:
131.             baddieAddCounter = 0
132.             baddieSize = random.randint(BADDIEMINSIZE, BADDIEMAXSIZE)
133.             newBaddie = {'rect': pygame.Rect (random.randint(0, WINDOWWIDTH-baddieSize), 
                             0 -baddieSize, baddieSize, baddieSize),
134.                         'speed': random.randint (BADDIEMINSPEED, BADDIEMAXSPEED),
135.                         'surface':pygame.transform.scale (baddieImage, (baddieSize, baddieSize)),
136.                         } 
137.
138.                            baddies.append(newBaddie)
139.
140.         # Move the player around.
141.         if moveLeft and playerRect.left > 0:
142.             playerRect.move_ip(-1 * PLAYERMOVERATE, 0)
143.         if moveRight and playerRect.right < WINDOWWIDTH:
144.             playerRect.move_ip(PLAYERMOVERATE, 0)
145.         if moveUp and playerRect.top > 0:
146.             playerRect.move_ip(0, -1 * PLAYERMOVERATE)
147.         if moveDown and playerRect.bottom < WINDOWHEIGHT:
148.             playerRect.move_ip(0, PLAYERMOVERATE) 149.
150.         # Move the mouse cursor to match the player.
151.         pygame.mouse.set_pos(playerRect.centerx, playerRect.centery)
152.
153.         # Move the baddies down.
154.         for b in baddies:
155.             if not reverseCheat and not slowCheat:
156.                 b['rect'].move_ip(0, b['speed'])
157.             elif reverseCheat:
158.                 b['rect'].move_ip(0, -5)
159.             elif slowCheat:
160.                 b['rect'].move_ip(0, 1) 
161.
162.          # Delete baddies that have fallen past the bottom.
163.         for b in baddies[:]:
164.             if b['rect'].top > WINDOWHEIGHT:
165.                 baddies.remove(b) 
166.
167.         # Draw the game world on the window.
168.         windowSurface.fill(BACKGROUNDCOLOR) 
169.
170.         # Draw the score and top score.
171.         drawText('Score: %s' % (score), font, windowSurface, 10, 0)
172.         drawText('Top Score: %s' % (topScore), font, windowSurface, 10, 40)
173.
174.         # Draw the player's rectangle
175.         windowSurface.blit(playerImage, playerRect)
176.
177.           # Draw each baddie
178.           for b in baddies:
179.               windowSurface.blit(b ['surface'] , b ['rect']) 
180.
181.                       pygame.display.update() 182 .
183.           # Check if any of the baddies have hit the player.
184.           if playerHasHitBaddie(playerRect, baddies):
185.               if score > topScore:
186.                   topScore = score # set new top score
187.               break 188 .
189.                       mainClock.tick(FPS) 190 .
191.      # Stop the game and show the "Game Over" screen.
192.      pygame.mixer.music.stop()
193.      gameOverSound.play() 194 .
195.      drawText('GAME OVER', font, windowSurface, (WINDOWWIDTH / 3),  (WINDOWHEIGHT / 3))
196.      drawText('Press a key to play again.', font, windowSurface, (WINDOWWIDTH / 3) - 80, (WINDOWHEIGHT / 3) +   50)
197.      pygame.display.update()
198.      waitForPlayerToPressKey() 
199.
200.      gameOverSound.stop()

When you run this program, the game will look like this:

A screenshot of the Dodger game in action.

Рис. 20.1. A screenshot of the Dodger game in action.
Марат Хасьянов
Марат Хасьянов
Россия
Роман Дрындик
Роман Дрындик
Россия