def __init__(self, game, map, dimensions): self.game = game self.map = TiledMap(path.join(game.maps_folder, map)) self.map_img = self.map.make_map() self.map_rect = self.map_img.get_rect() self.dimensions = dimensions self.screen = pg.display.set_mode(self.dimensions) self.all_sprites = game.all_sprites self.walls = game.walls self.items = game.items self.entities = game.entities self.mobs = game.mobs self.triggers = game.triggers self.passages = game.passages
def create_map(self, filename): # Basic map background image with data. self.map = TiledMap(os.path.join(self.map_folder, filename)) self.map.make_map() # Create the camera with the map dimensions. self.camera = Camera(SCREEN_WIDTH, SCREEN_HEIGHT, self.map.width, self.map.height) movement = { "back": True, "parts": { 1: { "vel": 150, "rot": 90, "distance": 400 }, 2: { "vel": 50, "rot": 45, "distance": 100 }, 3: { "vel": 200, "rot": 0, "distance": 600, } } } # Map objects. for tile_object in self.map.tilemap_data.objects: # The center of the tile. object_center = Vec(tile_object.x + tile_object.width / 2, tile_object.y + tile_object.height / 2) # Obstacles. if tile_object.object == "obstacle": Obstacle(self, tile_object.x, tile_object.y, tile_object.width, tile_object.height, tile_object.type) elif tile_object.object == "moving_obstacle": MovingObstacle(self, tile_object.x, tile_object.y, tile_object.width, tile_object.height, tile_object.type, movement) elif tile_object.object == "item": Item(self, object_center, tile_object.type, RANDOM_START_STEP)
def new(self): """For things that should happen once, at the start of a new game""" # Load map from file self.map_folder = path.join(self.game_folder, 'data/maps') # self.map = Map(path.join(game_folder, 'map.txt')) self.map = TiledMap(self, path.join(self.map_folder, MAP_NAME)) self.map_img = self.map.make_map() self.map_rect = self.map_img.get_rect() # self.paths = breadth_first_search(self.map, self # initialize all variables and do all the setup for a new game self.all_sprites = pg.sprite.LayeredUpdates() self.walls = pg.sprite.Group() self.mobs = pg.sprite.Group() self.bullets = pg.sprite.Group() self.items = pg.sprite.Group() # For Loading map from tmx data for tile_object in self.map.tmxdata.objects: obj_center = vec(tile_object.x + tile_object.width / 2, tile_object.y + tile_object.height / 2) if tile_object.name == 'player': self.player = Player(self, obj_center.x, obj_center.y) if tile_object.name == 'zombie': Mob(self, obj_center.x, obj_center.y) # For EM all entities must have unique id if tile_object.name == 'wall': Obstacle(self, tile_object.x, tile_object.y, tile_object.width, tile_object.height) if tile_object.name in ['health', 'shotgun', 'pistol']: Item(self, obj_center, tile_object.name) # self.EM = AI.EntityManager() for mob in self.mobs: # self.EM.add_entity(mob.id) #All entities must have a unique id mob.SM.current_state = zombie_states.Idle(self, mob) mob.SM.global_state = zombie_states.ZombieGlobalState(self, mob) assert self.player is not None self.camera = Camera(self.map.width, self.map.height) # Give camera total size of map # Flags self.draw_debug = False self.paused = False self.night = False self.effects_sounds['level_start'].play()
def new(self): # initialize all variables and do all the setup for a new game self.draw_debug = False self.paused = False self.night = True # Sprite groups self.all_sprites = pg.sprite.LayeredUpdates() self.obstacles = pg.sprite.Group() self.mobs = pg.sprite.Group() self.bullets = pg.sprite.Group() self.items = pg.sprite.Group() # Map self.map = TiledMap(path.join(self.map_folder, '01.tmx')) self.map_img = self.map.make_map() self.map_rect = self.map_img.get_rect() # Map Objects for tile_object in self.map.tmxdata.objects: # For spawning in center of tiled object obj_center = vec(tile_object.x + tile_object.width / 2, tile_object.y + tile_object.height / 2) if tile_object.name == 'player': self.player = Player(self, obj_center.x, obj_center.y) if tile_object.name == 'zombie': Mob(self, obj_center.x, obj_center.y) if tile_object.name == 'wall': Obstacle(self, tile_object.x, tile_object.y, tile_object.width, tile_object.height) if tile_object.name in ['health', 'shotgun']: Item(self, obj_center, tile_object.name) # Camera object self.camera = Camera(self.map.width, self.map.height) # Start a new level sound self.effects_sounds['level_start'].play()
class Level: def __init__(self, game): self.game = game self.map_folder = game.map_folder def new(self): pass def make_map_from_file(self, file): self.map = TiledMap(os.path.join(self.map_folder, file)) self.game.map = self.map self.game.map_img = self.map.make_map() self.game.map_rect = self.game.map_img.get_rect() def clear_sprites(self): game = self.game game.camera = Camera(self.map.width, self.map.height) game.all_sprites = pg.sprite.LayeredUpdates() game.walls = pg.sprite.Group() game.mobs = pg.sprite.Group() game.items = pg.sprite.Group() def spawn_tmx_objects(self): game = self.game for tile_object in self.map.tmxdata.objects: object_center = vec(tile_object.x + tile_object.width / 2, tile_object.y + tile_object.height / 2) if tile_object.name == 'player': game.player = Player(game, object_center.x, object_center.y) if tile_object.name == 'wall': Obstacle(game, tile_object.x, tile_object.y, tile_object.width, tile_object.height) if tile_object.name == 'mob': Mob(game, object_center.x, object_center.y) if tile_object.name in ['apple']: Item(game, object_center, tile_object.name)
def load_data(self): self.game_folder = path.dirname(__file__) self.maps_folder = path.join(self.game_folder, 'maps') self.assets_folder = path.join(self.game_folder, 'assets') self.texts_folder = path.join(self.game_folder, 'txt') self.fonts_folder = path.join(self.assets_folder, 'fonts') self.spritesheet = Spritesheet( path.join(self.assets_folder, SPRITESHEET)) self.player_img = self.spritesheet.get_sprite(PLAYER_SPRITE) self.lifebar_img = self.spritesheet.get_sprite(HEART_SPRITE) self.main_font = path.join(self.fonts_folder, MAIN_FONT) self.dim_screen = pg.Surface(self.screen.get_size()).convert_alpha() self.dim_screen.fill((0, 0, 0, 188)) maps = [ f for f in listdir(path.join(self.maps_folder)) if path.isfile(path.join(path.join(self.maps_folder), f)) ] for map_name in maps: if '.tmx' in map_name: map = TiledMap(path.join(self.maps_folder, map_name)) map_img = map.make_map() map_rect = map_img.get_rect() self.maps[map_name] = (map, map_img, map_rect) self.item_images = {} for item in ITEM_SPRITES: temp_image = self.spritesheet.get_sprite(ITEM_SPRITES[item]) self.item_images[item] = pg.transform.scale( temp_image, (TILE_SIZE - int(TILE_SIZE / 8), TILE_SIZE - int(TILE_SIZE / 8))) self.mobs_images = {} for mob in MOBS: self.mobs_images[mob] = self.spritesheet.get_sprite( MOBS[mob]['sprite']) self.entities_images = {} for entity in ENTITIES: sprite1 = self.spritesheet.get_sprite(ENTITIES[entity]['sprite1']) sprite2 = self.spritesheet.get_sprite(ENTITIES[entity]['sprite2']) self.entities_images[entity] = (sprite1, sprite2) self.all_texts = [] texts = [ f for f in listdir(path.join(self.texts_folder)) if path.isfile(path.join(path.join(self.texts_folder), f)) ] for file in texts: text = "" if '.txt' in file: file_text = open(path.join(self.texts_folder, file), 'r') for line in file_text.readlines(): text += line.strip() self.all_texts.append(text)
def load_data(self): game_folder = path.dirname(__file__) map_folder = path.join(game_folder, "maps") self.map = TiledMap(path.join(map_folder, "AI-map.tmx")) self.map_img = self.map.make_map() self.map_rect = self.map_img.get_rect()
class Game: def __init__(self): # pg.init() pg.display.init() pg.font.init() self.screen = pg.display.set_mode((WIDTH, HEIGHT)) pg.display.set_caption(TITLE) self.clock = pg.time.Clock() pg.key.set_repeat(250, 50) # Allows us to hold dowW keys to move, etc. self.load_data() self.total_carrots = 0 self.go_screen = False def load_data(self): game_folder = path.dirname(__file__) map_folder = path.join(game_folder, "maps") self.map = TiledMap(path.join(map_folder, "AI-map.tmx")) self.map_img = self.map.make_map() self.map_rect = self.map_img.get_rect() #self.map = Map(path.join(game_folder, "map.txt")) def new(self): # initialize all variables and do all the setup for a new game self.all_sprites = pg.sprite.Group() self.walls = pg.sprite.Group() self.chest = pg.sprite.Group() self.items = pg.sprite.Group() self.carrots = pg.sprite.Group() for tile_object in self.map.tmxdata.objects: if tile_object.name == "player": print("player location: ", tile_object.x, tile_object.y) self.player = AIPlayer(self, tile_object.x, tile_object.y) # self.player = Player(self, tile_object.x, tile_object.y) if tile_object.name == "wall": Obstacle(self, tile_object.x, tile_object.y, tile_object.width, tile_object.height) if tile_object.name == "carrot": Carrot(self, tile_object.x, tile_object.y, groups=[self.all_sprites, self.carrots, self.items]) self.total_carrots += 1 if tile_object.name == "chest": Chest(self, tile_object.x, tile_object.y, groups=[self.all_sprites, self.chest, self.items]) self.camera = Camera(self.map.width, self.map.height) def reset(self): # initialize all variables anddo all the setup for a new game self.chest = pg.sprite.Group() for chest in self.chest: self.all_sprites.remove(chest) chest.kill() for carrot in self.carrots: self.all_sprites.remove(carrot) carrot.kill() self.carrots.empty() self.carrots = pg.sprite.Group() for item in self.items: self.all_sprites.remove(item) item.kill() self.items = pg.sprite.Group() self.total_carrots = 0 for tile_object in self.map.tmxdata.objects: if tile_object.name == "player": print("player location: ", tile_object.x, tile_object.y) #self.player = AIPlayer(self, tile_object.x, tile_object.y) self.player.reset(tile_object.x, tile_object.y) if tile_object.name == "carrot": Carrot(self, tile_object.x, tile_object.y, groups=[self.all_sprites, self.carrots, self.items]) self.total_carrots += 1 if tile_object.name == "chest": Chest(self, tile_object.x, tile_object.y, groups=[self.all_sprites, self.chest, self.items]) def run(self): # game loop - set self.playing = False to end the game # useful for ending a training session self.playing = True while self.playing: self.dt = self.clock.tick(FPS) / 1000 self.events() self.update() self.draw() def quit(self): self.playing = False pg.quit() pg.display.quit() sys.exit() def update(self): # update portion of the game loop self.all_sprites.update() self.camera.update(self.player) def draw_grid(self): for x in range(0, WIDTH, TILESIZE): pg.draw.line(self.screen, LIGHTGREY, (x, 0), (x, HEIGHT)) for y in range(0, HEIGHT, TILESIZE): pg.draw.line(self.screen, LIGHTGREY, (0, y), (WIDTH, y)) def draw(self): self.screen.fill(BGCOLOR) self.draw_grid() self.screen.blit(self.map_img, self.camera.apply_rect(self.map_rect)) for sprite in self.all_sprites: self.screen.blit(sprite.image, self.camera.apply(sprite)) self.screen.blit(self.score_surface(self.player), (0, 0)) # Yuck try: if isinstance(self.player, AIPlayer) and DEBUG == True: if not self.player.controller.debug_queue.empty(): (self.episode, self.state_values ) = self.player.controller.debug_queue.get() if self.episode % DEBUG_BLIT_RATE == 0: for state in self.state_values: val = self.state_values.get(state, 0) val = round(val, 2) x, y = (state[0][0] + TILESIZE / 2, state[0][1] + TILESIZE / 2) if len(state) == 3 and state[2] == True: y = state[0][1] + TILESIZE / 4 self.screen.blit(self.state_value_surface(str(val)), (x, y)) except (NameError, AttributeError) as e: pass pg.display.flip() def events(self): # catch all events here for event in pg.event.get(): if event.type == pg.QUIT: if isinstance(self.player, AIPlayer): self.player.controller.quit() self.quit() self.player.events(event) if self.go_screen == True and event.type == pg.KEYDOWN and event.key == pg.K_SPACE: self.go_screen = False def score_surface(self, player): template = "Score: {}, Remaining Moves: {}, Pos: ({}, {})" template = template.format(player.score, MAX_ACTIONS - player.total_actions, player.rect.x, player.rect.y) default_font = pg.font.get_default_font() return pg.font.Font(default_font, 18).render(template, True, (0, 0, 255)) def show_start_screen(self): pass def game_over_surface(self): text = "Game Over! Press Space To Play Again" default_font = pg.font.get_default_font() return pg.font.Font(default_font, 24).render(text, True, (0, 0, 255)) def state_value_surface(self, V): default_font = pg.font.get_default_font() return pg.font.Font(default_font, 8).render(V, True, (0, 0, 240)) def show_go_screen(self): self.go_screen = True while self.go_screen: go_surf = self.game_over_surface() self.screen.blit(go_surf, (WIDTH / 2 - (go_surf.get_width() / 2), HEIGHT / 2)) pg.display.flip() self.events() self.update()
class Game: def __init__(self): self.logger = logging.getLogger(f"{__name__}.Game") self.logger.debug("Initializing game object") pg.mixer.pre_init( 44100, -16, 1, 1024) # increase sound buffer to minise lag when playing sounds pg.init() self.screen = pg.display.set_mode((WIDTH, HEIGHT)) pg.display.set_caption(TITLE) self.clock = pg.time.Clock() # pg.key.set_repeat(10, 100) # Lets you hold down a key to keep the move going self.game_folder = path.dirname(__file__) self.load_images() self.load_sounds() self.player = None def draw_text(self, text, font_name, size, color, x, y, align="nw"): font = pg.font.Font(font_name, size) text_surface = font.render(text, True, color) text_rect = text_surface.get_rect() if align == "nw": text_rect.topleft = (x, y) if align == "ne": text_rect.topright = (x, y) if align == "sw": text_rect.bottomleft = (x, y) if align == "se": text_rect.bottomright = (x, y) if align == "n": text_rect.midtop = (x, y) if align == "s": text_rect.midbottom = (x, y) if align == "e": text_rect.midright = (x, y) if align == "w": text_rect.midleft = (x, y) if align == "center": text_rect.center = (x, y) self.screen.blit(text_surface, text_rect) def load_images(self): self.logger.debug("loading images...") # Define game folders image_folder = path.join(self.game_folder, 'data/images') # Load images from files self.title_font = path.join(image_folder, 'ZOMBIE.TTF') self.hud_font = path.join(image_folder, 'Impacted2.0.TTF') self.dim_screen = pg.Surface(self.screen.get_size()).convert_alpha() self.dim_screen.fill((0, 0, 0, 180)) self.player_imgs = {} for img in PLAYER_IMGS: self.player_imgs[img] = pg.image.load( path.join(image_folder, PLAYER_IMGS[img])).convert_alpha() self.wall_img = pg.image.load(path.join(image_folder, WALL_IMG)).convert_alpha() self.wall_img = pg.transform.scale(self.wall_img, (TILESIZE, TILESIZE)) self.mob_img = pg.image.load(path.join(image_folder, MOB_IMG)).convert_alpha() self.bullet_images = {} self.bullet_images['lg'] = pg.image.load( path.join(image_folder, BULLET_IMG)).convert_alpha() self.bullet_images['lg'] = pg.transform.scale(self.bullet_images['lg'], (5, 5)) self.splat = pg.image.load(path.join(image_folder, SPLAT)).convert_alpha() self.splat = pg.transform.scale(self.splat, (64, 64)) self.gun_smoke = [] for img in MUZZLE_SMOKE: self.gun_smoke.append( pg.image.load(path.join(image_folder, img)).convert_alpha()) self.item_images = {} for item in ITEM_IMAGES: self.item_images[item] = pg.image.load( path.join(image_folder, ITEM_IMAGES[item])).convert_alpha() # Lighting self.fog = pg.Surface((WIDTH, HEIGHT)) self.fog.fill(NIGHT_COLOUR) self.light_mask = pg.image.load(path.join(image_folder, LIGHT_MASK)).convert_alpha() self.light_mask = pg.transform.scale(self.light_mask, LIGHT_RADIUS) self.light_rect = self.light_mask.get_rect() def load_sounds(self): self.logger.debug("loading sounds...") sound_folder = path.join(self.game_folder, 'data/sounds') self.music_folder = path.join(self.game_folder, 'data/music') # Load initial music - define user event to trigger when it ends, picked up in events() self.SONG_END = pg.USEREVENT + 1 self.current_song = random.choice(BG_MUSIC) pg.mixer.music.set_endevent(self.SONG_END) pg.mixer.music.load(path.join(self.music_folder, self.current_song)) pg.mixer.music.set_volume(BG_MUSIC_LEVEL) # Effects self.effects_sounds = {} for eff in EFFECTS_SOUNDS: self.effects_sounds[eff] = pg.mixer.Sound( path.join(sound_folder, EFFECTS_SOUNDS[eff]['file'])) self.effects_sounds[eff].set_volume(EFFECTS_SOUNDS[eff]['volume']) # Weapons self.weapon_sounds = {} for weapon in WEAPON_SOUNDS: self.weapon_sounds[weapon] = [] for sound in WEAPON_SOUNDS[weapon]: s = pg.mixer.Sound(path.join(sound_folder, sound)) s.set_volume(GUN_SOUND_LEVEL) self.weapon_sounds[weapon].append(s) # Zombies self.zombie_moan_sounds = [] for sound in ZOMBIE_MOAN_SOUNDS: s = pg.mixer.Sound(path.join(sound_folder, sound)) s.set_volume(ZOMBIE_MOAN_LEVEL) self.zombie_moan_sounds.append(s) self.zombie_hit_sounds = [] for sound in ZOMBIE_HIT_SOUNDS: s = pg.mixer.Sound(path.join(sound_folder, sound)) s.set_volume(ZOMBIE_HIT_LEVEL) self.zombie_hit_sounds.append(s) # Player self.player_hit_sounds = [] for sound in PLAYER_HIT_SOUNDS: s = pg.mixer.Sound(path.join(sound_folder, sound)) s.set_volume(PLAYER_HIT_LEVEL) self.player_hit_sounds.append(s) self.player_pain_sounds = [] for sound in PLAYER_PAIN_SOUNDS: s = pg.mixer.Sound(path.join(sound_folder, sound)) s.set_volume(PLAYER_PAIN_LEVEL) self.player_pain_sounds.append(s) self.player_panic_sounds = [] for sound in PLAYER_PANIC_SOUNDS: s = pg.mixer.Sound(path.join(sound_folder, sound)) s.set_volume(PLAYER_PANIC_LEVEL) self.player_panic_sounds.append(s) def new(self): """For things that should happen once, at the start of a new game""" # Load map from file self.map_folder = path.join(self.game_folder, 'data/maps') # self.map = Map(path.join(game_folder, 'map.txt')) self.map = TiledMap(self, path.join(self.map_folder, MAP_NAME)) self.map_img = self.map.make_map() self.map_rect = self.map_img.get_rect() # self.paths = breadth_first_search(self.map, self # initialize all variables and do all the setup for a new game self.all_sprites = pg.sprite.LayeredUpdates() self.walls = pg.sprite.Group() self.mobs = pg.sprite.Group() self.bullets = pg.sprite.Group() self.items = pg.sprite.Group() # For Loading map from tmx data for tile_object in self.map.tmxdata.objects: obj_center = vec(tile_object.x + tile_object.width / 2, tile_object.y + tile_object.height / 2) if tile_object.name == 'player': self.player = Player(self, obj_center.x, obj_center.y) if tile_object.name == 'zombie': Mob(self, obj_center.x, obj_center.y) # For EM all entities must have unique id if tile_object.name == 'wall': Obstacle(self, tile_object.x, tile_object.y, tile_object.width, tile_object.height) if tile_object.name in ['health', 'shotgun', 'pistol']: Item(self, obj_center, tile_object.name) # self.EM = AI.EntityManager() for mob in self.mobs: # self.EM.add_entity(mob.id) #All entities must have a unique id mob.SM.current_state = zombie_states.Idle(self, mob) mob.SM.global_state = zombie_states.ZombieGlobalState(self, mob) assert self.player is not None self.camera = Camera(self.map.width, self.map.height) # Give camera total size of map # Flags self.draw_debug = False self.paused = False self.night = False self.effects_sounds['level_start'].play() def run(self): pg.mixer.music.play() # game loop - set self.playing = False to end the game self.playing = True while self.playing: self.dt = self.clock.tick(FPS) / 1000 self.events() if not self.paused: self.update() self.draw() def quit(self): pg.quit() sys.exit() def update(self): """For things that should happen every frame""" # update portion of the game loop self.all_sprites.update() self.camera.update( self.player ) # Call camera.update - give player as target to follow # Game over condition - No more zombies # if len(self.mobs) == 0: # self.playing = False # Mobs hit player hits = pg.sprite.spritecollide(self.player, self.mobs, False, collide_hit_rect) for hit in hits: now = pg.time.get_ticks() if now - hit.last_hit > MOB_HIT_TIMEOUT and random.random( ) < MOB_HIT_CHANCE: hit.last_hit = now # self.player.health -= MOB_DAMAGE hit.vel = vec(0, 0) random.choice(self.player_hit_sounds).play() if self.player.health <= 0: self.playing = False self.player.got_hit() self.player.pos += vec(MOB_KNOCKBACK, 0).rotate(-hits[0].rot) # Bullets hit mobs hits = pg.sprite.groupcollide(self.mobs, self.bullets, False, True) for mob in hits: # hit.health -= WEAPONS[self.player.weapon]['damage'] * len(hits[hit]) # hit.draw_health() for bullet in hits[mob]: mob.health -= bullet.damage mob.vel = vec(0, 0) # Player hits items hits = pg.sprite.spritecollide(self.player, self.items, False) for hit in hits: if hit.type == 'health' and self.player.health < PLAYER_HEALTH: hit.kill() self.effects_sounds['health_up'].play() self.player.add_health(HEALTH_PACK_AMOUNT) if hit.type in WEAPONS.keys(): hit.kill() self.player.pickup(hit.type) # print(hit.type) def draw_grid(self): for x in range(0, WIDTH, TILESIZE): pg.draw.line(self.screen, GREEN, (x, 0), (x, HEIGHT)) for y in range(0, HEIGHT, TILESIZE): pg.draw.line(self.screen, GREEN, (0, y), (WIDTH, y)) def render_fog(self): # draw light mask (gradient) onto fog image self.fog.fill((NIGHT_COLOUR)) self.light_rect.center = self.camera.apply(self.player).center self.fog.blit(self.light_mask, self.light_rect) self.screen.blit(self.fog, (0, 0), special_flags=pg.BLEND_MULT) def draw(self): pg.display.set_caption("{:.2f}".format(self.clock.get_fps())) # self.screen.fill(BGCOLOR) self.screen.blit(self.map_img, self.camera.apply_rect(self.map_rect)) # self.draw_grid() # self.all_sprites.draw(self.screen) for sprite in self.all_sprites: if isinstance(sprite, Mob): sprite.draw_health() self.screen.blit( sprite.image, self.camera.apply(sprite) ) # blit all sprites to screen in location of where the camera says the sprite is # if self.draw_debug: # pg.draw.rect(self.screen, CYAN, self.camera.apply_rect(sprite.hit_rect), 1) if self.night: self.render_fog() # DEBUG HUD if self.draw_debug: for wall in self.walls: pg.draw.rect(self.screen, CYAN, self.camera.apply_rect(wall.rect), 1) for sprite in self.all_sprites: if isinstance(sprite, Mob): sprite.draw_health() pg.draw.circle(self.screen, CYAN, (self.camera.apply(sprite).centerx, self.camera.apply(sprite).centery), sprite.detect_radius, 1) pg.draw.rect(self.screen, CYAN, self.camera.apply_rect(sprite.hit_rect), 1) # HUD functions draw_player_stats(self.screen, 10, 10, (self.player.health / PLAYER_HEALTH)) draw_player_stats(self.screen, 10, 40, (self.player.fatigue / PLAYER_FATIGUE), BEIGE) self.draw_text("Zombies: {}".format(len(self.mobs)), self.hud_font, 30, WHITE, WIDTH - 10, 10, align="ne") if self.player.weapon is not None: self.draw_text("{}:{}".format(self.player.weapon.name, self.player.weapon.remaining_shots), self.hud_font, 30, WHITE, 10, HEIGHT - 50, align="nw") # Paused if self.paused: self.screen.blit(self.dim_screen, (0, 0)) self.draw_text("Paused", self.title_font, 105, RED, WIDTH / 2, HEIGHT / 2, align='center') pg.display.flip() def play_new_song(self): next_song = random.choice(BG_MUSIC) self.current_song = next_song # pg.mixer.music.load(next_song) pg.mixer.music.load(path.join(self.music_folder, next_song)) pg.mixer.music.play() def events(self): # catch all events here for event in pg.event.get(): if event.type == pg.QUIT: self.quit() if event.type == pg.MOUSEBUTTONDOWN: # print(event.button) if event.button == 1: self.player.shoot() if event.type == pg.KEYDOWN: if event.key == pg.K_ESCAPE: self.quit() if event.key == pg.K_h: self.draw_debug = not self.draw_debug if event.key == pg.K_p: self.paused = not self.paused if event.key == pg.K_n: self.night = not self.night if event.key == pg.K_r: self.player.reload() if event.key == pg.K_SPACE: self.player.cycle_weapon() if event.key == pg.K_g: self.player.print_inventory() if event.type == self.SONG_END: self.play_new_song() def show_start_screen(self): pass def show_go_screen(self): self.screen.fill(BLACK) pg.mixer.fadeout(5000) self.draw_text("GAME OVER", self.title_font, 180, RED, WIDTH / 2, HEIGHT / 2, align='center') self.draw_text("Press any key to start", self.title_font, 75, WHITE, WIDTH / 2, HEIGHT * 3 / 4, align='center') pg.display.flip() self.wait_for_key() def wait_for_key(self): pg.event.wait() # Clears event queue waiting = True while waiting: self.clock.tick(FPS) for event in pg.event.get(): if event.type == pg.QUIT: waiting = False self.quit() if event.type == pg.KEYUP: waiting = False
class Game: def __init__(self): # Initialize pygame. pg.mixer.pre_init(44100, -16, 1, 2048) pg.init() pg.mixer.init() # Display pg.display.set_caption(TITLE) self.screen = pg.display.set_mode((SCREEN_WIDTH, SCREEN_HEIGHT), FULLSCREEN) self.show_fps = False self.debug = False # Sprites groups. self.all_sprites = pg.sprite.Group() self.players = pg.sprite.Group() self.visible_sprites = pg.sprite.Group() self.walls = pg.sprite.Group() self.moving_walls = pg.sprite.Group() self.items = pg.sprite.Group() # Game loop. self.clock = pg.time.Clock() self.running = True self.playing = True self.player_pos = [] self.camera_update = True # Load data from files. self.load() def load(self): # Folders. game_folder = os.path.dirname(__file__) font_folder = os.path.join(game_folder, "fnt") img_folder = os.path.join(game_folder, "img") snd_folder = os.path.join(game_folder, "snd") self.map_folder = os.path.join(game_folder, "map") # App icon. self.icon = pg.image.load(os.path.join(img_folder, GAME_IMG)) pg.display.set_icon(self.icon) # Sprite images. self.player_imgs = {} for filename in PLAYER_IMGS: new_img = pg.image.load(os.path.join(img_folder, filename)).convert_alpha() # Rotate so the sprite moves in the direction it is pointing. self.player_imgs[filename] = new_img # self.player_imgs[filename] = pg.transform.rotate(new_img, 90) # Wall images. self.wall_imgs = {} for filename in WALL_IMGS: new_img = pg.image.load(os.path.join(img_folder, filename)).convert_alpha() self.wall_imgs[filename] = new_img # Item images. self.item_imgs = {} for filename in ITEM_IMGS: new_img = pg.image.load(os.path.join(img_folder, filename)).convert_alpha() self.item_imgs[filename] = new_img # Sounds. self.sounds = {} for sound_type, filename in SOUNDS.items(): new_snd = pg.mixer.Sound(os.path.join(snd_folder, filename)) new_snd.set_volume(0.1) self.sounds[sound_type] = new_snd # Music. self.game_music = os.path.join(snd_folder, GAME_BG_MUSIC) # Text font. self.theme_font = os.path.join(font_folder, THEME_FONT) def create_map(self, filename): # Basic map background image with data. self.map = TiledMap(os.path.join(self.map_folder, filename)) self.map.make_map() # Create the camera with the map dimensions. self.camera = Camera(SCREEN_WIDTH, SCREEN_HEIGHT, self.map.width, self.map.height) movement = { "back": True, "parts": { 1: { "vel": 150, "rot": 90, "distance": 400 }, 2: { "vel": 50, "rot": 45, "distance": 100 }, 3: { "vel": 200, "rot": 0, "distance": 600, } } } # Map objects. for tile_object in self.map.tilemap_data.objects: # The center of the tile. object_center = Vec(tile_object.x + tile_object.width / 2, tile_object.y + tile_object.height / 2) # Obstacles. if tile_object.object == "obstacle": Obstacle(self, tile_object.x, tile_object.y, tile_object.width, tile_object.height, tile_object.type) elif tile_object.object == "moving_obstacle": MovingObstacle(self, tile_object.x, tile_object.y, tile_object.width, tile_object.height, tile_object.type, movement) elif tile_object.object == "item": Item(self, object_center, tile_object.type, RANDOM_START_STEP) def new(self): # Create the map. self.create_map("map1.tmx") # Create the player object. self.player = Player(self, 100, 1800, "playerimg.png") # Start playing the background music. pg.mixer.music.load(self.game_music) pg.mixer.music.set_volume(0.1) pg.mixer.music.play(loops=-1) # Start running the game.. self.run() def run(self): # Game loop. self.playing = True while self.playing: # Pause. self.dt = self.clock.tick(FPS) / 1000.0 self.events() self.update() self.draw() def events(self): # Game events loop. for event in pg.event.get(): # Check for closing window. if event.type == QUIT or event.type == KEYDOWN and event.key == \ K_ESCAPE: self.playing = False self.running = False if event.type == KEYDOWN: if event.key == K_b: # Toggle debug mode. self.debug = not self.debug if event.key == K_f: self.show_fps = not self.show_fps if event.key == K_SPACE: self.player.try_jump("push") if event.key == K_g: # Change the player gravity up/down. self.player.gravity_orientation *= -1 if event.key == K_c: # Change the player gravity up/down. self.camera_update = not self.camera_update def update(self): # Game update loop. # self.moving_walls.update() # self.players.update() self.all_sprites.update() # Make the camera center on the player sprite. if self.camera_update: self.camera.update(self.player) # Update title with information. title = TITLE + f" FPS: {round(self.clock.get_fps(), 2)}" pg.display.set_caption(title) def draw_grid(self): # A grid of lines to represent the tiles of the map. The grid will # move along with the player/camera. for x in range(self.camera.x, SCREEN_WIDTH, TILESIZE): pg.draw.line(self.screen, LIGHTGRAY, (x, 0), (x, SCREEN_HEIGHT)) for y in range(self.camera.y, SCREEN_HEIGHT, TILESIZE): pg.draw.line(self.screen, LIGHTGRAY, (0, y), (SCREEN_WIDTH, y)) def draw_boundary(self, sprite, sprite_color): # Image boundary. pg.draw.rect(self.screen, sprite_color, self.camera.apply_sprite(sprite), 1) # Hit box. pg.draw.rect(self.screen, sprite_color, self.camera.apply_rect(sprite.hit_rect), 1) surface = pg.Surface((sprite.hit_rect.width, sprite.hit_rect.height)) surface.set_alpha(128) surface.fill(sprite_color) self.screen.blit(surface, self.camera.apply_rect(sprite.hit_rect)) def draw_debug(self): # Grid of tiles. self.draw_grid() # Draw wall boundaries. for sprite in self.all_sprites: self.draw_boundary(sprite, sprite.color) def draw(self): # Game draw loop. self.screen.fill(BGCOLOR) # Map image. self.screen.blit(self.map.image, self.camera.apply_rect(self.map.rect)) # Draw all sprites. for sprite in self.visible_sprites: self.screen.blit(sprite.image, self.camera.apply_sprite(sprite)) if self.show_fps: # Draw FPS self.draw_text(f"FPS: {round(self.clock.get_fps(), 2)}", OVERLAY_SIZE, TEXT_COLOR, SCREEN_WIDTH / 2, 0, align="n", font_name=self.theme_font) if self.debug: # Draw debug. self.draw_debug() # # Cool effect. # self.player_pos.append(Vec(self.player.pos.x, self.player.pos.y)) # if len(self.player_pos) > 100: # del self.player_pos[0] # width, height = self.player.hit_rect.width, self.player.hit_rect.height # for pos in self.player_pos: # surface = pg.Surface( # (width, height)) # surface.set_alpha(50) # surface.fill(self.player.color) # self.screen.blit(surface, # self.camera.apply_rect(pg.Rect(pos.x - width / 2, # pos.y - height / 2, # width, height))) # # Make sure it doesn't cover the player, so draw the player on top. # for sprite in self.players: # self.screen.blit(sprite.image, self.camera.apply_sprite(sprite)) # # Cool effect. # Flip the display (update the display). pg.display.flip() def draw_text(self, text, size, fillcolor, x, y, align="n", font_name=None): # Create the font. font = pg.font.Font(font_name, size) # Create a surface to put the text on. text_surface = font.render(text, True, fillcolor) text_rect = text_surface.get_rect() # Align the text. if align == "nw": text_rect.topleft = (x, y) elif align == "ne": text_rect.topright = (x, y) elif align == "sw": text_rect.bottomleft = (x, y) elif align == "se": text_rect.bottomright = (x, y) elif align == "n": text_rect.midtop = (x, y) elif align == "s": text_rect.midbottom = (x, y) elif align == "e": text_rect.midright = (x, y) elif align == "w": text_rect.midleft = (x, y) elif align == "center": text_rect.center = (x, y) self.screen.blit(text_surface, text_rect) # Return the dimensions of the text rect in case it is needed for # positioning multiple text rects so that they fit together nicely. return text_rect def show_start_screen(self): # Game start screen. pass def show_game_over_screen(self): # Game over screen. pass
def make_map_from_file(self, file): self.map = TiledMap(os.path.join(self.map_folder, file)) self.game.map = self.map self.game.map_img = self.map.make_map() self.game.map_rect = self.game.map_img.get_rect()
class Game: def __init__(self): # Initializes PyGame buffer=256 pg.mixer.pre_init(frequency=22050, size=-16, channels=2, buffer=256) pg.init() # Create screen and title self.screen = pg.display.set_mode((WIDTH, HEIGHT)) pg.display.set_caption(TITLE) # Clock speed and key delay self.clock = pg.time.Clock() pg.key.set_repeat(500, 100) # Loads data.. self.load_data() def load_data(self): # Asset folders game_folder = path.dirname(__file__) img_folder = path.join(game_folder, 'assets', 'textures') snd_folder = path.join(game_folder, 'assets', 'sounds', 'snd') music_folder = path.join(game_folder, 'assets', 'sounds', 'music') self.map_folder = path.join(game_folder, 'assets', 'maps') # Font self.title_font = path.join(img_folder, 'ZOMBIE.TTF') self.hud_font = path.join(img_folder, 'Impacted2.0.ttf') # Object images self.dim_screen = pg.Surface(self.screen.get_size()).convert_alpha() self.dim_screen.fill((0, 0, 0, 150)) self.player_img = pg.image.load( path.join(img_folder, 'player', PLAYER_IMG)).convert_alpha() self.bullet_images = {} self.bullet_images['lg'] = pg.image.load( path.join(img_folder, 'bullet', BULLET_IMG)).convert_alpha() self.bullet_images['sm'] = pg.transform.scale(self.bullet_images['lg'], (10, 10)) self.mob_img = pg.image.load(path.join(img_folder, 'mob', MOB_IMG)).convert_alpha() self.splat = pg.image.load(path.join(img_folder, 'mob', SPLAT)).convert_alpha() self.splat = pg.transform.scale(self.splat, (64, 64)) # Particles self.gun_flashes = [] for img in MUZZLE_FLASHES: self.gun_flashes.append( pg.image.load(path.join(img_folder, 'particles', img)).convert_alpha()) # Items self.item_images = {} for item in ITEM_IMAGES: self.item_images[item] = pg.image.load( path.join(img_folder, 'items', ITEM_IMAGES[item])).convert_alpha() # Lighting effects self.fog = pg.Surface((WIDTH, HEIGHT)) self.fog.fill(NIGHT_COLOR) self.light_mask = pg.image.load(path.join(img_folder, LIGHT_MASK)).convert_alpha() self.light_mask = pg.transform.scale(self.light_mask, LIGHT_RADIUS) self.light_rect = self.light_mask.get_rect() # Sounds pg.mixer.music.load(path.join(music_folder, BG_MUSIC)) self.effects_sounds = {} for type in EFFECTS_SOUNDS: s = pg.mixer.Sound(path.join(snd_folder, EFFECTS_SOUNDS[type])) s.set_volume(0.5) self.effects_sounds[type] = s self.weapon_sounds = {} for weapon in WEAPON_SOUNDS: self.weapon_sounds[weapon] = [] for snd in WEAPON_SOUNDS[weapon]: s = pg.mixer.Sound(path.join(snd_folder, snd)) if weapon == 'shotgun': s.set_volume(0.2) else: s.set_volume(0.5) self.weapon_sounds[weapon].append(s) self.zombie_moan_sounds = [] for snd in ZOMBIE_MOAN_SOUNDS: s = pg.mixer.Sound(path.join(snd_folder, snd)) s.set_volume(0.2) self.zombie_moan_sounds.append(s) self.player_hit_sounds = [] for snd in PLAYER_HIT_SOUNDS: self.player_hit_sounds.append( pg.mixer.Sound(path.join(snd_folder, snd))) self.zombie_hit_sounds = [] for snd in ZOMBIE_HIT_SOUNDS: s = pg.mixer.Sound(path.join(snd_folder, snd)) s.set_volume(0.3) self.zombie_hit_sounds.append(s) def new(self): # initialize all variables and do all the setup for a new game self.draw_debug = False self.paused = False self.night = True # Sprite groups self.all_sprites = pg.sprite.LayeredUpdates() self.obstacles = pg.sprite.Group() self.mobs = pg.sprite.Group() self.bullets = pg.sprite.Group() self.items = pg.sprite.Group() # Map self.map = TiledMap(path.join(self.map_folder, '01.tmx')) self.map_img = self.map.make_map() self.map_rect = self.map_img.get_rect() # Map Objects for tile_object in self.map.tmxdata.objects: # For spawning in center of tiled object obj_center = vec(tile_object.x + tile_object.width / 2, tile_object.y + tile_object.height / 2) if tile_object.name == 'player': self.player = Player(self, obj_center.x, obj_center.y) if tile_object.name == 'zombie': Mob(self, obj_center.x, obj_center.y) if tile_object.name == 'wall': Obstacle(self, tile_object.x, tile_object.y, tile_object.width, tile_object.height) if tile_object.name in ['health', 'shotgun']: Item(self, obj_center, tile_object.name) # Camera object self.camera = Camera(self.map.width, self.map.height) # Start a new level sound self.effects_sounds['level_start'].play() def run(self): # game loop - set self.playing = False to end the game self.playing = True # Starts music pg.mixer.music.play(loops=-1) while self.playing: # dt - How much time did the last frame take in ms (For frame-independent movement) self.dt = self.clock.tick(FPS) / 1000 self.events() if not self.paused: self.update() self.draw() def events(self): # catch all events here for event in pg.event.get(): # Closing window if event.type == pg.QUIT: self.quit() # Keyboard press if event.type == pg.KEYDOWN: # ESC if event.key == pg.K_ESCAPE: self.quit() if event.key == pg.K_h: self.draw_debug = not self.draw_debug if event.key == pg.K_p: self.paused = not self.paused if event.key == pg.K_n: self.night = not self.night def update(self): # Update portion of the game loop self.all_sprites.update() self.camera.update(self.player) # Game over? if len(self.mobs) == 0: self.playing = False # Player and item hits = pg.sprite.spritecollide(self.player, self.items, False) for hit in hits: if hit.type == 'health' and self.player.health < PLAYER_HEALTH: hit.kill() # Destroy item self.effects_sounds['health_up'].play() # Play sound self.player.add_health(HEALTH_PACK_AMOUNT) # Add health if hit.type == 'shotgun': hit.kill() self.effects_sounds['gun_pickup'].play() self.player.weapon = 'shotgun' # Player and mobs hits = pg.sprite.spritecollide(self.player, self.mobs, False, collide_hit_rect) for hit in hits: # Play sound if random() < 0.7: choice(self.player_hit_sounds).play() # Take damage self.player.health -= MOB_DAMAGE hit.vel = vec(0, 0) if self.player.health <= 0: self.playing = False if hits: self.player.hit() self.player.pos += vec(MOB_KNOCKBACK, 0).rotate(-hits[0].rot) # Bullets and Mobs hits = pg.sprite.groupcollide(self.mobs, self.bullets, False, True) for mob in hits: for bullet in hits[mob]: mob.health -= bullet.damage mob.vel = vec(0, 0) def draw(self): # Shows window title and FPS counter pg.display.set_caption("{} FPS - {:.2f}".format( TITLE, self.clock.get_fps())) # Fill background # self.screen.fill(BGCOLOR) # Draws grid # self.draw_grid() # Draws map self.screen.blit(self.map_img, self.camera.apply_rect(self.map_rect)) # Draws all sprites ant hit rectangles for sprite in self.all_sprites: if isinstance(sprite, Mob): sprite.draw_health() self.screen.blit(sprite.image, self.camera.apply(sprite)) if self.draw_debug: pg.draw.rect(self.screen, CYAN, self.camera.apply_rect(sprite.hit_rect), 1) if self.draw_debug: for obstacle in self.obstacles: pg.draw.rect(self.screen, CYAN, self.camera.apply_rect(obstacle.rect), 1) # Lighting effects if self.night: self.render_fog() # Draws HUD draw_player_health(self.screen, 10, 10, self.player.health / PLAYER_HEALTH) self.draw_text('Zombies: {}'.format(len(self.mobs)), self.hud_font, 30, WHITE, WIDTH - 10, 10, align="ne") # Draws PAUSED if self.paused: self.screen.blit(self.dim_screen, (0, 0)) self.draw_text("Paused", self.title_font, 105, RED, WIDTH / 2, HEIGHT / 2, align="center") # Flips/Updates screen pg.display.flip() def render_fog(self): self.fog.fill(NIGHT_COLOR) self.light_rect.center = self.camera.apply(self.player).center self.fog.blit(self.light_mask, self.light_rect) self.screen.blit(self.fog, (0, 0), special_flags=pg.BLEND_MULT) def draw_text(self, text, font_name, size, color, x, y, align="nw"): font = pg.font.Font(font_name, size) text_surface = font.render(text, True, color) text_rect = text_surface.get_rect() if align == "nw": text_rect.topleft = (x, y) if align == "ne": text_rect.topright = (x, y) if align == "sw": text_rect.bottomleft = (x, y) if align == "se": text_rect.bottomright = (x, y) if align == "n": text_rect.midtop = (x, y) if align == "s": text_rect.midbottom = (x, y) if align == "e": text_rect.midright = (x, y) if align == "w": text_rect.midleft = (x, y) if align == "center": text_rect.center = (x, y) self.screen.blit(text_surface, text_rect) def draw_grid(self): for x in range(0, WIDTH, TILESIZE): pg.draw.line(self.screen, LIGHTGREY, (x, 0), (x, HEIGHT)) for y in range(0, HEIGHT, TILESIZE): pg.draw.line(self.screen, LIGHTGREY, (0, y), (WIDTH, y)) def show_start_screen(self): pass def show_go_screen(self): self.screen.fill(BLACK) self.draw_text("GAME OVER", self.title_font, 100, RED, WIDTH / 2, HEIGHT / 2, align="center") self.draw_text("Press a key to start", self.title_font, 75, WHITE, WIDTH / 2, HEIGHT * 3 / 4, align="center") pg.display.flip() self.wait_for_key() def wait_for_key(self): pg.event.wait() waiting = True while waiting: self.clock.tick(FPS) for event in pg.event.get(): if event.type == pg.QUIT: waiting = False self.quit() if event.type == pg.KEYUP: waiting = False def quit(self): pg.quit() sys.exit()