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

Collision Detection and Input

< Лекция 17 || Лекция 18: 1234 || Лекция 19 >
Аннотация: Keyboard Input and Mouse Input in Pygame.

Topics Covered In This Chapter:

  • Collision Detection
  • Don't Modify a List While Iterating Over It
  • Keyboard Input in Pygame
  • Mouse Input in Pygame

A very common behavior in most graphical games is collision detection. Collision detection is figuring when two things on the screen have touched (that is, collided with) each other. This is used very often in computer games. For example, if the player touches an enemy they may lose health or a game life. Or we may want to know when the player has touched a coin so that they automatically pick it up. Collision detection can help determine if the game character is standing on solid ground, or if there is nothing but empty air underneath them. In our games, collision detection is determining if two rectangles are overlapping each other or not. Our next example program will cover this basic technique.

Later in this chapter, we will look at how our Pygame programs can accept input from the user through the keyboard and the mouse. It's a bit more complicated than calling the input() function like we did for our text programs. But using the keyboard is much more interactive in GUI programs, and using the mouse isn't even possible in our text games. Knowing these two concepts will make our games more advanced and exciting!

The Collision Detection Program's Source Code

Much of this code is similar to the animation program, so we will skip over explaining how to make the bouncer move and bounce off of the walls. (See the animation program in the previous chapter for an explanation of that code.) We will use a list of pygame.Rect objects to represent the food squares. Each pygame.Rect object in the list represents a single food square. On each iteration through the game loop, our program will read each pygame.Rect object in the list and draw a green square on the window. Every forty iterations through the game loop we will add a new pygame.Rect to the list so that the screen constantly has new food squares in it.

