class levelLoader(object): """ This class actually handles a lot of things; while also handling the level loading, it also must be used to call from another class in the game class itself. For example, to use anything from the Player class, the user must have levelLoader.getPlayer().functionHere. In all honesty, this class handles pretty much everything that has anything to do with levels. """ def __init__(self): self.level = 0 self.platforms = [] self.doorsClosed = True self.entities = pygame.sprite.Group() self.coin = pygame.sprite.Group() self.spikes = pygame.sprite.Group() self.trophies = pygame.sprite.Group() self.x = 0 self.y = 0 self.levelCoins = 0 self.loadedCoins = False self.showDebug = False def buildLevel(self): """ KEY FOR LEVELS P = Platform C = player starting position A = Spike (Up) - 1 V = Spike (Down) - 2 > = Spike (Right) - 3 < = Spike (Left) - 4 K = Key X = Trophy T = Door Top B = Door Bottom O = Coin """ level = open(Directory.getDirectory() + '/levels/level' + str(self.level) + '.txt', 'r') for row in level: for col in row: if col.isdigit() and self.loadedCoins == False: if int(col) > 0: self.loadedCoins = True self.levelCoins = int(col) else: self.loadedCoins = True self.levelCoins = 1 if col == "P": p = Platform(self.x, self.y) # Place a platform at the given x,y self.platforms.insert(0, p) # Insert it into the platforms list self.entities.add(p) # Add to entities so it appears on screen if col == "C": self.charX = self.x # The character x found from file loading self.charY = self.y # The character y found from file loading self.player = Player(self.charX, self.charY) # Set the player along with the x,y of the starting position if col == "A": spike = Spike(self.x, self.y, 1) # Load a spike at the x,y found self.entities.add(spike) # Add the spike to the entities self.spikes.add(spike) # Add the spike to the spike sprite group for collison purposes if col == "V": spike = Spike(self.x, self.y, 2) # Load a spike at the x,y found self.entities.add(spike) # Add the spike to the entities self.spikes.add(spike) # Add the spike to the spike sprite group for collison purposes if col == ">": spike = Spike(self.x, self.y, 3) # Load a spike at the x,y found self.entities.add(spike) # Add the spike to the entities self.spikes.add(spike) # Add the spike to the spike sprite group for collison purposes if col == "<": spike = Spike(self.x, self.y, 4) # Load a spike at the x,y found self.entities.add(spike) # Add the spike to the entities self.spikes.add(spike) # Add the spike to the spike sprite group for collison purposes if col == "O": coin = Coins(self.x, self.y) # Load a coin image at the given x,y self.entities.add(coin) # Coin 1 to the entities self.coin.add(coin) # add coin 1 to the coinA sprite group if col == "X": try: win_object = Trophy(self.x, self.y, self.level) # Load the proper trophy by passing the level to the trophy class and load at the given x,y from file loading self.entities.add(win_object) # Add the trophy to the entities so it appears self.trophies.add(win_object) # Also make it a trophy sprite for collision detection purposes except: win_object = Trophy(self.x, self.y, 0) self.entities.add(win_object) # Add the trophy to the entities so it appears self.trophies.add(win_object) # Also make it a trophy sprite for collision detection purposes if col == "T": self.doorA = Door(self.x, self.y) self.platforms.append(self.doorA) # Make the door top a platform so the player cannot walk through it self.entities.add(self.doorA) # Add the door bottom to the entities if col == "B": self.doorB = Door(self.x, self.y) self.platforms.append(self.doorB) # Make the door bottom a platform so the player cannot walk through it self.entities.add(self.doorB) # Add the door bottom to entities self.x += 32 self.y += 32 self.x = 0 # Try loading in the level image and theme; if it fails, use level 0 theme and background try: self.background = pygame.image.load(Directory.getDirectory() + '/images/backgrounds/background' + str(self.level) + '.png').convert_alpha() self.background_rect = self.background.get_rect() except: self.background = pygame.image.load(Directory.getDirectory() + '/images/backgrounds/background0.png').convert_alpha() self.background_rect = self.background.get_rect() def getPlayer(self): return self.player def getPlatforms(self): return self.platforms def getEntities(self): return self.entities def getCoins(self): return self.coin def getTrophy(self): return self.trophies def getSpikes(self): return self.spikes def getBGWidth(self): return self.background_rect.w def getBGHeight(self): return self.background_rect.h def getBackground(self): return self.background def delPlatforms(self): del self.platforms[-1] def delDoors(self): self.doorsClosed = False self.doorA.kill() self.doorB.kill() def rebuildDoors(self): self.doorsClosed = True def doorStatus(self): return self.doorsClosed def clearScreen(self): self.player.onGround = True self.x = 0 self.y = 0 self.loadedCoins = False level = self.level self.platforms = None self.doorA.kill() self.doorB.kill() self.entities.empty() self.trophies.empty() self.spikes.empty() self.coin.empty() def rebuildObjects(self): self.level = self.level self.platforms = [] self.doorsClosed = True self.player = Player(self.charX, self.charY) self.entities = pygame.sprite.Group() self.coin = pygame.sprite.Group() self.spikes = pygame.sprite.Group() self.trophies = pygame.sprite.Group() self.x = 0 self.y = 0 self.player.dead = False self.player.up = False self.player.right = False self.player.left = False self.player.running = False def addLevel(self): self.level += 1 def resetLevel(self): self.level = 0 def getLevel(self): return self.level def loadingBar(self): return self.loadingBar def getLevelCoins(self): return self.levelCoins def infoScreen(self): self.debug = Display.font.render("Information Window", True, (255,255,255)) self.death_status = Display.font.render("player.canDie: " + str(self.getPlayer().canDie), True, (255,255,255)) self.door_status = Display.font.render("door_closed: " + str(self.doorsClosed), True, (255,255,255)) self.coin_debug = Display.font.render("coin_count: " + str(self.getPlayer().getCoins()), True, (255,255,255)) Display.screen.blit(self.debug, (0,0)) Display.screen.blit(self.death_status, (0,25)) Display.screen.blit(self.door_status, (0,50)) Display.screen.blit(self.coin_debug, (0,75))
def main(): """The main loop of the game. It handles loading the levels, key strokes, playing music and sounds; relies heavily on multiple other classes to function correctly. These include the camera, coins, door, entities, platform, player, sounds, spike, themes, and trophies classes.""" gc.enable() # Garbage collector global cameraX, cameraY, key_count, delete_door, current_level, deaths, deaths_total, volume # Load in the global variables pygame.mixer.pre_init(44100, -16, 2, 2048) # Initilize the music screen = pygame.display.set_mode(DISPLAY, FLAGS, DEPTH) # Set the screen information screen_rect = screen.get_rect() timer = pygame.time.Clock() # We don't want to see the normal mouse cursor while playing. pygame.mouse.set_visible(False) sounds = Sounds() # Allows us to call sounds by doing sounds.name font = pygame.font.SysFont("arial", 25) # Font for the game loading_bar = pygame.transform.scale(pygame.image.load("images/button.png"), (WIN_WIDTH, 35)) # Loading bar image (so that the "Loading Level (level)..." text is visible) up = down = left = right = running = False # Set all key strokes (directions) to False # Load in the first level by assigning sprites into groups and into the platforms and coin_list lists # Read about what each thing does in the respective class # !!! WARNING !!! The game will break if the level does not contain the player ("C") within; the game may break if the door Top and Bottom is not found as well. """KEY FOR LEVELS P = Platform C = player starting position A = Spike (Up) V = Spike (Down) > = Spike (Right) < = Spike (Left) K = Key X = Trophy T = Door Top B = Door Bottom""" platforms = [] coin_list = [] entities = pygame.sprite.Group() coinA = pygame.sprite.Group() spikes = pygame.sprite.Group() trophies = pygame.sprite.Group() monsters = pygame.sprite.Group() x = 0 y = 0 level = open('levels/level' + str(current_level) + '.txt', 'r') for row in level: for col in row: if col == "P": p = Platform(x, y) # Place a platform at the given x,y platforms.insert(0, p) # Insert it into the platforms list entities.add(p) # Add to entities so it appears on screen if col == "C": charX = x # The character x found from file loading charY = y # The character y found from file loading player = Player(charX, charY) # Set the player along with the x,y of the starting position if col == "A": spike = Spike(x, y, 1) # Load a spike at the x,y found entities.add(spike) # Add the spike to the entities spikes.add(spike) # Add the spike to the spike sprite group for collison purposes if col == "V": spike = Spike(x, y, 2) # Load a spike at the x,y found entities.add(spike) # Add the spike to the entities spikes.add(spike) # Add the spike to the spike sprite group for collison purposes if col == ">": spike = Spike(x, y, 3) # Load a spike at the x,y found entities.add(spike) # Add the spike to the entities spikes.add(spike) # Add the spike to the spike sprite group for collison purposes if col == "<": spike = Spike(x, y, 4) # Load a spike at the x,y found entities.add(spike) # Add the spike to the entities spikes.add(spike) # Add the spike to the spike sprite group for collison purposes if col == "M": monster = Monster(x, y) # Load a spike at the x,y found entities.add(monster) # Add the spike to the entities monsters.add(monster) # Add the spike to the spike sprite group for collison purposes if col == "K": c1 = Coins(x, y) # Load a coin image at the given x,y entities.add(c1) # Coin 1 to the entities coinA.add(c1) # add coin 1 to the coinA sprite group if col == "X": win_object = Trophy(x, y) # Load the proper trophy by passing the current_level to the trophy class and load at the given x,y from file loading entities.add(win_object) # Add the trophy to the entities so it appears trophies.add(win_object) # Also make it a trophy sprite for collision detection purposes if col == "T": doorA = Door(x, y, pygame.transform.scale(pygame.image.load("images/door_locked1.png"), (60,100))) platforms.append(doorA) # Make the door top a platform so the player cannot walk through it entities.add(doorA) # Add the door bottom to the entities if col == "B": doorB = Door(x, y, pygame.transform.scale(pygame.image.load("images/door_locked2.png"), (60,32))) platforms.append(doorB) # Make the door bottom a platform so the player cannot walk through it entities.add(doorB) # Add the door bottom to entities x += 32 y += 32 x = 0 # Try loading in the level image and theme; if it fails, use level 0 theme and background background = pygame.image.load('images/backgrounds/background.png').convert_alpha() background_rect = background.get_rect() total_level_width = len('level'[0])*32 total_level_height = len('level')*32 camera = Camera(complex_camera, total_level_width, total_level_height) entities.add(player) # Finally, add player to entities so it appears missiles = pygame.sprite.RenderUpdates() # The main loop of the game which runs it until we're done. while 1: pygame.display.set_caption("Asylum | Deaths (level): " + str(deaths) + " | Deaths (Total): " + str(deaths_total) + " | FPS: " + str(int(timer.get_fps()))) asize = ((screen_rect.w // background_rect.w + 1) * background_rect.w, (screen_rect.h // background_rect.h + 1) * background_rect.h) bg = pygame.Surface(asize) # Create the background for x in range(0, asize[0], background_rect.w): for y in range(0, asize[1], background_rect.h): screen.blit(background, (x, y)) timer.tick(38) # The maximum framerate; the game is designed to run at an FPS of 30-40 (38 being best) # All the keystroke events; the game can run using the UP-RIGHT-LEFT arrow keys, Space Bar, and the AWD keys (down is never needed) # ENTER will kill the player (used if the player glitch spawns outside the level or glitch out (reloads the level as if they died)) for e in pygame.event.get(): if e.type == QUIT: exit() if e.type == KEYDOWN and e.key == K_ESCAPE: exit() if e.type == KEYDOWN and e.key == K_UP: player.direction = 'up' up = True down = left = right = False if e.type == KEYDOWN and e.key == K_DOWN: player.direction = 'down' down = True up = left = right = False if e.type == KEYDOWN and e.key == K_LEFT: player.direction = 'left' left = True right = up = down = False if e.type == KEYDOWN and e.key == K_RIGHT: player.direction = 'right' right = True left = up = down = False if e.type == KEYDOWN and e.key == K_w: player.direction = 'up' up = True down = left = right = False if e.type == KEYDOWN and e.key == K_s: player.direction = 'down' down = True up = left = right = False if e.type == KEYDOWN and e.key == K_a: player.direction = 'left' left = True right = up = down = False if e.type == KEYDOWN and e.key == K_d: player.direction = 'right' right = True left = up = down = False """ if e.type == KEYDOWN and e.key == K_RSHIFT and player.attacking == False and pygame.sprite.spritecollide(player, monster, True): print "Space bar clicked, attacking!" player.attacking = True sounds.shot.play() sounds.shot.set_volume(volume) if player.direction == 'down': player.image = pygame.transform.scale(player.attackList[0], (50, 50)) if player.direction == 'left': player.image = pygame.transform.scale(player.attackList[1], (50, 50)) if player.direction == 'up': player.image = pygame.transform.scale(player.attackList[2], (50, 50)) if player.direction == 'right': player.image = pygame.transform.scale(player.attackList[3], (50, 50)) """ if e.type == KEYUP and e.key == K_UP: player.direction = 'up' up = False if e.type == KEYUP and e.key == K_DOWN: player.direction = 'down' down = False if e.type == KEYUP and e.key == K_RIGHT: player.direction = 'right' right = False if e.type == KEYUP and e.key == K_LEFT: player.direction = 'left' left = False if e.type == KEYUP and e.key == K_w: player.direction = 'up' up = False if e.type == KEYUP and e.key == K_s: player.direction = 'down' down = False if e.type == KEYUP and e.key == K_d: player.direction = 'right' right = False if e.type == KEYUP and e.key == K_a: player.direction = 'left' left = False """ if e.type == KEYUP and e.key == K_RSHIFT: player.attacking = False print "reset attack" """ # All of the coin collision detection; when it occurs, the coin is removed and a sound plays while adding one to the coin_count (4 opens the door) # the True in each IF statement means that when the collision occurs the coin is removed from it's group, thus removing it from appearing on screen if pygame.sprite.spritecollide(player, coinA, True, pygame.sprite.collide_mask): sounds.coin_sound.play() sounds.coin_sound.set_volume(volume) key_count += 1 # If the player manages to reach the trophy, reset the level deaths, add one to the current_level, kill the theme (music), add the loading bar, print out loading level # kill all key-presses (directions) empty all sprites and lists and load in the next level if pygame.sprite.spritecollide(player, trophies, True, pygame.sprite.collide_mask): sounds.footsteps.play() deaths = 0 current_level += 1 platforms = None level = None up = False right = False left = False key_count = 0 doorA.kill() doorB.kill() entities.empty() trophies.empty() spikes.empty() coinA.empty() monsters.empty() screen.blit(loading_bar, (0,0)) # Blit the loading bar image to the screen (so text shows up on all background colors) load_text = font.render("Loading Level " + str(current_level) + "...", True, (255, 255, 255)) # Blit loading text to the loading_bar screen.blit(load_text, (1,0)) pygame.display.update() gc.collect() x = 0 y = 0 platforms = [] pause.sleep(3) # Sleep for 5 seconds ('loading'...might have an effect on lag by allowing it to pause for a few seconds) try: level = open('levels/level' + str(current_level) + '.txt', 'r') # Try loading the next level; if it fails, we assume they finished the game and reload the title screen except: screen.blit(loading_bar, (0,0)) congrats = font.render("Congratulations! You've conquered your fears and escaped Asylum!", True, (255, 255, 255)) screen.blit(congrats, (0,0)) print "blitted congrats" pygame.display.update() pause.sleep(5) False current_level = 0 # Reset the level counter so clicking play again doesn't crash the game coin_count = 0 # Reset coin count delete_door = True # Reset the door deletion status (True means the door can be removed) # Since we're heading back to the title menu, let's bring back the title screen music. pygame.mixer.pre_init(44100, -16, 2, 2048) sounds = Sounds() titleScreen() for row in level: for col in row: if col == "P": p = Platform(x, y) platforms.insert(0, p) entities.add(p) if col == "C": charX = x charY = y player = Player(charX, charY) if col == "A": spike = Spike(x, y, 1) entities.add(spike) spikes.add(spike) if col == "V": spike = Spike(x, y, 2) # Load a spike at the x,y found entities.add(spike) # Add the spike to the entities spikes.add(spike) # Add the spike to the spike sprite group for collison purposes if col == ">": spike = Spike(x, y, 3) # Load a spike at the x,y found entities.add(spike) # Add the spike to the entities spikes.add(spike) # Add the spike to the spike sprite group for collison purposes if col == "<": spike = Spike(x, y, 4) # Load a spike at the x,y found entities.add(spike) # Add the spike to the entities spikes.add(spike) # Add the spike to the spike sprite group for collison purposes if col == "M": monster = Monster(x, y) # Load a spike at the x,y found entities.add(monster) # Add the spike to the entities monsters.add(monster) # Add the spike to the spike sprite group for collison purposes if col == "K": c1 = Coins(x, y) entities.add(c1) coin_list.append(c1) coinA.add(c1) if col == "X": win_object = Trophy(x, y) entities.add(win_object) trophies.add(win_object) if col == "T": doorA = Door(x, y, pygame.transform.scale(pygame.image.load("images/door_locked1.png"), (60,100))) platforms.append(doorA) # Make the door top a platform so the player cannot walk through it entities.add(doorA) # Add the door bottom to the entities if col == "B": doorB = Door(x, y, pygame.transform.scale(pygame.image.load("images/door_locked2.png"), (60,32))) platforms.append(doorB) # Make the door bottom a platform so the player cannot walk through it entities.add(doorB) # Add the door bottom to entities x += 32 y += 32 x = 0 """ player.update(up, down, left, right, running, platforms) for e in entities: screen.blit(e.image, camera.apply(e)) """ pygame.display.update() delete_door = True # reset door status player.dead = False # ensure the player isn't dead entities.add(player) # Player collision with spike; if true, kill the player if pygame.sprite.spritecollide(player, spikes, False, pygame.sprite.collide_mask): player.dead = True if pygame.sprite.spritecollide(player, monsters, False, pygame.sprite.collide_mask): player.dead = True for m in monsters: m.sensePlayers(player, platforms) # If the player is dead, reset all key strokes to False, play the death sound, empty all groups and lists and reload the level, add one to both total and level deaths if player.dead == True: up = False right = False left = False sounds.death_sound.play() sounds.death_sound.set_volume(volume) player = Player(charX, charY) platforms = None level = None x = 0 y = 0 doorA.kill() doorB.kill() entities.empty() trophies.empty() spikes.empty() coinA.empty() monsters.empty() gc.collect() pause.sleep(1) key_count = 0 platforms = [] level = open('levels/level' + str(current_level) + '.txt', 'r') deaths += 1 deaths_total += 1 for row in level: for col in row: if col == "P": p = Platform(x, y) platforms.insert(0, p) entities.add(p) if col == "C": charX = x charY = y player = Player(charX, charY) if col == "A": spike = Spike(x, y, 1) entities.add(spike) spikes.add(spike) if col == "V": spike = Spike(x, y, 2) # Load a spike at the x,y found entities.add(spike) # Add the spike to the entities spikes.add(spike) # Add the spike to the spike sprite group for collison purposes if col == ">": spike = Spike(x, y, 3) # Load a spike at the x,y found entities.add(spike) # Add the spike to the entities spikes.add(spike) # Add the spike to the spike sprite group for collison purposes if col == "<": spike = Spike(x, y, 4) # Load a spike at the x,y found entities.add(spike) # Add the spike to the entities spikes.add(spike) # Add the spike to the spike sprite group for collison purposes if col == "M": monster = Monster(x, y) # Load a spike at the x,y found entities.add(monster) # Add the spike to the entities monsters.add(monster) # Add the spike to the spike sprite group for collison purposes if col == "K": c1 = Coins(x, y) entities.add(c1) coin_list.append(c1) coinA.add(c1) if col == "X": win_object = Trophy(x, y) entities.add(win_object) trophies.add(win_object) if col == "T": doorA = Door(x, y, pygame.transform.scale(pygame.image.load("images/door_locked1.png"), (60,100))) platforms.append(doorA) # Make the door top a platform so the player cannot walk through it entities.add(doorA) # Add the door bottom to the entities if col == "B": doorB = Door(x, y, pygame.transform.scale(pygame.image.load("images/door_locked2.png"), (60,32))) platforms.append(doorB) # Make the door bottom a platform so the player cannot walk through it entities.add(doorB) # Add the door bottom to entities x += 32 y += 32 x = 0 delete_door = True player.dead = False entities.add(player) # Readd the player to the entities # If the coin count is four, then set the door status to False, kill the door sprites and remove from the platforms list # When delete_door is True it means the door can be removed when the coins are all collected; False means it's been opened. This check was added to prevent it from continually playing the sounds. if key_count >= 1 and delete_door == True: sounds.door.play() sounds.door.set_volume(volume) for x in xrange(2): # Since we ensure doors are added to the end of the list, we can just remove the last two items in the platforms list safely del platforms[-1] delete_door = False # now the door status is False doorA.kill() # Kill doorA and doorB (makes it disappear (the door has "opened")) doorB.kill() camera.update(player) # Update the player and everything else missiles.update() pygame.sprite.groupcollide(missiles, platforms, True, False) missiles.draw(screen) player.update(up, down, left, right, running, platforms) for e in entities: screen.blit(e.image, camera.apply(e)) pygame.display.update() # Update the display