Россия |
Collision Detection and Input
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.
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.