Beispiel #1
0
    def playerThreeUpdate(self):
        """Change the sprite's image and coordinates based on frameCount, if it strikes a wall demo sprite or
        strikes a black home demo sprite.

        Is only to be called if playerNumber is 3.
        """
        if self.animated:
            if self.frameCount == 9:
                playSound("death.wav")
                DemoPlayerSprite.paused = True
                self.image = self.animationFrames[5]
            elif 15 < self.frameCount:
                animationNumber = min(3, (self.frameCount - 14) // 8)
                self.image = self.animationFrames[5 + animationNumber]
        elif DemoPlayerSprite.paused:
            if self.frameCount == 1:
                self.coordinates = (self.coordinates[0] - 18, self.coordinates[1])
            if self.frameCount < 4:
                self.image = self.animationFrames[2]
            elif self.frameCount < 6:
                self.image = self.animationFrames[3]
            elif self.frameCount < 11:
                self.image = self.animationFrames[4]
            elif self.frameCount == 11:
                DemoPlayerSprite.paused = False
                DemoPlayerSprite.facingDirection = c.Directions.RIGHT
                self.coordinates = (self.coordinates[0] + 18, self.coordinates[1])
Beispiel #2
0
    def update(self):
        """Increase frameCount. Depending on frameCount, determine which methods to call if animated is True."""
        self.frameCount += 1
        self.rect = pg.Rect(self.coordinates[0] + 20, self.coordinates[1], 50, 120)
        if self.animated:
            if self.frameCount % 33 // 3 in (0, 4, 6, 8, 10):
                self.image = self.animationFrames[1]
            elif self.frameCount % 33 // 3 in (1, 3, 7):
                self.image = self.animationFrames[2]
            elif self.frameCount % 33 // 3 == 2:
                self.image = self.animationFrames[3]

            else:
                self.image = self.animationFrames[0]
            if 18 < self.frameCount < 30:
                self.image = pg.transform.flip(self.image, True, False)
            elif self.frameCount % 33 == 0:
                self.frameCount = 0
                self.animated = False
            if self.demoNumber == 0:
                self.image = pg.transform.flip(self.image, True, False)
        else:
            self.image = self.animationFrames[0]

        for sprite in c.demoGroup:
            if isinstance(sprite, DemoPlayerSprite) and self.rect.collidepoint(sprite.rect.center) and\
                            not self.animated:
                playSound("bounce_rubber_or_player.wav")
                self.frameCount = sprite.frameCount = 0
                self.animated = True
                sprite.animated = True
Beispiel #3
0
    def checkSonicWaveCollision(self):
        """Check if the sprite is currently colliding with a sonic wave sprite, and change its state and color if
        so.

        The urchin's animation count is set to 0 if it is hit by a sonic wave sprite to reset the amount of time
        that it has spent being stunned.
        If the urchin is in any 'inactive' states, this method is ignored.
        """
        if self.enemyState not in [
                c.EnemyStates.EXPLODING, c.EnemyStates.OFF_SCREEN
        ]:
            if any(
                    wave.rect.collidepoint(self.rect.center)
                    for wave in c.attackGroup):
                self.audioCount += 1
                if self.audioCount % 4 == 0:
                    playSound("push_or_shoot_enemy.wav")
                self.color = c.YELLOW
                if self.enemyState == c.EnemyStates.BALL:
                    key = "ball"
                    index = 1
                elif self.enemyState == c.EnemyStates.SMALL_BALL:
                    key = "ball"
                    index = 0
                else:
                    key = "move"
                    index = 0
                self.changeImage(key, index)
                self.frameCount = self.animationCount = 0
Beispiel #4
0
    def collectItem(self):
        """Increase frameCount. Depending on frameCount, collectItem has different effects.

        On the first frame, it sets the UrchinSprite class variable isFrozen to True, sets the instance variable
        isFrozen for every other player sprite to True, and sets the level's image to its lighter variant.
        The sprite then spends 12 frames with each of the explosion images.
        After 24 frames total, the item's image changes to a fully transparent, blank image.
        After 513 frames total, the item undoes the aforementioned changes and its state changes to DEAD.
        """
        self.frameCount += 1
        if self.frameCount == 1:
            PlayerSprite.currentLevel.image = PlayerSprite.currentLevel.lightImage
            UrchinSprite.isFrozen = True
            for sprite in c.playerGroup:
                if sprite is not self.collectingPlayer:
                    sprite.isFrozen = True
        if self.frameCount < 12:
            self.image = self.imageDict["explosion 1"]
        elif 12 < self.frameCount < 24:
            self.image = self.imageDict["explosion 2"]
        if self.frameCount == 24:
            playSound("item_appears_or_collected.wav")
            self.image = self.imageDict["empty"]
        if self.frameCount == 513:
            PlayerSprite.currentLevel.image = PlayerSprite.currentLevel.standardImage
            UrchinSprite.isFrozen = False
            for sprite in c.playerGroup:
                if sprite is not self.collectingPlayer:
                    sprite.isFrozen = False
                    if sprite.playerState == c.PlayerStates.FINISHED_SWINGING:
                        sprite.frameCount = 0
            self.itemState = c.OtherStates.DEAD
Beispiel #5
0
    def checkEnemyCollision(self):
        """Check if the sprite is currently colliding with an enemy sprite, and run the appropriate method if so.

        If the player is in any 'inactive' states (Such as BALL, FALLING, or OFF_SCREEN), this method is ignored.
        Otherwise, if the player collides with a blue (i.e., active) enemy sprite, they enter the EXPLODING
        state.
        If they collide with a yellow (i.e., stunned) enemy sprite, the enemy sprite is pushed.
        """
        if self.playerState in [
                c.PlayerStates.MOVING, c.PlayerStates.SWINGING,
                c.PlayerStates.FINISHED_SWINGING, c.PlayerStates.HITTING_WALL,
                c.PlayerStates.HITTING_PLAYER_MOVING,
                c.PlayerStates.HITTING_PLAYER_SWINGING
        ]:
            if any(
                    enemy.collisionRect.colliderect(self.collisionRect)
                    and enemy.enemyState == c.EnemyStates.MOVING
                    and enemy.color == c.BLUE for enemy in c.enemyGroup):
                playSound("death.wav")
                self.frameCount = 0
                self.facingDirection = c.Directions.RIGHT
                self.playerState = c.PlayerStates.EXPLODING
                self.image = self.imageDict["death"][0]
            else:
                pushedEnemies = [
                    enemy for enemy in c.enemyGroup
                    if enemy.collisionRect.colliderect(self.rect)
                    and enemy.color == c.YELLOW
                ]
                for enemy in pushedEnemies:
                    enemy.push(self)
Beispiel #6
0
    def startMoving(self, direction):
        """Set the sprite's facingDirection and image, and puts them in the MOVING state.

        If the sprite is not currently in the BALL state, this method is ignored.

        Args:
             direction: A string representation of which direction key the player has begun moving.
                Note that if direction is not in "up", "down", "left", or "right", this will cause the program to
                end with an error message.
        """
        if self.playerState == c.PlayerStates.BALL:
            playSound("move_out_of_ball.wav")
            try:
                self.facingDirection = c.directionsDict[direction]
            except KeyError:
                print("ERROR: '{}' is not a valid cardinal direction.".format(
                    direction))
                pg.quit()
                sys.exit()
            self.setCoordinates(self.coordinates[0], self.coordinates[1] - 1)
            self.changeImage("move", 0)
            if self.isFrozen:
                self.changeImage("move", 2)
            self.playerState = c.PlayerStates.MOVING
            self.frameCount = 0
Beispiel #7
0
    def animateLevelEnd(self):
        """Change the sprite's image to the end-of-level image, and flip it every 16 frames."""
        self.facingDirection = c.Directions.LEFT
        self.image = self.imageDict["end"][0]
        if (self.frameCount - 1) % 32 > 15:
            self.flipImage()

        # Only player one makes noise during the level end, to prevent overlapping sound effects
        if self.frameCount % 16 == 1 and self.playerNumber == 1:
            playSound("grab_post_move_end.wav")
Beispiel #8
0
 def update(self):
     """Increase frameCount. After 28 frames, the sprite appears and then moves forward eight pixels every
     frame.
     """
     self.frameCount += 1
     if self.frameCount == 28:
         playSound("shoot_wave.wav")
     if 28 < self.frameCount:
         self.coordinates = (self.coordinates[0] - 8, self.coordinates[1])
         self.image = self.animationFrames[0]
         if self.frameCount % 2 == 0:
             self.image = self.animationFrames[1]
Beispiel #9
0
    def checkGrabPost(self):
        """Set the sprite's state to SWINGING if it is over a post on the level image.

        To check if the sprite is over a post on the level image, it initially checks if the sprite is
        overlapping any of the level boundary's rects or a revealed rubber trap, as those cover up posts. It also
        checks if the playerBody object is overlapping with a trap or is frozen, as it cannot grab a post in
        either of those situations.
        If none of the above occurs, it checks if it is within 2 frames of (36 + 48x, 36 + 48y) in either
        direction, since every post on the level image is on those coordinates. This gives it a range where it
        can grab the post despite being a couple of pixels before or after the post's location.
        Note that because of this, if the player's speed is set to more than 5 pixels per frame, the arm may pass
        through posts it should grab.

        If the sprite meets the above criteria and grabs a post, its state and the playerBody's state are set to
        SWINGING, and the currentAngleOctant and the player's currentAngle are set based on the sprite's current
        extendedDirection.
        """
        if not any(self.wallCollisionRect.colliderect(levelRect) for levelRect in
                   PlayerSprite.currentLevel.levelBorderRects) and not \
                any(self.wallCollisionRect.colliderect(trap.collisionRect) for trap in c.rubberGroup if
                    trap.trapState in [c.OtherStates.REVEALED, c.OtherStates.TRIGGERED]) and not \
                any(self.playerBody.rect.colliderect(trap.collisionRect) for trap in c.rubberGroup) and not \
                self.playerBody.isFrozen:
            if self.collisionRect[0] % 48 in range(34, 39) and self.collisionRect[1] % 48 in range(34, 39) and \
                                    30 < self.collisionRect[0] < 500 and 20 < self.collisionRect[1] < 500:
                playSound("grab_post_move_end.wav")
                self.armState = c.ArmStates.SWINGING
                self.playerBody.playerState = c.PlayerStates.SWINGING
                self.setSwingDirection()

                if self.extendedDirection == c.Directions.LEFT:
                    self.playerBody.currentAngle = 0
                    self.currentAngleOctant = 0
                    self.coordinates = (self.coordinates[0] - 2,
                                        self.coordinates[1] - 2)
                elif self.extendedDirection == c.Directions.UP:
                    self.playerBody.currentAngle = 90
                    self.currentAngleOctant = 2
                    self.coordinates = (self.coordinates[0],
                                        self.coordinates[1] - 4)
                elif self.extendedDirection == c.Directions.RIGHT:
                    self.playerBody.currentAngle = 180
                    self.currentAngleOctant = 4
                    self.coordinates = (self.coordinates[0] + 2,
                                        self.coordinates[1] - 2)
                else:
                    self.playerBody.currentAngle = 270
                    self.currentAngleOctant = 6

                self.offsetGrabCoordinates(self.collisionRect[0] % 48 - 34,
                                           self.collisionRect[1] % 48 - 36)
                self.playerBody.swingingArmCoordinates = self.collisionRect.center
Beispiel #10
0
    def update(self):
        """Increase frameCount. Depending on frameCount and playerNumber, determine which methods to call.

        For safety's sake, this sets the sprite's image to the emptyImage before running any other methods, which
        may or may not change its image again.
        """
        self.frameCount += 1
        self.image = self.emptyImage
        if self.demoNumber == 1:
            # If demoNumber is 1, this sprite's image will rotate, flip, and change based on frameCount to create
            # the illusion of animation.

            if 100 < self.frameCount < 147 or 164 < self.frameCount < 211 or 226 < self.frameCount:
                self.image = self.animationFrames[0]
                if 120 < self.frameCount < 130 or 183 < self.frameCount < 193 or 246 < self.frameCount < 256 or\
                        285 < self.frameCount < 296 or 324 < self.frameCount:
                    self.image = pg.transform.rotate(self.image, 270)
                if 129 < self.frameCount < 141 or 192 < self.frameCount < 204 or 255 < self.frameCount < 267 or\
                        295 < self.frameCount < 306:
                    self.image = self.animationFrames[1]
                    self.image = pg.transform.rotate(self.image, 90)
                elif 111 < self.frameCount < 121 or 174 < self.frameCount < 184 or 237 < self.frameCount < 247 or\
                        276 < self.frameCount < 286 or 315 < self.frameCount < 325:
                    self.image = self.animationFrames[2]
            else:
                self.image = self.emptyImage
            self.adjustPosition()
            if self.extendedDirection == c.Directions.LEFT:
                self.image = pg.transform.flip(self.image, True, False)
            if self.frameCount in [107, 171, 233]:
                playSound("grab_post_move_end.wav")

        # If demoNumber is 1, this sprite's and coordinates will flip and change based on frameCount to create the
        # illusion of animation.
        else:
            if 50 < self.frameCount < 150 or 180 < self.frameCount < 215 or 280 < self.frameCount:
                self.image = self.animationFrames[3]
            elif self.frameCount == 180:
                self.flipped = False
                self.coordinates = (self.coordinates[0], self.coordinates[1] + 88)
            elif self.frameCount == 215:
                self.flipped = True
                self.coordinates = (self.coordinates[0], self.coordinates[1] - 88)
            if DemoPlayerSprite.facingDirection == c.Directions.LEFT:
                self.image = pg.transform.flip(self.image, True, False)
        if self.flipped:
            self.image = pg.transform.flip(self.image, False, True)
Beispiel #11
0
    def checkBlackHoleCollision(self):
        """Check if the sprite is currently moving and its center point overlaps with a black hole sprite.

        If they are colliding, the player's coordinates are set to the black hole sprite's coordinates, for
        improved animation. The player is then put into the FALLING state.
        This method is ignored unless the player is in the MOVING state.
        """
        if self.playerState == c.PlayerStates.MOVING:
            for hole in c.blackHoleGroup:
                if hole.rect.collidepoint(self.rect.center):
                    self.coordinates = hole.coordinates
                    self.rect.topleft = hole.coordinates
                    playSound("death.wav")
                    self.frameCount = 0
                    self.facingDirection = c.Directions.RIGHT
                    self.playerState = c.PlayerStates.FALLING
                    self.image = self.imageDict["fall"][0]
Beispiel #12
0
def scoreTime(playerList, level, time, highScore):
    """Update each players' score based on the current time, 10 points each time this function is called.

    Args:
        playerList: A list of all PlayerSprite objects in the game.
        level: A Level object representing the current level being played.
        time: An integer representing the time the players have remaining after completing the current level.
        highScore: An integer showing the current high score.

    Returns:
        looping: A boolean indicating if scoreLevel should call this function again.
        time: An integer representing the time the players have remaining after completing the current level.
        scoreText: A list of the current scores for each of the players.
        highScore: An integer showing the current high score.
    """
    scoreText = []
    timeText = c.FONT.render("TIME,{:03d}".format(time), False, c.WHITE)
    checkQuitGame()
    checkPauseGameWithInput(playerList)

    # All living players increase their score by 10 points each time this function is called.
    for player in playerList:
        if player.lives > 0:
            player.score += 10
        scoreText.append(
            c.FONT.render("{:06d}PTS.".format(player.score % 1000000), False,
                          c.WHITE))
    highScore = compareHighScore(playerList, highScore)

    # The time remaining decreases by 10 counts each time this function is called.
    time = max(0, time - 10 - (time % 10))

    # Instead of updating the entire screen, this function only draws a square over the time's coordinates that matches
    # the background color, then blits the remaining time to the screen.
    pg.draw.rect(c.SCREEN, level.backgroundColor,
                 pg.rect.Rect(160, 224, 48, 16))
    c.SCREEN.blit(timeText, (82, 224))

    # Once the time reaches 0, looping is set to False so scoreTime will not be called again.
    # As long as the time is greater than 0, a sound effect will play as the time counts down.
    if time == 0:
        return False, time, scoreText, highScore
    else:
        playSound("count_points.wav")
        return True, time, scoreText, highScore
Beispiel #13
0
def scoreGold(playerList, iconCount, highScore):
    """Update each players' score based on the amount of gold that they have collected.

    Args:
        playerList: A list of all PlayerSprite objects in the game.
        iconCount: A list of integers representing how many times each player has gained points from the
            scoreGold function this level.
        highScore: An integer showing the current high score.

    Returns:
        looping: A boolean indicating if scoreLevel should call this function again.
        iconCount: A list of integers representing how many times each player has gained points from the
            scoreGold function this level.
        scoreText: A list of the current scores for each of the players.
        iconCountText: A list of text objects representing each player's iconCount value.
        highScore: An integer showing the current high score.
    """
    scoreText = []
    iconCountText = []
    checkQuitGame()
    checkPauseGameWithInput(playerList)
    if any(player.goldCollectedCount > 0 for player in playerList):
        playSound("count_points.wav")

    # All living players increase their score by 100 points each time this function is called, until it has been called
    # as many times as they've collected gold this level.
    for num, player in enumerate(playerList):
        if player.goldCollectedCount > iconCount[num]:
            player.score += 100
            iconCount[num] += 1
        scoreText.append(
            c.FONT.render("{:06d}PTS.".format(player.score % 1000000), False,
                          c.WHITE))
        iconCountText.append(
            c.FONT.render("+{:02d}".format(iconCount[num] % 100), False,
                          c.WHITE))
    highScore = compareHighScore(playerList, highScore)

    # Once iconCount has reached the correct number of collected gold for each player, looping is set to False so
    # scoreGold will not be called again.
    if all(iconCount[num] == player.goldCollectedCount
           for num, player in enumerate(playerList)):
        return False, iconCount, scoreText, iconCountText, highScore
    else:
        return True, iconCount, scoreText, iconCountText, highScore
Beispiel #14
0
    def collectItem(self):
        """Increase frameCount. Depending on frameCount, collectItem has different effects.

        On the first frame, increase the collecting player's lives by 1.
        The sprite then spends 12 frames with each of the explosion images.
        After 24 frames total, the item's state changes to DEAD.
        """
        self.frameCount += 1
        if self.frameCount == 1:
            self.collectingPlayer.lives += 1
        if self.frameCount % 24 < 12:
            self.image = self.imageDict["explosion 1"]
        else:
            self.image = self.imageDict["explosion 2"]
        if self.frameCount == 24:
            playSound("item_appears_or_collected.wav")
            self.image = self.imageDict["empty"]
            self.itemState = c.OtherStates.DEAD
Beispiel #15
0
    def push(self, pushingPlayer):
        """Move the sprite in the direction the player pushing it is facing, and check if it has collided with a
        wall.

        The urchin's animation count is set to 0 if it is pushed to reset the amount of time that it has spent
        being stunned.
        When the sprite and the player are both facing horizontally or are both facing vertically, this method
        puts the urchin immediately in front of the player sprite's rect every frame.
        Otherwise, this method just pushes the urchin sprite forward every frame until is it no longer in the
        middle of the intersection.
        """
        self.animationCount = 0
        self.audioCount += 1
        if self.audioCount % 10 == 0:
            playSound("push_or_shoot_enemy.wav")
        if any(levelRect.colliderect(self.collisionRect) for levelRect in PlayerSprite.currentLevel.levelBorderRects)\
                and self.enemyState != c.EnemyStates.EXPLODING:
            playSound("crush_enemy.wav")
            self.enemyState = c.EnemyStates.EXPLODING
            self.frameCount = 0
            self.changeImage("death", 0)
            pushingPlayer.killedUrchinCount += 1
        else:
            if self.isFacingHorizontally(
            ) == pushingPlayer.isFacingHorizontally():
                self.facingDirection = pushingPlayer.facingDirection
                if self.facingDirection == c.Directions.UP and\
                        self.collisionRect.collidepoint(pushingPlayer.collisionRect.midtop):
                    self.rect.bottom = pushingPlayer.rect.top
                elif self.facingDirection == c.Directions.DOWN and\
                        self.collisionRect.collidepoint(pushingPlayer.collisionRect.midbottom):
                    self.rect.top = pushingPlayer.rect.bottom
                elif self.facingDirection == c.Directions.LEFT and\
                        self.collisionRect.collidepoint(pushingPlayer.collisionRect.midleft):
                    self.rect.right = pushingPlayer.rect.left
                elif self.facingDirection == c.Directions.RIGHT and\
                        self.collisionRect.collidepoint(pushingPlayer.collisionRect.midright):
                    self.rect.left = pushingPlayer.rect.right
                self.setCoordinates(self.rect.topleft[0], self.rect.topleft[1])
                self.moveSprite(int(PlayerSprite.movementSpeed))
            elif 2 < self.rect.center[0] % 48 < 30 and 4 < self.rect.center[
                    1] % 48 < 32:
                self.moveSprite(int(PlayerSprite.movementSpeed))
Beispiel #16
0
    def checkPlayerCollision(self):
        """Check if the sprite's rects are colliding with any of the player sprites.

        If the item sprite is in the REVEALED state and collides with a player sprite, its state becomes the
        COLLECTED state.
        If the item sprite is in the OFF_SCREEN state and its triggerRect collides with a player sprite, its
        state becomes the REVEALED state.
        """
        for player in c.playerGroup:
            if self.rect.colliderect(
                    player.collisionRect
            ) and self.itemState == c.OtherStates.REVEALED:
                self.collectingPlayer = player
                self.itemState = c.OtherStates.COLLECTED
            elif self.triggerRect.colliderect(
                    player.collisionRect
            ) and self.itemState == c.OtherStates.OFF_SCREEN:
                playSound("item_appears_or_collected.wav")
                self.itemState = c.OtherStates.REVEALED
Beispiel #17
0
    def startFlipAnimation(self):
        """Set the sprite's state as it is passed over.

        If the sprite has already been revealed, frameCount is set to 12 instead of 0 to account for the fact
        that its image is already in the middle of its flipping animation.
        Gold sprites cannot enter the FLIPPING_DOWN state while in a bonus level, or before level 22.
        """
        self.frameCount = 0
        playSound("pass_over_gold.wav")
        if self.goldState == c.OtherStates.REVEALED and GoldSprite.levelCount > 21 and not\
                isinstance(PlayerSprite.currentLevel, BonusLevel):
            self.goldState = c.OtherStates.FLIPPING_DOWN
        elif self.goldState in [
                c.OtherStates.UPSIDE_DOWN, c.OtherStates.OFF_SCREEN,
                c.OtherStates.REVEALED
        ]:
            if self.alreadyRevealed:
                self.frameCount = 12
            self.goldState = c.OtherStates.FLIPPING_UP
Beispiel #18
0
def shootWave(player):
    """Create a sonic wave sprite in front of the player who pressed the shoot button, assuming that player does
    not already have two sonic wave sprites active.

    Args:
        player: The PlayerSprite object for the player who is shooting a sonic wave.
    """
    sonicWavesFromPlayer = [
        sprite for sprite in c.attackGroup
        if sprite.firingPlayerNumber == player.playerNumber
    ]
    if len(sonicWavesFromPlayer) < 2 and player.playerState in [
            c.PlayerStates.MOVING, c.PlayerStates.SWINGING,
            c.PlayerStates.FINISHED_SWINGING
    ]:
        waveCoordinates = player.coordinates

        # In order to keep the sonic wave sprite centered on its row or column, its initial coordinates are adjusted
        # by mod 48.
        # This is done because the player's coordinates are not necessarily centered on the row or column while they
        # are swinging.
        if player.isFacingHorizontally():
            if 0 < player.coordinates[1] % 48 < 24:
                waveCoordinates = (int(player.coordinates[0]),
                                   int(player.coordinates[1] -
                                       (player.coordinates[1] % 48)))
            elif player.coordinates[1] % 48 > 23:
                waveCoordinates = (int(player.coordinates[0]),
                                   int(player.coordinates[1] +
                                       (48 - player.coordinates[1] % 48)))
        else:
            if 0 < player.coordinates[0] % 48 < 24:
                waveCoordinates = (int(player.coordinates[0] -
                                       (player.coordinates[0] % 48)),
                                   int(player.coordinates[1]))
            elif player.coordinates[0] % 48 > 23:
                waveCoordinates = (int(player.coordinates[0] +
                                       (48 - player.coordinates[0] % 48)),
                                   int(player.coordinates[1]))
        playSound("shoot_wave.wav")
        newWave = SonicWaveSprite(player.facingDirection, player.playerNumber)
        newWave.setCoordinates(waveCoordinates[0], waveCoordinates[1])
        c.attackGroup.add(newWave)
Beispiel #19
0
    def update(self):
        """Increase frameCount. Depending on frameCount and animationCount, determine which methods to call.

        The sprite's image changes every 5th and 8th frame in an 8 frame cycle until it is crushed against a demo
        wall sprite.
        """
        self.frameCount += 1
        if self.animationCount == 0:
            if self.frameCount % 8 < 5:
                self.image = self.animationFrames[0]
            else:
                self.image = self.animationFrames[1]
            for sprite in c.demoGroup:
                if isinstance(sprite, DemoWaveSprite) and self.rect.collidepoint(sprite.rect.center) and\
                        0 < self.frameCount:
                    playSound("push_or_shoot_enemy.wav")
                    self.animationCount = 1
                    self.frameCount = 0
        elif self.animationCount == 1:
            if self.frameCount < 3:
                self.image = self.animationFrames[2]
            elif self.frameCount % 8 < 5:
                self.image = self.animationFrames[3]
            else:
                self.image = self.animationFrames[4]
            for sprite in c.demoGroup:
                if isinstance(sprite, DemoPlayerSprite) and self.rect.colliderect(sprite.rect) and\
                        self.animationCount == 1:
                    self.animationCount = 2
                    self.frameCount = 0
        elif self.animationCount == 2:
            if self.frameCount > 3:
                self.coordinates = (self.coordinates[0] - 4, self.coordinates[1])
                self.audioCount += 1
            if self.audioCount % 10 == 0:
                    playSound("push_or_shoot_enemy.wav")
        else:
            if self.frameCount < 5:
                self.image = self.animationFrames[5]
            elif self.frameCount < 10:
                self.image = self.animationFrames[6]
            else:
                self.kill()
Beispiel #20
0
    def checkOtherPlayerCollision(self):
        """Check if the sprite is colliding with any of the other player sprites.

        If they are colliding, the sprite's image is changed to the appropriate colliding image, and the sprite's
        state is set to either HITTING_PLAYER_MOVING or HITTING_PLAYER_SWINGING.
        This method is ignored unless the player is currently in a moving or swinging state, and is not already
        colliding with another wall or player.
        """
        if self.playerState in [c.PlayerStates.MOVING, c.PlayerStates.SWINGING, c.PlayerStates.FINISHED_SWINGING]\
                and not self.bouncingOffWall and not self.bouncingOffPlayer:
            otherPlayers = [
                player for player in c.playerGroup
                if (player != self and player.playerState in [
                    c.PlayerStates.MOVING, c.PlayerStates.SWINGING, c.
                    PlayerStates.FINISHED_SWINGING, c.PlayerStates.HITTING_WALL
                ])
            ]
            for player in otherPlayers:
                if player.collisionRect.colliderect(self.collisionRect):
                    playSound("bounce_rubber_or_player.wav")
                    self.frameCount = 0
                    self.bouncingOffPlayer = True
                    player.checkOtherPlayerCollision()
                    if self.playerState in [
                            c.PlayerStates.MOVING,
                            c.PlayerStates.FINISHED_SWINGING
                    ]:
                        self.playerState = c.PlayerStates.HITTING_PLAYER_MOVING
                        self.image = self.imageDict["move"][
                            self.getDirectionKey()][2]
                    else:
                        self.playerState = c.PlayerStates.HITTING_PLAYER_SWINGING
                        if self.isTurningOrthogonally():
                            self.image = self.imageDict["move"][
                                self.getDirectionKey()][2]
                        elif self.frameCount % 8 < 4:
                            self.image = self.imageDict["turn"][2]
                            self.flipDiagonalImage()
                        else:
                            self.image = self.imageDict["turn"][3]
                            self.flipDiagonalImage()
                    player.checkOtherPlayerCollision()
Beispiel #21
0
    def collectItem(self):
        """Increase frameCount. Depending on frameCount, collectItem has different effects.

        On the first frame, increase the collecting player's score by 800.
        The sprite then spends 12 frames with each of the explosion images.
        Its image then changes to an 1500 for 32 frames, representing its value in points.
        After 56 frames total, the item's state changes to DEAD.
        """
        self.frameCount += 1
        if self.frameCount == 1:
            self.collectingPlayer.score += 1500
        if self.frameCount % 56 < 12:
            self.image = self.imageDict["explosion 1"]
        elif self.frameCount % 56 < 24:
            self.image = self.imageDict["explosion 2"]
        else:
            self.image = self.imageDict["1500"]
        if self.frameCount == 24:
            playSound("item_appears_or_collected.wav")
        if self.frameCount % 56 == 0:
            self.itemState = c.OtherStates.DEAD
Beispiel #22
0
    def update(self):
        """Increase frameCount. Depending on frameCount and timesFlipped, determine which methods to call."""
        self.frameCount += 1
        if self.flipping and 9 < self.frameCount:
            self.flipUp()
        elif self.timesFlipped:
            if self.frameCount % 12 < 6:
                self.image = self.animationFrames[3]
            else:
                self.image = self.animationFrames[8]

        # If the demo player sprite collides with this sprite, it sets flipping to True.
        # timesFlipped should always be either 0 or 1 during the demo animation, and thus frameCount will be set to
        # either 0 or 9 (To account for the fact that its image is already in the middle of its flipping animation).
        # This is not triggered if frameCount is 0, since all sprites start on the same coordinates when the demo
        # animation begins.
        for sprite in c.demoGroup:
            if isinstance(sprite, DemoPlayerSprite) and self.rect.colliderect(sprite.rect) and\
                    0 < self.frameCount and not self.flipping:
                playSound("pass_over_gold.wav")
                self.flipping = True
                self.frameCount = 9 * self.timesFlipped
Beispiel #23
0
def pauseGame(pausingPlayerIndex):
    """Stop all onscreen action until the same player to pause the game unpauses it.

    This function will do nothing if any of the other players attempt to unpause the game. Only the pause button
    from the player who paused the game will have an effect.

    Args:
        pausingPlayerIndex: An integer representing which of the players initially paused the game.
    """
    while True:
        checkQuitGame()
        for event in pg.event.get():

            # After unpausing, the queue is cleared to ensure that no keys pressed during the game preparing to unpause
            # take effect.
            if event.type == pg.KEYDOWN:
                if event.key == controlsDicts[pausingPlayerIndex]["pause"]:
                    playSound("pause_unpause.wav")
                    pg.time.delay(1000)
                    pg.mixer.music.unpause()
                    pg.event.clear()
                    return
Beispiel #24
0
    def update(self):
        """Increase frameCount and set the sprite's image.

        If the player collides with the sprite, frameCount is set to -100 to ensure that it doesn't collide with
        the sprite again before bouncing off.
        """
        self.frameCount += 1
        if self.demoNumber == 2:
            self.image = self.animationFrames[1]
            self.image = pg.transform.flip(self.image, True, False)

        for sprite in c.demoGroup:
            if isinstance(sprite, DemoPlayerSprite) and self.rect.colliderect(sprite.rect) and 0 < self.frameCount\
                    and not DemoPlayerSprite.paused:
                playSound("bounce_wall.wav")
                DemoPlayerSprite.paused = True
                self.frameCount = -100
                sprite.frameCount = 0
            elif isinstance(sprite, DemoUrchinSprite) and self.rect.collidepoint(sprite.rect.center) and\
                    sprite.animationCount == 2:
                playSound("crush_enemy.wav")
                sprite.animationCount = 3
                sprite.frameCount = 0
Beispiel #25
0
def checkPauseGameWithInput(playerList):
    """Check the keys currently pressed. If any are the pause button, pause the game.

    In situations where keys pressed can have other effects on the game (such as during normal level gameplay),
    do not use this function, as it will pop all events out of the event queue.
    Use checkPauseGame in those cases instead.

    Args:
        playerList: A list of all PlayerSprite objects in the game.
    """
    for event in pg.event.get():
        if event.type == pg.KEYDOWN:
            for num, player in enumerate(playerList):
                # Players who have run out of lives cannot pause the game.
                # After pausing, the queue is cleared to ensure that no keys pressed during the game preparing to pause
                # take effect while paused.
                if event.key == controlsDicts[num][
                        "pause"] and player.playerState != c.PlayerStates.DEAD:
                    pg.mixer.music.pause()
                    playSound("pause_unpause.wav")
                    pauseGame(num)
                    pg.time.delay(1000)
                    pg.event.clear()
Beispiel #26
0
    def checkPlayerCollision(self):
        """Check if the sprite's rects are colliding with any of the player sprites.

        If the item sprite is not in the TRIGGERED state and collides with a player sprite, its state becomes the
        TRIGGERED state.
        The flipTrigger boolean is set to True if the colliding player is moving left or upwards, so the trap
        appears to be contorting around the player (As opposed to doing so in the direction opposite the player).
        """
        if self.trapState != c.OtherStates.TRIGGERED:
            for player in c.playerGroup:
                if self.collisionRect.colliderect(player.collisionRect) and\
                                player.playerState == c.PlayerStates.MOVING:
                    if self.trapState == c.OtherStates.OFF_SCREEN:
                        self.image.set_colorkey(c.RED)
                        playSound("bounce_rubber_or_player.wav")
                    else:
                        playSound("bounce_wall.wav")
                    self.collidingPlayer = player
                    self.trapState = c.OtherStates.TRIGGERED
                    if self.collidingPlayer.facingDirection == c.Directions.LEFT or \
                            self.collidingPlayer.facingDirection == c.Directions.UP:
                        self.flipTrigger = True
                    else:
                        self.flipTrigger = False
Beispiel #27
0
    def collectItem(self):
        """Increase frameCount. Depending on frameCount, collectItem has different effects.

        On the first frame, changes the state of all OFF_SCREEN items and gold sprites to reveal them.
        The sprite then spends 12 frames with each of the explosion images.
        After 24 frames total, the item's state changes to DEAD.
        """
        self.frameCount += 1
        if self.frameCount == 1:
            for sprite in c.itemGroup:
                if sprite.itemState == c.OtherStates.OFF_SCREEN:
                    sprite.itemState = c.OtherStates.REVEALED

            for sprite in c.goldGroup:
                if sprite.goldState == c.OtherStates.OFF_SCREEN:
                    sprite.goldState = c.OtherStates.UPSIDE_DOWN
        if self.frameCount % 24 < 12:
            self.image = self.imageDict["explosion 1"]
        else:
            self.image = self.imageDict["explosion 2"]
        if self.frameCount == 24:
            playSound("item_appears_or_collected.wav")
            self.image = self.imageDict["empty"]
            self.itemState = c.OtherStates.DEAD
Beispiel #28
0
 def hitWall(self):
     """Change the sprite's image to appear squished, and sets their state to HITTING_WALL."""
     self.frameCount = 0
     playSound("bounce_wall.wav")
     self.playerState = c.PlayerStates.HITTING_WALL
     self.image = self.imageDict["squish"][self.getDirectionKey()][0]
Beispiel #29
0
def blitLevelEndData(playerList, level, time, levelCount, highScore,
                     scoreBonus):
    """Draw the end-of-level data to the screen, while calling the functions to increase the players' scores as
    required.

    This includes the players' displays and sprites, their lives, their scores, the time remaining, level count,
    and the current high score.

    Args:
        playerList: A list of all PlayerSprite objects in the game.
        level: A Level object representing the current level being played.
        time: An integer representing the time the players have remaining to complete the level.
                levelCount: An integer storing how many levels the player has currently played.
        levelCount: An integer storing how many levels the player has currently played.
        highScore: An integer showing the current high score.
        scoreBonus: A boolean indicating if the level has been completed within 300 counts of the timer.
    """
    playerTextData = []
    playerScoreData = []
    playerLivesData = []
    playerDisplayIcons = []
    iconCountText = []
    frameCount = 0

    levelText = c.FONT.render(
        "<<<<< CLU,CLU,LAND,,{:02d} >>>>>".format(levelCount % 100), False,
        c.WHITE)
    timeText = c.FONT.render("TIME,{:03d}".format(time), False, c.WHITE)

    if len(playerList) < 3:
        playerTextCoordinates = [(162, 47), (162, 271)]
        scoreDataCoordinates = [(240, 95), (240, 319)]
        livesDataCoordinates = [(140, 95), (140, 319)]
        playerSpriteCoordinates = [(88, 79), (88, 303)]
        displayIconTextCoordinates = [(140, 143), (140, 367)]
        bonusTextCoordinates = [(236, 143), (236, 367)]
        bonusScoreCoordinates = [(340, 143), (340, 367)]
        bonusLevelCompletionTextCoordinates = [(220, 127), (220, 351)]
        bonusLevelCompletionScoreCoordinates = [(340, 127), (340, 351)]
    else:
        playerTextCoordinates = [(37, 46), (292, 46), (37, 271), (292, 271)]
        scoreDataCoordinates = [(55, 74), (309, 74), (55, 298), (309, 298)]
        livesDataCoordinates = [(70, 111), (327, 111), (70, 335), (327, 335)]
        playerSpriteCoordinates = [(17, 99), (273, 99), (17, 323), (273, 323)]
        displayIconTextCoordinates = [(64, 147), (320, 147), (64, 371),
                                      (320, 371)]
        bonusTextCoordinates = [(150, 135), (407, 135), (150, 358), (407, 358)]
        bonusScoreCoordinates = [(150, 151), (407, 151), (150, 374),
                                 (407, 374)]
        bonusLevelCompletionTextCoordinates = [(134, 103), (391, 103),
                                               (134, 327), (391, 327)]
        bonusLevelCompletionScoreCoordinates = [(150, 119), (407, 119),
                                                (150, 343), (407, 343)]

    # All of the bonus font objects default to an empty string. They are only updated as a relevant string if the
    # appropriate bonus is earned.
    bonusEarnedText = bonusScoreText = bonusLevelCompletionText = bonusLevelCompletionScore =\
        c.FONT.render("", False, c.WHITE)

    # Standard bonus points cannot be scored during a bonus level in a one-player game.
    if isinstance(level, BonusLevel) and len(playerList) == 1:
        doesScoreBonus, bonusScoringIndex = False, 0
    else:
        doesScoreBonus, bonusScoringIndex = checkIfScoresBonusPoints(
            playerList, scoreBonus)

    # The bonus completion points are only earned if the players collect all 66 gold bars on the bonus stage.
    if isinstance(level, BonusLevel) and sum(
        [player.goldCollectedCount for player in playerList]) == 66:
        doesScoreBonusCompletion = True
    else:
        doesScoreBonusCompletion = False

    for num, player in enumerate(playerList):
        playerDisplayIcons.append(DisplayIconSprite(num + 1, len(playerList)))
        playerTextData.append(
            c.FONT.render("< PLAYER {} >".format(num + 1), False, c.WHITE))
        playerScoreData.append(
            c.FONT.render("{:06d}PTS.".format(player.score % 1000000), False,
                          c.WHITE))
        playerLivesData.append([
            c.FONT.render("<", False, c.WHITE),
            c.FONT.render("{}".format(min(player.lives, 9)), False, c.WHITE),
            c.FONT.render(">", False, c.WHITE)
        ])
        player.coordinates = playerSpriteCoordinates[num]

        # Which displays are used in the end-of-level animation depends on the number of players.
        # If there are one or two players, the full-sized displays are used, with player one on top and player two
        # on the bottom.
        # If there are three or four players, the half-sized displays are used, with player one on the top-left, player
        # two on the top-right, player three on the bottom-left, and player four on the bottom-right.
        if len(playerList) < 3:
            FullDisplaySprite(num + 1)
        else:
            HalfDisplaySprite(num + 1)

    while True:
        frameCount += 1

        # If none of the players have any lives remaining, do not score or animate their sprites in the end-of-level
        # screen.
        if any(player.lives > 0 for player in playerList):
            if frameCount == 32:
                highScore, iconCount = scoreLevel(playerList,
                                                  level,
                                                  time,
                                                  highScore,
                                                  stepToScore=0)
                timeText = c.FONT.render("TIME,000", False, c.WHITE)

            # These steps are skipped during bonus levels, as there are no enemies to score.
            elif frameCount == 64 and not isinstance(level, BonusLevel):
                for icon in playerDisplayIcons:
                    icon.setIconImage()
                iconCountText = [
                    c.FONT.render("+00", False, c.WHITE) for _ in playerList
                ]
            elif frameCount == 96 and not isinstance(level, BonusLevel):
                highScore, iconCount = scoreLevel(playerList,
                                                  level,
                                                  time,
                                                  highScore,
                                                  stepToScore=1)
                iconCountText = []
                for num, player in enumerate(playerList):
                    iconCountText.append(
                        c.FONT.render("+{:02d}".format(iconCount[num] % 100),
                                      False, c.WHITE))

            elif frameCount == 128:
                iconCountText = [
                    c.FONT.render("+00", False, c.WHITE) for _ in playerList
                ]
                for icon in playerDisplayIcons:
                    icon.setIconImage()

                    # This method is called again during a bonus level, to skip the urchin icon and move directly to
                    # the gold icon.
                    if isinstance(level, BonusLevel):
                        icon.setIconImage()
            elif frameCount == 160:
                highScore, iconCount = scoreLevel(playerList,
                                                  level,
                                                  time,
                                                  highScore,
                                                  stepToScore=2)
                iconCountText = []
                for player in playerList:
                    iconCountText.append(
                        c.FONT.render(
                            "+{:02d}".format(player.goldCollectedCount % 100),
                            False, c.WHITE))

            elif frameCount == 188:
                for player in playerList:
                    player.setLevelEndCountImage()
                if doesScoreBonus:
                    playerList[bonusScoringIndex].score += 2000
                    if playerList[bonusScoringIndex].score > highScore:
                        highScore = playerList[bonusScoringIndex].score
                    playSound("earn_bonus.wav")
                    bonusEarnedText = c.FONT.render("BONUS", False, c.WHITE)
                    bonusScoreText = c.FONT.render("2000!", False, c.WHITE)
                if doesScoreBonusCompletion:
                    for player in playerList:
                        if player.lives > 0:
                            player.score += 3000

                    # To prevent the earn_bonus sound from playing multiple times at once, it only plays here if the
                    # doesScoreBonus is False (since it should already be playing from the above block of code if it is
                    # True).
                    if not doesScoreBonus:
                        playSound("earn_bonus.wav")
                    bonusLevelCompletionText = c.FONT.render(
                        "PERFECT", False, c.WHITE)
                    bonusLevelCompletionScore = c.FONT.render(
                        "3000!", False, c.WHITE)
        if frameCount == 442:
            return

        scoreText = []

        # Every frame, update the text displaying the players' scores and the high score, in case these values have
        # changed since the previous frame.
        for player in playerList:
            scoreText.append(
                c.FONT.render("{:06d}PTS.".format(player.score % 1000000),
                              False, c.WHITE))
        highScore = compareHighScore(playerList, highScore)
        highScoreText = c.FONT.render("TOP,{:06d}".format(highScore), False,
                                      c.WHITE)

        c.SCREEN.fill(level.backgroundColor)
        checkQuitGame()
        checkPauseGameWithInput(playerList)

        c.SCREEN.blit(highScoreText, (254, 224))
        c.SCREEN.blit(timeText, (82, 224))
        c.SCREEN.blit(levelText, (38, 192))
        for display in c.displayGroup:
            c.SCREEN.blit(
                display.image,
                (display.coordinates[0], display.coordinates[1] - 450))
        for textSprite in c.textGroup:
            c.SCREEN.blit(
                textSprite.image,
                (textSprite.coordinates[0], textSprite.coordinates[1]))
        for player in c.playerGroup:
            if frameCount < 188:
                player.update()
            c.SCREEN.blit(player.image, player.coordinates)

        # Because the < > symbols should be slightly closer to the number of lives than the standard text width would
        # allow, the life count is placed 13 pixels after the <, and the > is placed 15 frames after the life count.
        for fontData, coords in zip(playerLivesData, livesDataCoordinates):
            for num, text in enumerate(fontData):
                c.SCREEN.blit(text, (coords[0], coords[1]))
                coords = (coords[0] + 13,
                          coords[1]) if num == 0 else (coords[0] + 15,
                                                       coords[1])

        for text, coords in zip(playerTextData, playerTextCoordinates):
            c.SCREEN.blit(text, (coords[0], coords[1]))
        for text, coords in zip(scoreText, scoreDataCoordinates):
            c.SCREEN.blit(text, (coords[0], coords[1]))

        # During regular levels, the score icon and its text should be visible from frame 75 onwards, when enemies are
        # scored.
        # During bonus levels, the score icon and its text should be visible from frame 139 onwards, when gold is
        # scored.
        if (frameCount > 74
                and not isinstance(level, BonusLevel)) or frameCount > 138:
            for text, coords in zip(iconCountText, displayIconTextCoordinates):
                c.SCREEN.blit(text, (coords[0], coords[1]))

        if frameCount > 188:
            c.SCREEN.blit(bonusEarnedText,
                          bonusTextCoordinates[bonusScoringIndex])
            c.SCREEN.blit(bonusScoreText,
                          bonusScoreCoordinates[bonusScoringIndex])
            for (coords, player) in zip(bonusLevelCompletionTextCoordinates,
                                        playerList):
                if player.lives > 0:
                    c.SCREEN.blit(bonusLevelCompletionText,
                                  (coords[0], coords[1]))
            for (coords, player) in zip(bonusLevelCompletionScoreCoordinates,
                                        playerList):
                if player.lives > 0:
                    c.SCREEN.blit(bonusLevelCompletionScore,
                                  (coords[0], coords[1]))

        pg.display.update()
        c.CLOCK.tick(c.FPS)
Beispiel #30
0
def animateDemo():
    """Play the demo animation until the user presses return to cancel it."""
    pg.mixer.music.load(c.DEMO_MUSIC)
    pg.mixer.music.play()
    playerNames = [c.DEMO_FONT.render("BUBBLES", False, c.RED), c.DEMO_FONT.render("GLOOPY", False, c.GREEN),
                   c.DEMO_FONT.render("NEMO", False, c.BLUE), c.DEMO_FONT.render("DIZZY", False, c.YELLOW)]
    playerNameCoordinates = [(103, 61), (127, 61), (145, 337), (122, 337)]

    coverRect = pg.Rect(20, -260, 380, 260)
    displayRects = [pg.Rect(20, -260, 380, 260), pg.Rect(480, 180, 380, 260), pg.Rect(120, 444, 380, 260),
                    pg.Rect(-380, 20, 380, 260)]
    nameRects = [pg.Rect(86, 47, 540, 100), pg.Rect(86, 46, 540, 100), pg.Rect(57, 324, 540, 100),
                 pg.Rect(57, 324, 540, 100)]
    spriteCoords = [(0, 4), (-4, 0), (0, -4), (4, 0)]

    for demoNum in range(4):
        # Initialize each scene of the demo by setting frameCount to 0, removing all sprites from demoGroup, and
        # resetting the base class variables of the PlayerDemoSprite class.
        frameCount = 0
        c.demoGroup.empty()
        d_sprite.initialize()
        c.SCREEN.fill(c.GREY)
        pg.display.update()

        createDemoSprites(demoNum, displayRects)
        alphaKey = 255

        # Each scene of the demo animation is 600 frames long.
        while frameCount < 600:
            checkQuitGame()
            for event in pg.event.get():
                if event.type == pg.KEYDOWN:
                    if event.key == controlsDicts[0]["pause"] or event.key == pg.K_RETURN:
                        pg.mixer.music.stop()
                        c.SCREEN.fill(c.BLACK)
                        return
            frameCount += 1

            # Only the sprites inside of the display rect are visible.
            # The display rect moves from off of one edge of the screen towards the either side for 104 frames.
            # Every sprite moves this amount in addition to their regular movement, to create the illusion of them
            # moving with the display.
            # A grey rect stays against one side of the display rect to cover up every sprite that moves past the edge
            # of the display rect.
            if frameCount < 105:
                displayRects[demoNum].topleft = [displayRects[demoNum].topleft[0] + spriteCoords[demoNum][0],
                                                 displayRects[demoNum].topleft[1] + spriteCoords[demoNum][1]]
                if demoNum == 0:
                    coverRect.bottomleft = displayRects[demoNum].topleft
                elif demoNum == 1:
                    coverRect.topleft = displayRects[demoNum].topright
                elif demoNum == 2:
                    coverRect.topleft = displayRects[demoNum].bottomleft
                else:
                    coverRect.topright = displayRects[demoNum].topleft
                for sprite in c.demoGroup:
                    sprite.coordinates = (sprite.coordinates[0] + spriteCoords[demoNum][0],
                                          sprite.coordinates[1] + spriteCoords[demoNum][1])

            # For the first 328 frames, the sprites are all animated and move as desired, with the player sprite
            # constantly staying in the middle of the display rect.
            if frameCount < 328:
                pg.draw.rect(c.SCREEN, c.BLACK, displayRects[demoNum])
                for sprite in c.demoGroup:
                    sprite.setCoordinates()
                    sprite.update()
                    c.SCREEN.blit(sprite.image, sprite.coordinates)
                pg.draw.rect(c.SCREEN, c.GREY, coverRect)
                pg.display.update(coverRect)
                pg.display.update(displayRects[demoNum])

            # On the 328th frame, all sprites stop moving. Any sprite that has a monochrome image variant switches to
            # that image.
            # The name display and player character's name appears as well, but they are hidden by the screen being
            # covered by a white rect in the following conditional statement.
            elif frameCount == 328:
                playSound("item_appears_or_collected.wav")
                demoNameBlock = d_sprite.DemoNameDisplay(demoNum, (nameRects[demoNum].left, nameRects[demoNum].top))
                for sprite in c.demoGroup:
                    sprite.setMonochromeImage()

            else:
                # Grey rects are drawn on all four sides of the display rect to ensure that all demo sprites outside of
                # the display rect are covered up.
                # The flashScreen function is called every frame, gradually decreasing the visibility of the white rect
                # covering the screen.
                c.SCREEN.fill(c.GREY)
                pg.draw.rect(c.SCREEN, c.BLACK, displayRects[demoNum])
                for sprite in c.demoGroup:
                    c.SCREEN.blit(sprite.image, sprite.coordinates)
                pg.draw.rect(c.SCREEN, c.GREY, (displayRects[demoNum].right, 0,
                                                c.SCREEN_SIZE[0] - displayRects[demoNum].right, c.SCREEN_SIZE[1]))
                pg.draw.rect(c.SCREEN, c.GREY, (0, 0, displayRects[demoNum].left, c.SCREEN_SIZE[1]))
                pg.draw.rect(c.SCREEN, c.GREY, (0, 0, c.SCREEN_SIZE[0], displayRects[demoNum].top))
                pg.draw.rect(c.SCREEN, c.BLACK, (nameRects[demoNum].left, nameRects[demoNum].top, 365, 65))
                c.SCREEN.blit(demoNameBlock.image, demoNameBlock.coordinates)
                c.SCREEN.blit(playerNames[demoNum], playerNameCoordinates[demoNum])
                alphaKey = flashScreen(frameCount, alphaKey)
                pg.display.update()
            c.CLOCK.tick(c.FPS)