Beispiel #1
0
 def initSounds(self):
     #Hit sound from:
     #https://www.freesound.org/people/radiopassiveboy/sounds/219266/
     self.soundHit = Sound("SFX/hit.ogg")
     #Mistake sound from:
     #https://www.freesound.org/people/zerolagtime/sounds/49238/
     self.soundMiss = Sound("SFX/miss.ogg")
Beispiel #2
0
 def __init__(self):
     Screen.__init__(self)
     self.sel = (0, 0)
     self.options = {"AUDIO": (("Play", lambda: Settings.AUDIO == 1, lambda: setattr(Settings, "AUDIO", 1) or Sound.cycleMusic()),
                               ("Mute", lambda: Settings.AUDIO == 0,
                                lambda: setattr(Settings, "AUDIO", 0) or Sound.stop_all(False))),
                     "GRAPHICS": (("High", lambda: Settings.GRAPHICS == 2, lambda: setattr(Settings, "GRAPHICS", 2)),
                                  ("Medium", lambda: Settings.GRAPHICS == 1, lambda: setattr(Settings, "GRAPHICS", 1)),
                                  ("Low", lambda: Settings.GRAPHICS == 0, lambda: setattr(Settings, "GRAPHICS", 0))),
                     "~": (("Return to Main Menu", lambda: False, lambda: MainMenu),)}
Beispiel #3
0
 def play(self, audio_file):
     if self._is_playing:
         return
     try:
         self._is_playing = 1
         self._snd = Sound.open(audio_file)
         if self._snd.state() == EOpen:
             self._snd.stop()  # Avoids runtime errors
             self._snd.play(callback=self._stop())
     except Exception, e:
         # NOTE: Log the error properly
         # debug('[Audio] - %s' % (str(e)), level='error')
         pass