The bouncer is represented by a dictionary. The dictionary has a key named 'rect' (whose value is a pygame.Rect object) and a key named 'dir' (whose value is one of the constant direction variables just like we had in last chapter's Animation program). As the bouncer bounces around the window, we check if it collides with any of the food squares. If it does, we delete that food square so that it will no longer be drawn on the screen.

Type the following into a new file and save it as collisionDetection.py. If you don't want to type all of this code, you can download the source from the book's website at http://inventwithpython.com/chapter18.

collisionDetection.py

This code can be downloaded from http://inventwithpython.com/collisionDetection.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, random
2.  from pygame.locals import * 
3.
4. def doRectsOverlap(rect1, rect2):
5.      for a, b in [(rect1, rect2), (rect2, rect1)]:
6.         # Check if a's corners are inside b
7.          if ((isPointInsideRect(a.left, a.top, b)) or
8.              (isPointInsideRect(a.left, a.bottom, b)) or
9.              (isPointInsideRect(a.right, a.top, b)) or
10.              (isPointInsideRect(a.right, a.bottom, b))):
11.             return True
12.
13.     return False
14.
15. def isPointInsideRect(x, y, rect):
16.      if (x > rect.left) and (x < rect.right) and (y > rect.top) and (y < rect.bottom):
17.         return True
18.     else:
19.         return False 20 .
21.
22. # set up pygame
23. pygame.init()
24. mainClock = pygame.time.Clock() 25 .
26. # set up the window
27. WINDOWWIDTH = 400
28. WINDOWHEIGHT = 400
29. windowSurface = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT), 0, 32)
30. pygame.display.set_caption('Collision Detection') 31.
32. # set up direction variables
33. DOWNLEFT = 1
34. DOWNRIGHT = 3
35. UPLEFT = 7
36. UPRIGHT = 9 37.
38. MOVESPEED = 4 39.
40. # set up the colors
41. BLACK = (0, 0, 0)
42. GREEN = (0, 255, 0)
43. WHITE = (255, 255, 255) 44.
45. # set up the bouncer and food data structures
46. foodCounter = 0
47. NEWFOOD = 40
48. FOODSIZE = 20
49. bouncer = {'rect':pygame.Rect(300, 100, 50, 50), 'dir':UPLEFT}
50. foods = []
51. for i in range(20):
52.     foods.append(pygame.Rect(random.randint(0, WINDOWWIDTH - FOODSIZE), 
random.randint(0, WINDOWHEIGHT - FOODSIZE), FOODSIZE, FOODSIZE))
53.
54. # run the game loop
55. while True:
56.     # check for the QUIT event
57.     for event in pygame.event.get():
58.         if event.type == QUIT:
59.             pygame.quit()
60.             sys.exit() 61.
62.     foodCounter += 1
63.     if foodCounter >= NEWFOOD:
64.         # add new food
65.         foodCounter = 0
66.         foods.append(pygame.Rect(random.randint(0, WINDOWWIDTH - FOODSIZE), 
random.randint(0, WINDOWHEIGHT -FOODSIZE), FOODSIZE, FOODSIZE))
67.
68.     # draw the black background onto the surface
69.     windowSurface.fill(BLACK) 70.
71.     # move the bouncer data structure
72.     if bouncer['dir'] == DOWNLEFT:
73.         bouncer['rect'].left -= MOVESPEED
74.         bouncer['rect'].top += MOVESPEED
75.     if bouncer['dir'] == DOWNRIGHT:
76.         bouncer['rect'].left += MOVESPEED
77.         bouncer['rect'].top += MOVESPEED
78.      if bouncer['dir'] == UPLEFT:
79.         bouncer['rect'].left -= MOVESPEED
80.         bouncer['rect'].top -= MOVESPEED
81.      if bouncer['dir'] == UPRIGHT:
82.         bouncer ['rect'] .left += MOVESPEED
83.         bouncer ['rect'] .top -= MOVESPEED 
84.
85.     # check if the bouncer has move out of the window
86.      if bouncer['rect'].top < 0:
87.         # bouncer has moved past the top
88.          if bouncer['dir'] == UPLEFT:
89.             bouncer ['dir'] = DOWNLEFT
90.          if bouncer['dir'] == UPRIGHT:
91.             bouncer['dir'] = DOWNRIGHT
92.       if bouncer ['rect'] .bottom > WINDOWHEIGHT: 
93 .                          # bouncer has moved past the bottom
94.          if bouncer['dir'] == DOWNLEFT:
95.             bouncer ['dir'] = UPLEFT
96.          if bouncer['dir'] == DOWNRIGHT:
97.             bouncer['dir'] = UPRIGHT
98.      if bouncer ['rect'] .left < 0:
99.         # bouncer has moved past the left side
100.          if bouncer['dir'] == DOWNLEFT:
101.             bouncer['dir'] = DOWNRIGHT
102.          if bouncer['dir'] == UPLEFT:
103.             bouncer['dir'] = UPRIGHT
104.      if bouncer['rect'].right > WINDOWWIDTH:
105.         # bouncer has moved past the right side
106.          if bouncer['dir'] == DOWNRIGHT:
107.             bouncer['dir'] = DOWNLEFT
108.          if bouncer['dir'] == UPRIGHT:
109.             bouncer['dir'] = UPLEFT 
110.
111.     # draw the bouncer onto the surface
112.     pygame.draw.rect(windowSurface, WHITE, bouncer ['rect' ])
113.
114.     # check if the bouncer has intersected with any food squares.
115.      for food in foods[: ] :
116.          if doRectsOverlap(bouncer ['rect'] , food) :
117.              foods.remove(food) 118 .
119.     # draw the food
120.      for i in range(len(foods)):
121.         pygame.draw.rect(windowSurface, GREEN, foods[i]) 
122.
123.     # draw the window onto the screen
124.     pygame.display.update()
125.     mainClock.tick(40)

When you run this code, this is what the program looks like. The white square (the bouncer) will bounce around the window, and when it collides with the green squares (the food) will disappear from the screen.

The Collision Detection program.

Рис. 18.1. The Collision Detection program.

Importing the Modules

1.  import pygame, sys, random
2.  from pygame.locals import *

The collision detection program imports the same things as the Animation program in the last chapter, along with the random module.

< Лекция 17 || Лекция 18: 1234 || Лекция 19 >