Skip to main content
Engineering LibreTexts

9.24: Collision Detection- Eat or Be Eaten

  • Page ID
    14643
    \( \newcommand{\vecs}[1]{\overset { \scriptstyle \rightharpoonup} {\mathbf{#1}} } \) \( \newcommand{\vecd}[1]{\overset{-\!-\!\rightharpoonup}{\vphantom{a}\smash {#1}}} \)\(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\) \(\newcommand{\id}{\mathrm{id}}\) \( \newcommand{\Span}{\mathrm{span}}\) \( \newcommand{\kernel}{\mathrm{null}\,}\) \( \newcommand{\range}{\mathrm{range}\,}\) \( \newcommand{\RealPart}{\mathrm{Re}}\) \( \newcommand{\ImaginaryPart}{\mathrm{Im}}\) \( \newcommand{\Argument}{\mathrm{Arg}}\) \( \newcommand{\norm}[1]{\| #1 \|}\) \( \newcommand{\inner}[2]{\langle #1, #2 \rangle}\) \( \newcommand{\Span}{\mathrm{span}}\)\(\newcommand{\AA}{\unicode[.8,0]{x212B}}\)

                # check if the player has collided with any squirrels
                for i in range(len(squirrelObjs)-1, -1, -1):
                    sqObj = squirrelObjs[i]
                    if 'rect' in sqObj and playerObj['rect'].colliderect(sqObj['rect']):
                        # a player/squirrel collision has occurred
    
                        if sqObj['width'] * sqObj['height'] <= playerObj['size']**2:
                            # player is larger and eats the squirrel
                            playerObj['size'] += int( (sqObj['width'] * sqObj['height'])**0.2 ) + 1
                            del squirrelObjs[i]
    
                            if playerObj['facing'] == LEFT:
                                playerObj['surface'] = pygame.transform.scale(L_SQUIR_IMG, (playerObj['size'], playerObj['size']))
                            if playerObj['facing'] == RIGHT:
                                playerObj['surface'] = pygame.transform.scale(R_SQUIR_IMG, (playerObj['size'], playerObj['size']))
    
                            if playerObj['size'] > WINSIZE:
                                winMode = True # turn on "win mode"
    
                        elif not invulnerableMode:
                            # player is smaller and takes damage
                            invulnerableMode = True
                            invulnerableStartTime = time.time()
                            playerObj['health'] -= 1
                            if playerObj['health'] == 0:
                                gameOverMode = True # turn on "game over mode"
                                gameOverStartTime = time.time()
    

    The for loop on 2 [273] will go run code on each of the enemy squirrel game objects in squirrelObjs. Notice that the parameters to range() on line 2 [273] start at the last index of squirrelObjs and decrement. This is because the code inside this for loop may end up deleting some of these enemy squirrel game objects (if the player’s squirrel ends up eating them), so it is important to iterate from the end down to the front. The reason why was explained previously in the "When Deleting Items in a List, Iterate Over the List in Reverse" section.

    If the player’s squirrel is equal or larger than the size of the enemy squirrel it has collided with, then the player’s squirrel will eat that squirrel and grow. The number that is added to the 'size' key in the player object (that is, the growth) is calculated based on the enemy squirrel’s size on line 9 [280]. Here’s a graph showing the growth from different sized squirrels. Notice that larger squirrels cause more growth:

    Figure 47

    So, according to the chart, eating a squirrel that has a width and height of 45 (that is, an area of 1600 pixels) would cause the player to grow 5 pixels wider and taller.

    Line 10 [281] deletes the eaten squirrel object from the squirrelObjs list so that it will no longer appear on the screen or have its position updated.

    The player’s squirrel image needs to be updated now that the squirrel is larger. This can be done by passing the original squirrel image in L_SQUIR_IMG or R_SQUIR_IMG to the pygame.transform.scale() function, which will return an enlarged version of the image. Depending on whether playerObj['facing'] is equal to LEFT or RIGHT determines which original squirrel image we pass to the function.

    The way the player wins the game is by getting the squirrel to have a size larger than the integer stored in the WINSIZE constant variable. If this is true, then the winMode variable is set to True. Code in the other parts of this function will handle displaying the congratulations text and checking for the player to press the R key to restart the game.

    If the player’s area was not equal to or larger than the area of the enemy squirrel, and invulnerableMode was not set to True, then the player will take damage from colliding with this larger squirrel.

    To prevent the player from being damaged several times by the same squirrel immediately, we will briefly make the player invulnerable to further squirrel attacks by setting invulnerableMode to True on line 22 [293]. Line 23 [294] will set invulnerableStartTime to the current time (which is returned by time.time()) so that lines 133 and 134 can know when to set invulnerableMode to False.

    Line 24 [295] decrements the player’s health by 1. Because there is a chance that the player’s health is now at 0, line 25 [296] checks for this and, if so, sets gameOverMode to True and gameOverStartTime to the current time.


    This page titled 9.24: Collision Detection- Eat or Be Eaten is shared under a CC BY-NC-SA 3.0 license and was authored, remixed, and/or curated by Al Sweigart via source content that was edited to the style and standards of the LibreTexts platform; a detailed edit history is available upon request.