Exemple #1
0
class View:
    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
Exemple #2
0
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)
Exemple #3
0
    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)
Exemple #4
0
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
Exemple #6
0
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
Exemple #7
0
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()