Beispiel #4
0
    def tick(self, surface, delta, fontmap):
        scr = None

        # Paint the background
        surface.fill(pygame.color.Color("#222222"))

        # Paint title
        go = fontmap["title"].render("Credits", True, pygame.color.Color("#FFFFFF"))
        (w, h) = fontmap["title"].size("Credits")
        surface.blit(go, (Constants.WIDTH // 2 - w // 2, 60))

        # Paint the sections
        yoff = -200
        for section in ("krx\nProgrammer and Special Effects", "RedSoxFan\nProgrammer",
                        "Spetsnaz\nGame Idea", "s.a.x Software\nSaxMono Font", "Game Made In\nPython with pygame",
                        "Sound Effects Made In\nBFXR + LabChirp", "Music By\nSiriusBeat", "EXE Creation\npy2exe with pygame2exe script"):
            for i, text in enumerate(section.split("\n")):
                ttype = "msgtitle" if i == 0 else "msgbody"
                col = pygame.color.Color("#CCCCCC" if ttype == "msgtitle" else "#888888")
                sc = fontmap[ttype].render(text, True, col)
                (w, h) = fontmap[ttype].size(text)
                surface.blit(sc, (Constants.WIDTH // 2 - w // 2, Constants.HEIGHT // 2 - h // 2 + yoff))
                yoff += h + 2
            yoff += 15

        # Paint the return to main menu message
        txt = "Press <enter> to return to the Main Menu"
        msg = fontmap["hud"].render(txt, True, pygame.color.Color("#999999"))
        (w, h) = fontmap["hud"].size(txt)
        surface.blit(msg, (Constants.WIDTH // 2 - w // 2, Constants.HEIGHT - h - 10))

        # Check to see if enter is pressed
        if Keyboard.released(pygame.K_RETURN):
            Sound.play('menuselect')
            scr = MainMenu

        return scr
Beispiel #5
0
    def tick(self, surface, delta, fontmap):
        scr = None

        # Paint the background
        surface.fill(pygame.color.Color("#222222"))

        # Paint the title
        ttl = fontmap["title"].render(Constants.TITLE, True, pygame.color.Color("#FFFFFF"))
        (w, h) = fontmap["title"].size(Constants.TITLE)
        surface.blit(ttl, (Constants.WIDTH // 2 - w // 2, Constants.HEIGHT // 4 + h // 2))

        # Paint the options
        msel = -1
        for i, option in enumerate(MainMenu.options):
            # Get the bounding box
            (w, h) = fontmap["option"].size(option)
            (x, y) = (Constants.WIDTH // 2 - w // 2, Constants.HEIGHT // 2 + i * h * 2)
            # Determine if the option is highlighted or if the mouse is hovering over it
            m = Mouse.getX() in xrange(x, x + w) and Mouse.getY() in xrange(y, y + h)
            msel = i if m else msel
            s = self.sel == i or m
            # Paint the option
            txt = fontmap["option"].render(option, True, pygame.color.Color("#00FF00" if s else "#CCCCCC"))
            surface.blit(txt, (x, y))

        # Check for input
        if len(MainMenu.options) > 0:
            if Keyboard.released(pygame.K_DOWN):
                # If not at bottom, move the selection down
                Sound.play('menumove')
                self.sel = min(self.sel + 1, len(MainMenu.options) - 1)
            elif Keyboard.released(pygame.K_UP):
                # If not at top, move the selection up
                Sound.play('menumove')
                self.sel = max(0, self.sel - 1)
            elif Keyboard.released(pygame.K_RETURN):
                # Select the highlighted option
                Sound.play('menuselect')
                scr = MainMenu.screens[self.sel]
            elif msel >= 0 and Mouse.leftReleased():
                # Select the option that mouse is hovering over
                Sound.play('menuselect')
                scr = MainMenu.screens[msel]

        return scr
Beispiel #6
0
    def __init__(self):
        """Initialize running class."""
        self.config = ConfigParser()
        self.config.read('settings.ini')
        self.size_x = self.config.getint('screen', 'size_x')
        self.size_y = self.config.getint('screen', 'size_y')

        with open('languages.dat', 'rb') as lang_file:
            self.phrases = pickle.load(lang_file)[self.config.get(
                'total', 'language')]

        self.speech = Speech(self.config)
        self.speech.speak(self.phrases['start'])

        pygame.init()
        pygame.font.init()
        pygame.mixer.init()

        self.screen = pygame.display.set_mode((self.size_x, self.size_y))
        pygame.display.set_caption(self.phrases['title'])

        self.music = Music(self.config.getfloat('audio', 'music_volume'))
        self.sounds = Sound(self.config.getfloat('audio', 'sound_volume'))

        self.board = Board(self.config, self.screen, self.sounds)
        self.player = Player(self.board, self.speech, self.phrases)
        self.game_over = True
        self.win = False

        self.STOPPED_PLAYING = pygame.USEREVENT + 1
        pygame.mixer.music.set_endevent(self.STOPPED_PLAYING)
        self.fontObj = pygame.font.SysFont('arial', 50)
        self.clock = pygame.time.Clock()

        random.seed()
        self.music_play()
        self.new_game()
Beispiel #7
0
    def __init__(self, z=0, x=0, y=0, enemy=None):
        super().__init__(z, x, y)
        # This unit's health
        self.health = 100
        self.heart_rate = 10  # lower = faster heart animation speed
        self.bullets = []
        self.blocks = pygame.sprite.Group(
        )  # What sprites am I not allowd to cross?
        self.interactables = pygame.sprite.Group()
        self.hazards = []  # similar to interactables but dangerous!
        self.enemies = pygame.sprite.Group()
        self.stepTile = 0
        self.direction = 0
        self.angle = 0
        self.last_hit = pygame.time.get_ticks()
        self.move_timer = pygame.time.get_ticks()
        self.moveSpeed = 150
        self.delta = 512
        self.screen = None
        self.sounds = Sound()
        self.walk_sound = pygame.mixer.Sound('../assets/player/walk.wav')
        self.walk_timer = pygame.time.get_ticks()
        self.room = None
        # Where the player is positioned
        self.x = x
        self.y = y
        self.camera = None

        self.items = None  # set up by in engine in game.py
        self.inventory = {0: "None"}
        self.active_item = 0

        self.sheet = Spritesheet_Ext(
            '../assets/map assets/sprite sheets/Horror City - Frankenstein MV/Characters/$Dr Frankenstien.png',
            32, 48, 3, 4, 4, [96, 188], .5)
        self.sprites = self.sheet.sprites
        self.image = self.sprites[self.stepTile].image

        # timers
        self.shoot_timer = 20
        self.shoot_counter = self.shoot_timer
        self.spotted_timer = 30
        self.spotted_counter = self.spotted_timer
        self.interaction_timer = 20
        self.interaction_counter = self.interaction_timer
        self.interaction_counter_prev = -1
        self.interaction_timeout = 10
        # raycast init
        self.raycast_increments = 15
        self.raycast_points = [
            0 for i in range(360 // self.raycast_increments)
        ]
        self.sight_coords = [(-1, -1), (-1, -1), (-1, -1), (-1, -1)]

        self.rect = self.image.get_rect(
            center=(self.x, self.y)
        )  # the players collision mask, this determines when the player collides with things
        self.rect.width = self.rect.width // 2
        self.rect.height = self.rect.height // 2

        # How big the world is, so we can check for boundries
        self.world_size = (Settings.width, Settings.height)

        # Which collision detection function?
        self.collide_function = pygame.sprite.collide_rect
        self.collisions = []
        # For collision detection, we need to compare our sprite
        # with collideable sprites.  However, we have to remap
        # the collideable sprites coordinates since they change.
        # For performance reasons I created this sprite so we
        # don't have to create more memory each iteration of
        # collision detection.
        self.collider = Drawable()
        self.collider.image = pygame.Surface(
            [Settings.tile_size, Settings.tile_size])
        self.collider.rect = pygame.Rect(0, 0, 16, 16)

        self.cpoint = Drawable()
        self.cpoint.image = pygame.Surface(
            [Settings.tile_size, Settings.tile_size])
        self.cpoint.rect = pygame.Rect(0, 0, 1, 1)

        # Overlay
        self.font = pygame.font.Font('freesansbold.ttf', 32)
        self.overlay = self.font.render(
            str(self.health) + "        4 lives", True, (0, 0, 0))
Beispiel #8
0
class Player(Character):
    """This is a sample class for a player object.  A player
    is a character, is a drawable, and an updateable object.
    This class should handle everything a player does, such as
    moving, throwing/shooting, collisions, etc.  It was hastily
    written as a demo but should direction.
    """
    def __init__(self, z=0, x=0, y=0, enemy=None):
        super().__init__(z, x, y)
        # This unit's health
        self.health = 100
        self.heart_rate = 10  # lower = faster heart animation speed
        self.bullets = []
        self.blocks = pygame.sprite.Group(
        )  # What sprites am I not allowd to cross?
        self.interactables = pygame.sprite.Group()
        self.hazards = []  # similar to interactables but dangerous!
        self.enemies = pygame.sprite.Group()
        self.stepTile = 0
        self.direction = 0
        self.angle = 0
        self.last_hit = pygame.time.get_ticks()
        self.move_timer = pygame.time.get_ticks()
        self.moveSpeed = 150
        self.delta = 512
        self.screen = None
        self.sounds = Sound()
        self.walk_sound = pygame.mixer.Sound('../assets/player/walk.wav')
        self.walk_timer = pygame.time.get_ticks()
        self.room = None
        # Where the player is positioned
        self.x = x
        self.y = y
        self.camera = None

        self.items = None  # set up by in engine in game.py
        self.inventory = {0: "None"}
        self.active_item = 0

        self.sheet = Spritesheet_Ext(
            '../assets/map assets/sprite sheets/Horror City - Frankenstein MV/Characters/$Dr Frankenstien.png',
            32, 48, 3, 4, 4, [96, 188], .5)
        self.sprites = self.sheet.sprites
        self.image = self.sprites[self.stepTile].image

        # timers
        self.shoot_timer = 20
        self.shoot_counter = self.shoot_timer
        self.spotted_timer = 30
        self.spotted_counter = self.spotted_timer
        self.interaction_timer = 20
        self.interaction_counter = self.interaction_timer
        self.interaction_counter_prev = -1
        self.interaction_timeout = 10
        # raycast init
        self.raycast_increments = 15
        self.raycast_points = [
            0 for i in range(360 // self.raycast_increments)
        ]
        self.sight_coords = [(-1, -1), (-1, -1), (-1, -1), (-1, -1)]

        self.rect = self.image.get_rect(
            center=(self.x, self.y)
        )  # the players collision mask, this determines when the player collides with things
        self.rect.width = self.rect.width // 2
        self.rect.height = self.rect.height // 2

        # How big the world is, so we can check for boundries
        self.world_size = (Settings.width, Settings.height)

        # Which collision detection function?
        self.collide_function = pygame.sprite.collide_rect
        self.collisions = []
        # For collision detection, we need to compare our sprite
        # with collideable sprites.  However, we have to remap
        # the collideable sprites coordinates since they change.
        # For performance reasons I created this sprite so we
        # don't have to create more memory each iteration of
        # collision detection.
        self.collider = Drawable()
        self.collider.image = pygame.Surface(
            [Settings.tile_size, Settings.tile_size])
        self.collider.rect = pygame.Rect(0, 0, 16, 16)

        self.cpoint = Drawable()
        self.cpoint.image = pygame.Surface(
            [Settings.tile_size, Settings.tile_size])
        self.cpoint.rect = pygame.Rect(0, 0, 1, 1)

        # Overlay
        self.font = pygame.font.Font('freesansbold.ttf', 32)
        self.overlay = self.font.render(
            str(self.health) + "        4 lives", True, (0, 0, 0))

    def get_x(self):
        return self.rect.x

    def get_y(self):
        return self.rect.y

    def move_left(self, time):
        self.angle = 180
        now = pygame.time.get_ticks()
        if now - self.move_timer < self.moveSpeed:
            return

        self.get_animation(1)
        amount = self.delta * time
        try:
            if self.x - amount < 0:
                raise OffScreenLeftException
            else:
                self.x = self.x - amount
                now = pygame.time.get_ticks()
                if now - self.walk_timer > 300:
                    self.walk_sound.play()
                    self.walk_timer = now
                self.update(0)
                while (len(self.collisions) != 0):
                    self.x = self.x + amount
                    self.update(0)
        except:
            pass

    def move_right(self, time):
        self.angle = 0
        now = pygame.time.get_ticks()
        if now - self.move_timer < self.moveSpeed:
            return

        self.get_animation(2)
        self.collisions = []
        amount = self.delta * time
        try:
            if self.x + amount > self.world_size[0] - Settings.tile_size:
                raise OffScreenRightException
            else:
                self.x = self.x + amount
                now = pygame.time.get_ticks()
                if now - self.walk_timer > 300:
                    self.walk_sound.play()
                    self.walk_timer = now
                self.update(0)
                while (len(self.collisions) != 0):
                    self.x = self.x - amount
                    self.update(0)
        except:
            pass

    def move_up(self, time):
        self.angle = 270
        now = pygame.time.get_ticks()
        if now - self.move_timer < self.moveSpeed:
            return

        self.get_animation(3)
        self.collisions = []
        amount = self.delta * time
        try:
            if self.y - amount < 0:
                raise OffScreenTopException
            else:
                self.y = self.y - amount
                now = pygame.time.get_ticks()
                if now - self.walk_timer > 300:
                    self.walk_sound.play()
                    self.walk_timer = now
                self.update(0)
                if len(self.collisions) != 0:
                    self.y = self.y + amount
                    self.update(0)
                    self.collisions = []
        except:
            pass

    def move_down(self, time):
        self.angle = 90
        now = pygame.time.get_ticks()
        if now - self.move_timer < self.moveSpeed:
            return

        self.get_animation(0)
        self.collisions = []
        amount = self.delta * time
        try:
            if self.y + amount > self.world_size[1] - Settings.tile_size:
                raise OffScreenBottomException
            else:
                self.y = self.y + amount
                now = pygame.time.get_ticks()
                if now - self.walk_timer > 300:
                    self.walk_sound.play()
                    self.walk_timer = now
                self.update(0)
                if len(self.collisions) != 0:
                    self.y = self.y - amount
                    self.update(0)
                    self.collisions = []
        except:
            pass

    def get_animation(self, dir):
        self.move_timer = pygame.time.get_ticks()
        if self.direction != dir:
            self.direction = dir
            self.stepTile = 0 + (3 * dir)

        else:
            self.stepTile = ((self.stepTile + 1) % 3) + (3 * dir)

        self.image = self.sprites[self.stepTile].image

    def lineofsight_raycast(self, length, direction, precise=0):
        xx = int(self.rect.x + 16)
        yy = int(self.rect.y + 16)
        r = radians(direction)
        dirx = int(cos(r))
        diry = int(sin(r))
        # necessary for light raycasting
        if precise:
            dirx = cos(r)
            diry = sin(r)
        # find where the raycast SHOULD end up assuming nothing blocking it
        end_position = (xx + dirx * length, yy + diry * length)
        tempx = xx
        tempy = yy
        # loop through all positions in range
        for i in range(0, length, 8):
            self.cpoint.x = self.cpoint.rect.x = tempx
            self.cpoint.y = self.cpoint.rect.y = tempy
            # line of sight runs into wall
            if pygame.sprite.spritecollideany(self.cpoint,
                                              self.blocks) != None:
                end_position = (tempx, tempy)
                break
            # line of sight runs into enemy
            elif pygame.sprite.spritecollideany(
                    self.cpoint, self.enemies) != None and not precise:
                # find the specific enemy that has spotted the player
                for enemy in self.enemies:
                    # check if the correct enemy has been found
                    if pygame.sprite.collide_rect(self.cpoint, enemy):
                        if not dirx:
                            self.spotted_by_enemy(
                                enemy, 0,
                                copysign(-1,
                                         enemy.y - self.y))  # set enemy state
                        else:
                            self.spotted_by_enemy(
                                enemy, copysign(1, enemy.x - self.x), 0)

                end_position = (xx, yy)
                break

            tempx = xx + dirx * i
            tempy = yy + diry * i

        return end_position

    def light_raycast(self, length):
        for i in range(0, 360, self.raycast_increments):
            direction = i
            condition0 = (self.angle == 0 and (i >= 330 or i <= 30))
            condition90 = (self.angle == 90 and (i <= 120 and i >= 60))
            condition180 = (self.angle == 180 and (i <= 210 and i >= 150))
            condition270 = (self.angle == 270 and (i <= 300 and i >= 240))
            # extend the raycast if near player movement direction
            if condition0 or condition90 or condition180 or condition270:
                ray = self.lineofsight_raycast(length * 3, direction, 1)
                self.raycast_points[i // self.raycast_increments] = ray
            else:
                ray = self.lineofsight_raycast(length, direction, 1)
                self.raycast_points[i // self.raycast_increments] = ray

    def lineofsight_right(self, length):
        self.sight_coords[0] = self.lineofsight_raycast(length, 0)
        return self.sight_coords[0]

    def lineofsight_left(self, length):
        self.sight_coords[1] = self.lineofsight_raycast(length, 180)
        return self.sight_coords[1]

    def lineofsight_up(self, length):
        self.sight_coords[2] = self.lineofsight_raycast(length, 90)
        return self.sight_coords[2]

    def lineofsight_down(self, length):
        self.sight_coords[3] = self.lineofsight_raycast(length, 270)
        return self.sight_coords[3]

    def spotted_by_enemy(self, enemy, dirx, diry):
        # the 'trapped' state is state 3, enemies should be unable to move in this case
        if enemy.state == 3:
            return
        enemy.state = 2
        # enemy chase state is 2
        enemy.sight_counter = enemy.sight_timeout  # reset the enemy chase timer
        enemy.target = self
        enemy.dirx = dirx  # target x direction to move to
        enemy.diry = diry  # target y direction to move to

        # increase heart rate and set counter for when to catch breath
        self.spotted_counter = self.spotted_timer
        self.heart_rate = 3

        return

    def interact(self, time):
        # check to make sure the player is in range of an interactable object
        if not pygame.sprite.spritecollideany(self, self.interactables):
            return

        # check for interaction buffer
        if self.interaction_counter > self.interaction_timer:
            return  # player must wait before another action

        # set the interaction timer, must be held to complete action
        if self.interaction_counter <= 0:
            self.interaction_counter = self.interaction_timer + 10  # reset interaction timer
            self.interaction_timeout = 10

            # loop through the interactable sprite group
            for sprite in self.interactables:
                if pygame.sprite.collide_rect(self, sprite):
                    # check for door opening case
                    if sprite.isDoor == 1:
                        self.sounds.play_door_sound()
                        sprite.changeRoom()  # run the door opening code
                        return
                    self.inventory[self.active_item] = sprite.contents

        else:
            # decrement timer
            self.interaction_counter -= 1

    def use_active_item(self, time):
        # get direction player is facing, important for placing items
        r = radians(self.direction)
        tarx = self.rect.x + int(cos(r)) * 3
        tary = self.rect.y + int(sin(r)) * 3

        # beartrap use code
        if self.inventory[self.active_item] == "beartrap":
            self.create_physical_item(0, 1, BearTrap(tarx, tary))

        # lantern use code
        elif self.inventory[self.active_item] == "lantern":
            self.create_physical_item(0, 0, Lantern(tarx - 64, tary - 64))

        # rancid meat
        elif self.inventory[self.active_item] == "rancidmeat":
            self.create_physical_item(0, 1, RancidMeat(tarx, tary))

        self.inventory[
            self.active_item] = "None"  # empty out the current inventory slot

    def create_physical_item(self, impassable, hazard, item):
        if impassable:
            self.blocks.append(item)

        if hazard:
            self.hazards.append(item)
        # add a new object to the list of entities created from user input
        self.items.append(item)

    def reset_all_timers(self):
        self.shoot_counter = self.shoot_timer
        self.spotted_counter = self.spotted_timer
        self.interaction_counter = self.interaction_timer

    def update(self, time):

        if (self.sight_coords[0][0] < 0):
            # light raycasts stuff (drawing happens in engine!)
            self.light_raycast(50)

        # events which should not occur on every update call
        if time != 0:
            self.shoot_counter -= 1
            self.spotted_counter -= 1
            if self.spotted_counter <= 0:
                self.heart_rate = 10
            # necessary counter buffer so the player can't spam interactions
            # all other interaction updates occur in the interaction function
            if self.interaction_counter > self.interaction_timer:
                self.interaction_counter -= 1
            # run all line of sight raycasts
            self.lineofsight_right(200)
            self.lineofsight_left(200)
            self.lineofsight_up(200)
            self.lineofsight_down(200)
            # light raycasts stuff (drawing happens in engine!)
            self.light_raycast(50)
        # check for redundant action meter display
        elif self.interaction_counter < self.interaction_timer:
            keys_pressed = pygame.key.get_pressed()  # get all pressed keys
            # check to make sure the player is still pressing the interact button
            if keys_pressed[pygame.K_e] != 1:
                # if the action meter is display (meaning the player pressed e) but has stopped pressing the interact button
                # change the counter values so that the overlay stops showing the action meter
                self.interaction_counter = self.interaction_timer + 10

        # collision stuffs
        self.collisions = []
        prevrect = (self.get_x(), self.get_y())
        self.collider.x = self.collider.rect.x = self.rect.x = self.x
        self.collider.y = self.collider.rect.y = self.rect.y = self.y
        for sprite in self.blocks:
            self.collider.rect.x = sprite.x
            self.collider.rect.y = sprite.y
            if pygame.sprite.collide_rect(self, self.collider):
                self.collisions.append(sprite)

        if pygame.sprite.spritecollideany(self, self.enemies):
            self.reset_room()

    def ouch(self):
        now = pygame.time.get_ticks()
        if now - self.last_hit > 1000:
            self.health = self.health - 10
            self.last_hit = now

    def reset_room(self):
        self.room.engine.changeRoom(self.room.current_room)
        self.x = self.resetx
        self.y = self.resety

    def getX(self):
        return self.x

    def getY(self):
        return self.y
Beispiel #9
0
    def tick(self, surface, delta, platforms):
        msgs = []
        if self.disphealth > self.health:
            self.disphealth = Arithmetic.clamp(self.health, self.maxhealth, self.disphealth - ceil((self.disphealth - self.health) / 30.0))

        if Settings.GRAPHICS >= 2 and self.innerfire:
            self.generateInnerFire()

        # If alive, tick
        if self.health > 0:
            # Check for a resize
            if Keyboard.down(Constants.GROW_KEY):
                width = min(self.rect.width + Constants.SIZE_INTERVAL, Constants.MAX_PLAYER_WIDTH)
                height = min(self.rect.height + Constants.SIZE_INTERVAL, Constants.MAX_PLAYER_HEIGHT)
                self.image = pygame.transform.scale(self.image, (width, height)).convert_alpha()
                center = self.rect.center
                self.rect.size = self.image.get_rect().size
                self.rect.center = center
                self.__draw_image()
            elif Keyboard.down(Constants.SHRINK_KEY):
                width = max(Constants.MIN_PLAYER_WIDTH, self.rect.width - Constants.SIZE_INTERVAL)
                height = max(Constants.MIN_PLAYER_HEIGHT, self.rect.height - Constants.SIZE_INTERVAL)
                self.image = pygame.transform.scale(self.image, (width, height)).convert_alpha()
                center = self.rect.center
                self.rect.size = self.image.get_rect().size
                self.rect.center = center
                self.__draw_image()
            # If not in the center, fall to center of the screen
            if self.rect.centery < Constants.HEIGHT // 4:
                self.rect.y += ceil(Constants.GRAVITY / Constants.FPS * delta)
                self.rect.y = min(Constants.HEIGHT // 4, self.rect.y)
            else:
                self.ready = True
            # Check collision with platforms
            for p in pygame.sprite.spritecollide(self, platforms, False):
                if not p.can_break(self.force):
                    msgs.append(Message("Splat\n-%d" % self.health, self.rect.right + 100, self.rect.centery, "bad"))
                    self.health = 0
                    break
                elif p.can_splinter(self.force):
                    Sound.play('hit{}'.format(randint(1, 3)))
                    self.health = max(0, self.health - p.damage)
                    self.destroyPlatform(p, True)
                    p.kill()
                    msgs.append(Message("Splinter\n-%d" % p.damage, self.rect.right + 100, self.rect.centery, "bad"))
                else:
                    Sound.play('hit{}'.format(randint(1, 3)))
                    self.destroyPlatform(p, False)
                    p.kill()
        else:
            # Death sequence
            if self.rect.width > 2:
                # Shrink until tiny
                width = Arithmetic.clamp(2, Constants.MAX_PLAYER_WIDTH, self.rect.width - 3 * Constants.SIZE_INTERVAL)
                height = Arithmetic.clamp(2, Constants.MAX_PLAYER_HEIGHT, self.rect.height - 3 * Constants.SIZE_INTERVAL)
                self.image = pygame.transform.scale(self.image, (width, height)).convert_alpha()
                center = self.rect.center
                self.rect.size = self.image.get_rect().size
                self.rect.center = center
                self.__draw_image()
            elif not self.sploded:
                # splode
                Sound.play('explode')
                self.sploded = True
                self.innerfire = False
                self.image.fill(pygame.Color(0, 0, 0))

                # Line particles
                for i in xrange(randint(20, 40)):
                    angle = random() * 2.0 * pi
                    speed = random() * 5.0 + 2.5
                    rotRate = random() * (0.5 * pi) - (0.25 * pi)
                    size = randint(3, 17)
                    self.particles.append(FlippyLineParticle([self.rect.center[0], self.rect.center[1]], size, [speed * cos(angle), speed * sin(angle)], pygame.Color(0, 255, 0), random() * 2.0 * pi, rotRate, mingfx=1))

                # Fire particles
                for i in xrange(randint(200, 500)):
                    angle = random() * 2.0 * pi
                    speed = random() * 5.0 + 1.0
                    size = randint(1, 3)
                    self.particles.append(FadingParticle([self.rect.center[0], self.rect.center[1]], size, [speed * cos(angle), speed * sin(angle)], pygame.Color(0, 255, 0), 6, mingfx=1))

        # If on screen, paint
        if self.rect.bottom > 0:
            surface.blit(self.image, (self.rect.x, self.rect.y))
        return msgs
Beispiel #10
0
    def tick(self, surface, delta, fontmap):
        scr = None

        # Paint the background
        surface.fill(pygame.color.Color("#222222"))

        # Paint title
        go = fontmap["title"].render("Info", True, pygame.color.Color("#FFFFFF"))
        (w, h) = fontmap["title"].size("Info")
        surface.blit(go, (Constants.WIDTH // 2 - w // 2, 100))

        # Paint the sections
        yoff = 200
        for section in ("Objective\nTo get as far down the abyss as possible",
                        "Controls\nUp Arrow - Grow\nDown Arrow - Shrink",
                        "How To Play\n[Grow or shrink the player to either reduce or increase force. You "
                        "will need to have enough force to break the platform (40% of the width). If you "
                        "don't, you will splat and die. Also, if you have enough force to break the "
                        "platform, but not cleanly (60% of the width), you will cause the platform "
                        "to splinter, which will damage you.]"):
            for i, text in enumerate(section.split("\n")):
                ttype = "msgtitle" if i == 0 else "msgbody"
                col = pygame.color.Color("#CCCCCC" if ttype == "msgtitle" else "#888888")
                if text.startswith("[") and text.endswith("]"):
                    words = text[1:-1].split(" ")
                    text = ""
                    while len(words) > 0:
                        (w, h) = fontmap[ttype].size("%s %s" % (text, words[0]))
                        if w < Constants.WIDTH - 20:
                            text = "%s %s" % (text, words[0])
                            words = words[1:]
                        else:
                            sc = fontmap[ttype].render(text, True, col)
                            (w, h) = fontmap[ttype].size(text)
                            surface.blit(sc, (Constants.WIDTH // 2 - w // 2, yoff))
                            yoff += h + 2
                            text = ""
                    if len(text) > 0:
                        sc = fontmap[ttype].render(text, True, col)
                        (w, h) = fontmap[ttype].size(text)
                        surface.blit(sc, (Constants.WIDTH // 2 - w // 2, yoff))
                        yoff += h + 2
                else:
                    # Line
                    sc = fontmap[ttype].render(text, True, col)
                    (w, h) = fontmap[ttype].size(text)
                    surface.blit(sc, (Constants.WIDTH // 2 - w // 2, yoff))
                    yoff += h + 2
            yoff += 20

        # Paint the return to main menu message
        txt = "Press <enter> to return to the Main Menu"
        msg = fontmap["hud"].render(txt, True, pygame.color.Color("#999999"))
        (w, h) = fontmap["hud"].size(txt)
        surface.blit(msg, (Constants.WIDTH // 2 - w // 2, Constants.HEIGHT - h - 10))

        # Check to see if enter is pressed
        if Keyboard.released(pygame.K_RETURN):
            Sound.play('menuselect')
            scr = MainMenu

        return scr
Beispiel #11
0
    def tick(self, surface, delta, fontmap):
        scr = None

        # Paint the background
        surface.fill(pygame.color.Color("#222222"))

        # Paint the title
        ttl = fontmap["title"].render("Settings", True, pygame.color.Color("#FFFFFF"))
        (w, h) = fontmap["title"].size("Settings")
        surface.blit(ttl, (Constants.WIDTH // 2 - w // 2, Constants.HEIGHT // 4 + h // 2))

        # Paint the options
        mcb = None
        yoff = 0
        for i, key in enumerate(sorted(self.options.keys())):
            # Get the bounding box
            (w, h) = fontmap["msgtitle"].size(key.replace("~", ""))
            (x, y) = (Constants.WIDTH // 2 - w // 2, Constants.HEIGHT // 2 + yoff)
            # Paint the option
            txt = fontmap["msgtitle"].render(key.replace("~", ""), True, pygame.color.Color("#CCCCCC"))
            surface.blit(txt, (x, y))
            yoff += h + 2

            for j, (txt, val, cb) in enumerate(self.options[key]):
                # Get the bounding box
                (w, h) = fontmap["msgbody"].size(txt)
                (x, y) = (Constants.WIDTH // 2 - w // 2, Constants.HEIGHT // 2 + yoff)
                # Determine if the option is highlighted or if the mouse is hovering over it
                m = Mouse.getX() in xrange(x, x + w) and Mouse.getY() in xrange(y, y + h)
                mcb = cb if m else mcb
                s = self.sel == (i, j) or m
                # Paint the option
                col = "#008800" if val() else "#CCCCCC"
                txt = fontmap["msgbody"].render(txt, True, pygame.color.Color("#00FF00" if s else col))
                surface.blit(txt, (x, y))
                yoff += h + 2

            yoff += 20

        # Check for input
        if len(MainMenu.options) > 0:
            if Keyboard.released(pygame.K_DOWN):
                # If not at bottom, move the selection down
                if self.sel[1] < len(self.options[sorted(self.options.keys())[self.sel[0]]]) - 1:
                    self.sel = (self.sel[0], self.sel[1] + 1)
                    Sound.play('menumove')
                elif self.sel[0] < len(self.options.keys()) - 1:
                    self.sel = (self.sel[0] + 1, 0)
                    Sound.play('menumove')
            elif Keyboard.released(pygame.K_UP):
                # If not at top, move the selection up
                if self.sel[1] > 0:
                    self.sel = (self.sel[0], self.sel[1] - 1)
                    Sound.play('menumove')
                elif self.sel[0] > 0:
                    self.sel = (self.sel[0] - 1, len(self.options[sorted(self.options.keys())[self.sel[0] - 1]]) - 1)
                    Sound.play('menumove')
            elif Keyboard.released(pygame.K_RETURN):
                # Select the highlighted option
                scr = self.options[sorted(self.options.keys())[self.sel[0]]][self.sel[1]][2]()
                Sound.play('menuselect')
            elif mcb is not None and Mouse.leftReleased():
                # Select the option that mouse is hovering over
                scr = mcb()
                Sound.play('menuselect')

        return scr
Beispiel #12
0
    def __init__(self):
        """Initialize running class."""
        self.config = ConfigParser()
        self.config.read('settings.ini')

        if self.config.getboolean('total', 'debug'):
            if getattr(sys, 'frozen', False):
                self.logger = Logger(
                    os.path.join(os.path.dirname(sys.executable),
                                 self.__class__.__name__))
            else:
                self.logger = Logger(
                    os.path.join(os.getcwd(), self.__class__.__name__))
        self.log = logging.getLogger()
        self.log.info(__name__ + ': ' + 'def ' + self.__init__.__name__ +
                      '(): ' + self.__init__.__doc__)

        self.size_x = self.config.getint('screen', 'size_x')
        self.size_y = self.config.getint('screen', 'size_y')

        with open('languages.dat', 'rb') as lang_file:
            self.phrases = pickle.load(lang_file)[self.config.get(
                'total', 'language')]

        self.speech = Speech(self.config)
        self.speech.speak(self.phrases['start'], True)

        pygame.init()
        pygame.font.init()
        pygame.mixer.init()

        self.screen = pygame.display.set_mode((self.size_x, self.size_y))
        pygame.display.set_caption(self.phrases['title'])

        self.music = Music(self.config.getfloat('audio', 'music_volume'))
        self.sounds = Sound(self.config.getfloat('audio', 'sound_volume'))

        self.menu = Menu(self.config, self.screen, self.speech, self.phrases,
                         self.sounds)
        self.menu_flag = True
        menu_functions = [self.new_game, self.rules, self.help, self.exit]
        self.menu.set_functions(menu_functions)

        self.board = Board(self.config, self.screen, self.sounds)
        self._ai = AI(self.board, self.speech, self.phrases)
        self.player = Player(self.board, self.speech, self.phrases, self._ai)
        self._ai.gamer = self.player
        self._ai.player.behaviors.set_controllers(self._ai)
        self.running = True
        self.game_over = True
        self.win = False

        self.handle_numbers = {'K_' + str(num): num for num in range(1, 10)}
        self.handle_numbers.update(
            {'K_KP' + str(num): num
             for num in range(1, 10)})

        self.font_obj = pygame.font.SysFont('arial', 50)
        self.clock = pygame.time.Clock()

        self.music_play()
        self.menu.activate(self.menu_flag)
Beispiel #13
0
# Copyright (c) 2005 Nokia Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import e32
from audio import Sound

SLEEP = 7

player = Sound()
player.open(u'c:\\Baby_One_More_Time.mid')
player.play()
e32.ao_sleep(SLEEP - 2)
player.stop()  #does not close the file

player.open(u'c:\\foobar.wav')
player.record()
e32.ao_sleep(SLEEP)
player.stop()
player.close()  #needed for sound flushing, otherwise not written
Beispiel #14
0
class PygameGame(object):
    def __init__(self, width=1500, height=850,fps=60, 
                    title="My Game"):
        (self.width, self.height) = (width, height)
        self.fps = fps
        self.title = title
        iconPath = os.path.normpath("Pictures/icon.png")
        self.icon = pygame.image.load(iconPath)

        self.initModes()
        self.initBeats()
        self.initTracking()

        #Create an event that will trigger when the song finishes.
        self.PLAYBACK_END = pygame.USEREVENT + 1

        #Global delay of 450ms seems the best, as there is a noticeable delay
        #in pygame audio otherwise.
        #Need to start time a second early because we add a beat a second early.
        self.audioDelay = -1.45
        self.timeElapsed = 0 + self.audioDelay
        #We want the game to end a bit after the song playback ends, so we add
        #a delayed end timer
        self.endDelay = 2.0
        self.countdown = None

        #Preinitializing with this buffer value helps with audio lag.
        pygame.mixer.pre_init(buffer=1024)
        pygame.mixer.init()
        self.initSounds()
        pygame.display.set_icon(self.icon)
        pygame.init()
        pygame.font.init()

    def initTracking(self):
        self.combo = 0
        self.maxCombo = 0
        self.score = 0
        self.prevAddition = 0
        self.lastBeatHit = (0, 0)
        self.hits = pygame.sprite.Group()
        self.hitKill = 0.5

    def initModes(self):
        self.inGame = True
        self.inMenu = True
        self.songSelect = False
        self.instructions = False
        self.playSong = False
        self.scoreScreen = False
        self.paused = False
        self.error = False

    def initMenu(self):
        #Needed for copy/paste support.
        pygame.scrap.init()

        #Menu picture from: https://goo.gl/bwppX2
        path = "Pictures/menu.png"
        path = os.path.normpath(path)
        self.menu = pygame.image.load(path)
        self.menu.convert()
        self.menuButtons = pygame.sprite.Group()
        self.initMenuButtons()

        path = "Pictures/loading.png"
        path = os.path.normpath(path)
        self.loadScreen = pygame.image.load(path)
        self.loadScreen.convert()

        path = "Pictures/paused.png"
        path = os.path.normpath(path)
        self.pauseScreen = pygame.image.load(path)
        self.pauseScreen.convert()

    def initMenuButtons(self):
        (logoX, logoY) = (50, 275)
        (logoW, logoH) = (700, 300)
        logoPath = "Pictures/Logo.png"
        logo = Button(logoPath, logoX, logoY, logoW, logoH)

        (playX, playY) = (850, 210)
        (playW, playH) = (500, 200)
        playPath = "Pictures/Buttons/Play.png"
        self.playButton = Button(playPath, playX, playY, playW, playH)

        (howToX, howToY) = (850, 460)
        (howToW, howToH) = (500, 150)
        howToPath = "Pictures/Buttons/HowTo.png"
        self.howToButton = Button(howToPath, howToX, howToY, howToW, howToH)

        logo.add(self.menuButtons)
        self.playButton.add(self.menuButtons)
        self.howToButton.add(self.menuButtons)

    def initMenuMusic(self):
        #Menu music taken from: http://www.newgrounds.com/audio/listen/438759
        menuMusicPath = "SFX/menu.ogg"
        pygame.mixer.music.load(menuMusicPath)

        #Repeat menu music indefinitely.
        pygame.mixer.music.play(loops=-1)

    def initBeats(self):
        self.r = 50
        self.beats = pygame.sprite.Group()

        #Having a separate queue allows for indexing (so we can pull the most
        #recent beat)
        self.beatQueue = deque()

        #Choices of color for beats: Red, Blue, Green, Orange
        self.colorChoices = [(255,0,0),(0,0,255),(24,226,24),(247,162,15)]
        self.beatColor = (0, 0, 0)
        self.shuffleColor()

        #Needed in order to properly randomize beat positions.
        self.prevX = None
        self.prevY = None
        self.maxDist = 200
        self.minDist = 100
        self.beatNum = 1
        self.beatNumMax = 4

        self.initBeatTiming()
        self.initScoring()

    def initScoring(self):
        self.scoreBad = 50
        self.scoreGood = 100
        self.scorePerfect = 300

        self.misses = 0
        self.bads = 0
        self.goods = 0
        self.perfects = 0

    def initBeatTiming(self):
        #Beats appear a second early (beatApproach), and the width between the
        #different scores is dictated by windowWidth.
        self.beatApproach = 1.0
        self.windowWidth = 0.06

        self.goodLate = self.beatApproach + self.windowWidth
        self.badLate = self.goodLate + self.windowWidth
        self.missLate = self.badLate + self.windowWidth
        self.beatKill = self.missLate + self.windowWidth

        self.perfectEarly = self.beatApproach - self.windowWidth
        self.goodEarly = self.perfectEarly - self.windowWidth
        self.badEarly = self.goodEarly - self.windowWidth
        self.missEarly = self.badEarly - self.windowWidth

    def initSong(self, path):
        self.songPath = os.path.normpath(self.songPath)

        startTime = time.time()
        self.song = Song(self.songPath)
        self.times = self.song.getBeatTimes()
        self.nextBeat = self.times.pop(0)
        pygame.mixer.music.load(self.songPath)
        endTime = time.time()
        
        loadTime = abs(endTime - startTime)
        #Necessary offset, or else song and game go out of sync.
        self.timeElapsed -= loadTime

    def initSounds(self):
        #Hit sound from:
        #https://www.freesound.org/people/radiopassiveboy/sounds/219266/
        self.soundHit = Sound("SFX/hit.ogg")
        #Mistake sound from:
        #https://www.freesound.org/people/zerolagtime/sounds/49238/
        self.soundMiss = Sound("SFX/miss.ogg")
        
    def initHowTo(self):
        self.howToItems = pygame.sprite.Group()

        (x, y) = (250, 100)
        (width, height) = (1200, 700)
        path = "Pictures/HowTo.png"
        howToPlay = Button(path, x, y, width, height)

        (x, y) = (260, 50)
        (width, height) = (600, 50)
        path = "Pictures/HowToHeader.png"
        howToHeader = Button(path, x, y, width, height)

        (x, y) = (50, 50)
        (width, height) = (175, 750)
        path = "Pictures/Buttons/Back.png"
        self.toMenu = Button(path, x, y, width, height)

        howToPlay.add(self.howToItems)
        howToHeader.add(self.howToItems)
        self.toMenu.add(self.howToItems)

    def initSongSelect(self):
        self.songSelItems = pygame.sprite.Group()
        #Spacing between song select buttons.
        spacing = 5 + 120

        self.initInput()

        (x, y, width, height) = (50, 50, 800, 175)
        path = "Pictures/TextInput.png"
        self.textInput = Button(path, x, y, width, height)
        self.textInput.add(self.songSelItems)

        (x, y0, width, height) = (950, 50, 500, 120)
        applePath = "Pictures/Song Select/badAppleBox.png"
        self.badAppleBox = Button(applePath, x, y0, width, height)
        self.badAppleBox.add(self.songSelItems)

        y1 = y0 + spacing
        bonePath = "Pictures/Song Select/bonetrousleBox.png"
        self.bonetrousleBox = Button(bonePath, x, y1, width, height)
        self.bonetrousleBox.add(self.songSelItems)

        y2 = y1 + spacing
        dummyPath = "Pictures/Song Select/dummyBox.png"
        self.dummyBox = Button(dummyPath, x, y2, width, height)
        self.dummyBox.add(self.songSelItems)

        #I hate you, arbitrary 20-line limit.
        self.initSongSelect2(x, width, height, y2, spacing)

    def initSongSelect2(self, x, width, height, y2, spacing):
        y3 = y2 + spacing
        megaPath = "Pictures/Song Select/megalovaniaBox.png"
        self.megalovaniaBox = Button(megaPath, x, y3, width, height)
        self.megalovaniaBox.add(self.songSelItems)

        y4 = y3 + spacing
        rhinePath = "Pictures/Song Select/rhinestoneBox.png"
        self.rhinestoneBox = Button(rhinePath, x, y4, width, height)
        self.rhinestoneBox.add(self.songSelItems)

        y5 = y4 + spacing
        goodPath = "Pictures/Song Select/feelgoodBox.png"
        self.feelgoodBox = Button(goodPath, x, y5, width, height)
        self.feelgoodBox.add(self.songSelItems)

        self.backSmallGrp = pygame.sprite.GroupSingle()
        (width, height) = (175, 175)
        (x, y) = (50, self.height - 50 - height)
        path = "Pictures/Buttons/BackSmall.png"
        self.backSmall = Button(path, x, y, width, height)
        self.backSmall.add(self.backSmallGrp)

        self.initError()
        self.initTextClear()

    def initInput(self):
        menuFont = "Fonts/SourceCodePro-Regular.ttf"
        font = pygame.font.Font(menuFont, 25)
        textColor = (217, 230, 255)
        self.usrSong = eztext.Input(color=textColor, maxlength=50, x=70, 
            y=150, font=font)

    def initError(self):
        self.oops = pygame.sprite.GroupSingle()
        (x, y) = (50, 250)
        (width, height) = (800, 350)
        path = "Pictures/Error.png"
        self.errorMessage = Button(path, x, y, width, height)
        self.errorMessage.add(self.oops)

    def initTextClear(self):
        self.clearTextGrp = pygame.sprite.GroupSingle()
        (x, y) = (860, 50)
        (width, height) = (40, 175)
        path = "Pictures/Buttons/Clear.png"
        self.clearText = Button(path, x, y, width, height)
        self.clearText.add(self.clearTextGrp)

    def run(self):
        clock = pygame.time.Clock()
        self.screen = pygame.display.set_mode((self.width, self.height))
        pygame.display.set_caption(self.title)
        self.initMenu()
        self.initHowTo()
        self.initSongSelect()

        while self.inGame:
            self.mainLoop(clock)

        pygame.font.quit()
        pygame.mixer.quit()
        pygame.quit()

###############################################################################
########################### Loop code starts here #############################
###############################################################################
    def mainLoop(self, clock):
        if not pygame.mixer.music.get_busy():
            self.initMenuMusic()

        while self.inMenu:
            self.menuLoop(clock)

        while self.instructions:
            self.instructionLoop(clock)

        while self.songSelect:
            self.songSelectLoop(clock)

        if self.playSong:
            pygame.mixer.music.play()
            pygame.mixer.music.set_endevent(self.PLAYBACK_END)

        while self.playSong:
            self.songLoop(clock)

        while self.scoreScreen:
            self.scoreScreenLoop(clock)
        
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self.inGame = False

        self.mainLoopUpdate()

    def menuLoop(self, clock):
        clock.tick(self.fps)

        self.screen.blit(self.menu, (0, 0))
        self.menuButtons.draw(self.screen)
        pygame.display.flip()

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self.inGame = False
                self.inMenu = False
            elif ((event.type == pygame.MOUSEBUTTONDOWN) and 
                    (event.button == 1)):
                self.mousePressed()

    def instructionLoop(self, clock):
        clock.tick(self.fps)

        self.screen.blit(self.menu, (0, 0))
        self.howToItems.draw(self.screen)
        pygame.display.flip()

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self.inGame = False
                self.instructions = False
            elif event.type == pygame.KEYDOWN:
                if (event.key == pygame.K_ESCAPE):
                    self.soundMiss.play()
                    self.instructions = False
                    self.inMenu = True
            elif ((event.type == pygame.MOUSEBUTTONDOWN) and
                    (event.button == 1)):
                self.mousePressed()

    def songSelectLoop(self, clock):
        clock.tick(self.fps)

        events = pygame.event.get()

        self.songSelUpdate(events)

        if self.error:
            self.oops.draw(self.screen)

        pygame.display.flip()

        for event in events:
            if event.type == pygame.QUIT:
                self.inGame = False
                self.songSelect = False
            elif event.type == pygame.KEYDOWN:
                if (event.key == pygame.K_ESCAPE):
                    self.soundMiss.play()
                    self.songSelect = False
                    self.inMenu = True
            elif ((event.type == pygame.MOUSEBUTTONDOWN) and
                    (event.button == 1)):
                self.mousePressed()

    def songLoop(self, clock):
        #tick_busy_loop is more expensive (more accurate too) than just
        #clock.tick, but this is necessary in a rhythm game.
        tick = clock.tick_busy_loop(self.fps) / 1000 #Convert to seconds
        if not self.paused:
            pygame.mixer.music.unpause()
            self.timeElapsed += tick
            self.gameTimerFired(self.timeElapsed, tick)

        for event in pygame.event.get():
            self.actEvent(event)

        if self.paused:
            pygame.mixer.music.pause()

        if self.countdown != None:
            self.countdown -= tick
            if self.countdown <= 0:
                self.playSong = False
                self.scoreScreen = True

        self.songLoopUpdate()

    def scoreScreenLoop(self, clock):
        clock.tick(self.fps)

        if not pygame.mixer.music.get_busy():
                self.initMenuMusic()

        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self.inGame = False
                self.scoreScreen = False
            elif event.type == pygame.KEYDOWN:
                if (event.key == pygame.K_ESCAPE):
                    self.soundMiss.play()
                    self.scoreScreen = False
                    self.songSelect = True
                    self.reset()
            elif ((event.type == pygame.MOUSEBUTTONDOWN) and
                    (event.button == 1)):
                self.mousePressed()

        self.screen.blit(self.menu, (0, 0))
        self.scoreItems.draw(self.screen)
        self.printScoreText()
        pygame.display.flip()

    def mainLoopUpdate(self):
        BLACK = (0, 0, 0)
        self.screen.fill(BLACK)
        pygame.display.flip()

    def songSelUpdate(self, events):
        self.screen.blit(self.menu, (0, 0))
        self.backSmallGrp.draw(self.screen)
        self.songSelItems.draw(self.screen)
        self.clearTextGrp.draw(self.screen)
        self.usrSong.update(events)
        self.usrSong.draw(self.screen)

    def songLoopUpdate(self):
        if not self.paused:
            BLACK = (0, 0, 0)
            self.screen.fill(BLACK)
            self.printText()
            self.hits.draw(self.screen)
            self.beats.draw(self.screen)
            if self.countdown != None:
                fadeOut = pygame.Surface((self.width, self.height))
                BLACK = (0, 0, 0)
                fadeOut.fill(BLACK)
                alpha = int((1 - self.countdown/self.endDelay) * 255)
                alpha = max(alpha, 0)
                fadeOut.set_alpha(alpha)
                self.screen.blit(fadeOut, (0,0))
        if self.paused:
            self.screen.blit(self.pauseScreen, (0,0))

        pygame.display.flip()

    def actEvent(self, event):
        if event.type == pygame.QUIT:
            self.inGame = False
            self.playSong = False
        elif event.type == pygame.KEYDOWN:
            if event.key == pygame.K_ESCAPE: self.paused = not self.paused
            if self.paused:
                if event.key == pygame.K_r:
                    self.reset()
                    self.songSelect = True
                    return
            elif not self.paused:
                if (event.key == pygame.K_z or event.key == pygame.K_x):
                    self.beatPressed()
        if not self.paused:
            if event.type == pygame.MOUSEBUTTONDOWN: self.beatPressed()
            elif event.type == self.PLAYBACK_END:
                if (self.combo > self.maxCombo): self.maxCombo = self.combo
                self.initScoreScreen()
                self.countdown = self.endDelay

    def mousePressed(self):
        (x, y) = pygame.mouse.get_pos()
        click = MousePointer(x, y)

        if self.inMenu:
            self.checkMenuCollision(click)
        elif self.instructions:
            self.checkHowToCollision(click)
        elif self.songSelect:
            self.checkSongSelCollision(click)
        elif self.scoreScreen:
            self.checkScoreCollision(click)

    def checkMenuCollision(self, click):
        if pygame.sprite.collide_rect(self.playButton, click):
            self.soundHit.play()
            self.songSelect = True
            self.inMenu = False
        elif pygame.sprite.collide_rect(self.howToButton, click):
            self.soundHit.play()
            self.instructions = True
            self.inMenu = False

    def checkHowToCollision(self, click):
        if pygame.sprite.collide_rect(self.toMenu, click):
            self.soundMiss.play()
            self.instructions = False
            self.inMenu = True

    def checkSongSelCollision(self, click):
        self.checkSelectedSong(click)

        if pygame.sprite.collide_rect(self.clearText, click):
            self.soundMiss.play()
            self.usrSong.clear()

        if pygame.sprite.collide_rect(self.backSmall, click):
            self.soundMiss.play()
            self.songSelect = False
            self.inMenu = True

        if pygame.sprite.spritecollideany(click, self.songSelItems):
            self.soundHit.play()
            self.play()

    def checkSelectedSong(self, click):
        if pygame.sprite.collide_rect(self.badAppleBox, click):
            self.songPath = "Songs/Bad Apple.mp3"
        elif pygame.sprite.collide_rect(self.bonetrousleBox, click):
            self.songPath = "Songs/Bonetrousle.ogg"
        elif pygame.sprite.collide_rect(self.dummyBox, click):
            self.songPath = "Songs/Dummy!.ogg"
        elif pygame.sprite.collide_rect(self.megalovaniaBox, click):
            self.songPath = "Songs/MEGALOVANIA.ogg"
        elif pygame.sprite.collide_rect(self.rhinestoneBox, click):
            self.songPath = "Songs/Rhinestone Eyes.ogg"
        elif pygame.sprite.collide_rect(self.feelgoodBox, click):
            self.songPath = "Songs/Feel Good Inc.ogg"
        elif pygame.sprite.collide_rect(self.textInput, click):
            self.songPath = self.usrSong.value.replace('"', "")

    def checkScoreCollision(self, click):
        if pygame.sprite.collide_rect(self.backScore, click):
            self.soundMiss.play()
            self.scoreScreen = False
            self.songSelect = True
            self.reset()

    def initScoreScreen(self):
        self.scoreItems = pygame.sprite.Group()

        (x, y) = (50, 50)
        (width, height) = (1400, 650)
        path = "Pictures/Score.png"
        howToPlay = Button(path, x, y, width, height)

        (x, y) = (50, 720)
        (width, height) = (1400, 80)
        path = "Pictures/Buttons/BackScore.png"
        self.backScore = Button(path, x, y, width, height)

        howToPlay.add(self.scoreItems)
        self.backScore.add(self.scoreItems)

    def printScoreText(self):
        (width, height) = self.screen.get_size()

        textScore = str(self.score)
        (xScore, yScore) = (1390, 90)
        scoreSize = 70
        scoreText = StText(self.screen, textScore, scoreSize, xScore, yScore, "ne")
        
        textCombo = str(self.maxCombo) + "x"
        (xCombo, yCombo) = (110, 240)
        comboSize = 80
        comboText = StText(self.screen, textCombo, comboSize, xCombo, yCombo)

        self.printTimingText()

    def printTimingText(self):
        textScore = str(self.perfects)
        (xScore, yScore) = (620, 445)
        scoreSize = 50
        scoreText = StText(self.screen, textScore, scoreSize, xScore, yScore)

        textScore = str(self.goods)
        (xScore, yScore) = (1190, 445)
        scoreSize = 50
        scoreText = StText(self.screen, textScore, scoreSize, xScore, yScore)

        textScore = str(self.bads)
        (xScore, yScore) = (620, 540)
        scoreSize = 50
        scoreText = StText(self.screen, textScore, scoreSize, xScore, yScore)

        textScore = str(self.misses)
        (xScore, yScore) = (1190, 540)
        scoreSize = 50
        scoreText = StText(self.screen, textScore, scoreSize, xScore, yScore)

    def play(self):
        self.screen.blit(self.loadScreen, (0, 0))
        pygame.display.flip()

        #If custom path doesn't work (crashes), then we go back to song select.
        try:
            self.initSong(self.songPath)
        except:
            self.error = True
            return

        pygame.mixer.music.stop()
        self.songSelect = False
        self.playSong = True

    #Resets variables to prepare for next song.
    def reset(self):
        pygame.mixer.music.stop()

        self.error = False

        self.countdown = None
        self.playSong = False
        self.paused = False

        self.combo = 0
        self.maxCombo = 0
        self.score = 0
        self.prevAddition = 0
        self.lastBeatHit = (0, 0)
        self.hits = pygame.sprite.Group()
        self.timeElapsed = 0 + self.audioDelay
        self.beats = pygame.sprite.Group()
        self.beatQueue = deque()
        self.beatNum = 1
        self.initScoring()

        pygame.mixer.music.set_endevent()

###############################################################################
########################### Game code starts here #############################
###############################################################################
    def beatPressed(self):
        if (len(self.beatQueue) == 0):
            return
        (x, y) = pygame.mouse.get_pos()
        click = MousePointer(x, y)

        #Only the oldest beat placed can be clicked on.
        beat = self.beatQueue[0]
        if (pygame.sprite.collide_circle(beat, click)):
            mistake = self.addScore(beat.clock, beat)
            if (mistake == None):
                return
            elif mistake:
                self.mistake(beat)
            else:
                self.soundHit.play()
                self.combo += 1
            beat.dying()
            self.beatQueue.popleft()
            self.addHit(beat)

    #Returns True if a mistake is made, None if player clicks early, and 
    #increments score otherwise.
    def addScore(self, time, beat):
        if (time >= self.missLate):
            return True
        elif (time >= self.badLate):
            addition = self.scoreBad
        elif (time >= self.goodLate):
            addition = self.scoreGood
        elif (time >= self.perfectEarly):
            addition = self.scorePerfect
        elif (time >= self.goodEarly):
            addition = self.scoreGood
        elif (time >= self.badEarly):
            addition = self.scoreBad
        elif (time >= self.missEarly):
            return True
        else:
            return None

        self.scoreTrack(addition)

        return False

    #Increments counter for each hit type.
    def scoreTrack(self, addition):
        mult = self.getComboMult()
        self.score = int(self.score + (addition * mult))
        self.prevAddition = addition

        if (addition == self.scoreBad):
            self.bads += 1
        elif (addition == self.scoreGood):
            self.goods += 1
        elif (addition == self.scorePerfect):
            self.perfects += 1

    #Based off how osu! calculates this, from: https://osu.ppy.sh/wiki/Score
    def getComboMult(self):
        return (1 + self.combo/25)

    #Checks internal clocks of each beat.
    def gameTimerFired(self, time, tick):
        if (time + self.beatApproach) >= self.nextBeat:
            if len(self.times) > 0:
                self.addBeat()
                self.nextBeat = self.times.pop(0)

        for beat in self.beats:
            beat.update(tick)
            if ((beat.killClock == None) and (beat.clock >= self.beatKill)):
                beat.dying()
                self.beatQueue.remove(beat)
                self.mistake(beat)
        for hit in self.hits:
            hit.update(tick)
            if ((hit.killClock == None) and (hit.clock >= self.hitKill)):
                hit.dying()

    def addBeat(self):
        #Can't let beat go off-screen.
        (offsetW, offsetH) = (self.width-self.r, self.height-self.r)
        if (self.prevX == None) and (self.prevY == None):
            x = random.randint(0+self.r, offsetW)
            y = random.randint(0+self.r, offsetH)
        #Biasing in effect here. If beat position is in the edge 1/4 of the
        #screen, it will push the next beat to the center of the screen. If
        #it's in the center already, it's completely random.
        else:
            if (self.prevX < self.width // 4): xMult = 1
            elif (self.prevX > 3*(self.width // 4)): xMult = -1
            else: xMult = random.choice([-1, 1])

            if (self.prevY < self.height // 4): yMult = 1
            elif (self.prevY > 3*(self.height // 4)): yMult = -1
            else: yMult = random.choice([-1, 1])

            dx = random.randint(self.minDist, self.maxDist) * xMult
            dy = random.randint(self.minDist, self.maxDist) * yMult
            (x, y) = (self.prevX + dx, self.prevY + dy)

        (self.prevX, self.prevY) = (x, y)
        beat = Beat(x, y, self.beatColor, self.beatNum)
        beat.add(self.beats)
        self.beatQueue.append(beat)
        self.updateOrdinal()

    #Updates number drawn on the beat.
    def updateOrdinal(self):
        self.beatNum += 1
        if self.beatNum > self.beatNumMax:
            self.beatNum = 1
            self.shuffleColor()

    def mistake(self, beat):
        if (self.combo > self.maxCombo): self.maxCombo = self.combo
        #Only play noise when the player has a decent-sized combo.
        #Otherwise it's annoying as hell.
        if (self.combo >= 10):
            self.soundMiss.play()

        self.combo = 0

        xColor = (255, 0, 0)
        (x, y) = beat.getPos()
        text = "x"
        size = 100
        missText = Text(self.screen, text, size, x, y, "center", xColor)
        missText.add(self.hits)

        self.misses += 1

    #Change color of beats.
    def shuffleColor(self):
        newColor = random.choice(self.colorChoices)
        while (newColor == self.beatColor):
            newColor = random.choice(self.colorChoices)
        self.beatColor = newColor

    #Prints combo and score on screen.
    def printText(self):
        (width, height) = self.screen.get_size()
        textScore = str(self.score)
        (xScore, yScore) = (width-10, 0)
        scoreSize = 60
        scoreText = Text(self.screen, textScore, scoreSize, xScore, yScore,"ne")
        
        textCombo = str(self.combo) + "x"
        (xCombo, yCombo) = (10, height)
        comboSize = 75
        comboText = Text(self.screen, textCombo, comboSize, xCombo, yCombo,"sw")

    def addHit(self, beat):
        colorPerfect = (125, 200, 255)
        colorGood = (88, 255, 88)
        colorBad = (255, 226, 125)

        (x, y) = beat.getPos()
        text = str(self.prevAddition)
        if (self.prevAddition == self.scorePerfect):
            color = colorPerfect
        elif (self.prevAddition == self.scoreGood):
            color = colorGood
        elif (self.prevAddition == self.scoreBad):
            color = colorBad
        else: return
        size = 50
        hitText = Text(self.screen, text, size, x, y, "center", color)
        hitText.add(self.hits)