Example #1
0
    def draw(self):
        if self.follow:
            cam = self.camera.pos
            cam.center = self.player.rect.center
            cam.bottom = min(cam.bottom, self.level_rect.bottom)
        # scrolling background
        self.screen.fill(BACKGROUND_COLOR)
        bg_rect = self.camera.apply(self.bg)
        bg_rect.x %= WIDTH
        bg_rect.y = max(bg_rect.y, HEIGHT - bg_rect.h)
        bg_rect.y = min(bg_rect.y, 0)
        self.screen.blit(self.bg.image, bg_rect)
        self.screen.blit(self.bg.image, bg_rect.move(bg_rect.width, 0))
        self.screen.blit(self.bg.image, bg_rect.move(-bg_rect.width, 0))

        # draw sprites
        for sprite in self.fixed_sprites + self.fading:
            self.screen.blit(sprite.image, self.camera.apply(sprite))
        for sprite in self.destroyers:
            self.screen.blit(sprite.image, self.camera.apply(sprite))
        self.player.draw(self.screen, self.camera, self.debug)
        for zombie in self.zombies.sprites() + self.fading_zombies:
            zombie.draw(self.screen, self.camera, self.debug)

        if self.minimap:
            mm = pg.Rect(100, 60, WIDTH - 200, HEIGHT - 120)
            map_cam = Camera(*mm)
            map_cam.move(
                -220,
                -200)  # TODO: dynamic offset & scale factor to fit whole level
            pg.draw.rect(self.screen, pg.Color('gray'), mm, 0)
            for sprite in self.fixed_sprites:
                self.screen.blit(sprite.map_image,
                                 map_cam.apply_rect(sprite.map_rect))
            # draw current screen
            cur_screen = self.camera.pos.copy()
            cur_screen.w *= 0.5
            cur_screen.h *= 0.5
            cur_screen.x *= 0.5
            cur_screen.y *= 0.5
            pg.draw.rect(self.screen, pg.Color('red'),
                         map_cam.apply_rect(cur_screen), 1)
class Game:
    all_sprites: Group

    def __init__(self):
        # Initialize pygame
        pygame.init()

        # Create variable to satisfy game loop
        self.running = True

        # Initialize game-pad / joystick[0]
        self.control = Control(self)

        # Set window title and icon
        pygame.display.set_caption('Zorlda')
        self.icon = pygame.image.load(WINDOW_ICON)
        pygame.display.set_icon(self.icon)

        # Set display size to match assets, create display, and scale
        #  'SCALED' flag seems to be an integer scalar that is in PyGame 2.0.0+
        #  without, game runs at original pixel resolution (currently at 320x180)
        self.screen = pygame.display.set_mode((ART_SCALE_X, ART_SCALE_Y),
                                              SCALED)

        # ~Sprite Groups~
        # ALL sprites # group with all sprites for camera updates
        self.all_sprites = pygame.sprite.Group()
        # Walls group
        self.walls = pygame.sprite.Group()
        # Mobs group
        self.mobs = pygame.sprite.Group()
        # Animated sprites group
        self.anim_spr = pygame.sprite.Group()
        # EXPERIMENTAL Set up active sprite group, which sorts layering by Y axis value
        # self.sprite_draw_group = YSortedGroup()
        # Beeper group
        self.beepers = pygame.sprite.Group()

        # ~Levels/Maps
        # Load the map file
        self.map = TiledMap(MAP_FILE)
        self.map_img = self.map.make_map()
        self.map_rect = self.map_img.get_rect()

        # Load objects from map
        self.load_map_obj()

        # -Background objects - transparent layer on top of other sprites bushes, fountains, etc.
        self.bg_objects = BGObjects(self, 0, 0, BG_OBJECTS_IMG)

        # ~Clocks
        # Pygame clock
        self.clock = pygame.time.Clock()
        # # Delta time for movement
        # self.dt = 0
        # Animation clock
        self.anim_clock = Animation()

        # ~Camera
        # IT'S MAGIC
        self.camera = Camera(self.map.width, self.map.height)

        # Testing
        self.show_fps = False
        self.draw_debug = False

    def load_map_obj(self):
        for tile_object in self.map.tmxdata.objects:
            if tile_object.name == 'player':
                # Place Player
                self.player = Player(self, tile_object.x, tile_object.y,
                                     PLAYER_SPRITESHEET)
            if tile_object.name == 'karel':
                # place Karels
                Karel(self, tile_object.x, tile_object.y, KAREL_SPRITESHEET)
            if tile_object.name == 'wall':
                # place wall, etc. bounding boxes
                Obstacle(self, tile_object.x, tile_object.y, tile_object.width,
                         tile_object.height)

    def input_processing(self):
        self.control.get_input()

    def update(self):
        # Update ALL SPRITES
        # Sprite groups can ONLY call the update function and then use the functions *in there* XD
        self.all_sprites.update()

        # a Karel hits the Player(!)
        hits = pygame.sprite.spritecollide(self.player,
                                           self.mobs,
                                           False,
                                           collided=collide_hit_rect)
        for hit in hits:
            self.player.health -= 1
            # hit.vel = vec(0, 0)
            if self.player.health <= 0:
                self.running = False
        if hits:
            # KNOCK-BACK
            # TODO: make this more responsive
            #  ...camera moves too much to be comfortable at high velocities
            #  solution might be to stop the mob and player's movement for a sec, freeze mob longer than player
            self.player.pos += hit.vel * 8
            hit.pos = hit.pos - (hit.vel * 12)

        # a Karel hits a beeper
        hits = pygame.sprite.groupcollide(self.mobs, self.beepers, False, True)
        for hit in hits:
            hit.health -= 1

        # Update camera
        self.camera.update(self.player.hit_rect)

    def render(self):
        # Render Map layers
        self.screen.blit(self.map_img, self.camera.apply_rect(self.map_rect))

        # Render all sprites!!
        for sprite in self.all_sprites:
            self.screen.blit(sprite.image, self.camera.apply(sprite))
            if self.draw_debug:
                pygame.draw.rect(self.screen, CYAN,
                                 self.camera.apply_rect(sprite.hit_rect), 1)

        # Testing functions
        # Show FPS in window title
        if self.show_fps:
            pygame.display.set_caption('Zorlda - FPS:{:.2f}'.format(
                self.clock.get_fps()))
        else:
            pygame.display.set_caption('Zorlda')
        # Show bounding boxes
        if self.draw_debug:
            for wall in self.walls:
                pygame.draw.rect(self.screen, CYAN,
                                 self.camera.apply_rect(wall.rect), 1)

        # HUD functions
        draw_player_health(self.screen, 10, 10, self.player.health)

        # Update display
        pygame.display.update()

    def run(self):
        while self.running:
            self.input_processing()
            self.update()
            self.render()
            # Frame-rate (essentially divides 1000 milliseconds(via PyGame clock) by FRAME_RATE)
            self.clock.tick(FRAME_RATE)
Example #3
0
class Game:
    def __init__(self):
        pg.init()
        self.screen = pg.display.set_mode((WIDTH, HEIGHT))
        pg.display.set_caption(TITLE)
        self.clock = pg.time.Clock()
        self.load_data()

    def load_data(self):
        game_folder = path.dirname(__file__)
        img_folder = path.join(game_folder, 'img')
        map_folder = path.join(game_folder, 'img')
        self.map = TiledMap(path.join(map_folder, 'map_city.tmx'))
        self.map_img = self.map.make_map()
        self.map_rect = self.map_img.get_rect()

    def new(self):
        # initialize all variables and do all the setup for a new game
        self.all_sprites = pg.sprite.Group()
        self.obstacles = pg.sprite.Group()
        self.stairsRD = pg.sprite.Group()
        self.stairsLD = pg.sprite.Group()
        for tile_object in self.map.tmxdata.objects:
            if tile_object.name == 'player':
                self.player_img = [self.map.tmxdata.get_tile_image_by_gid(gid) for gid, duration in tile_object.properties['frames']]
                self.player = Player(self, tile_object.x, tile_object.y)
            if tile_object.name == 'obstacle':
                Obstacle(self, tile_object.x, tile_object.y,
                         tile_object.width, tile_object.height)
            if tile_object.name == 'stair-right-down':
                StairRD(self, tile_object.x, tile_object.y,
                         tile_object.width, tile_object.height)
            if tile_object.name == 'stair-left-down':
                StairLD(self, tile_object.x, tile_object.y,
                         tile_object.width, tile_object.height)
        self.camera = Camera(self.map.width, self.map.height)
        self.draw_debug = False

    def run(self):
        # 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()
            self.update()
            self.draw()

    def quit(self):
        pg.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):
        pg.display.set_caption("{:.2f}".format(self.clock.get_fps()))
        # 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))
        
        pg.display.flip()

    def events(self):
        # catch all events here
        for event in pg.event.get():
            if event.type == pg.QUIT:
                self.quit()
            if event.type == pg.KEYDOWN:
                if event.key == pg.K_ESCAPE:
                    self.quit()

    def show_start_screen(self):
        pass

    def show_go_screen(self):
        pass
Example #4
0
class Game:
    def __init__(self):
        """Initialize everything needed to run the game."""
        pg.init()
        self.screen = pg.display.set_mode((WIDTH, HEIGHT))
        pg.display.set_caption(TITLE)
        self.clock = pg.time.Clock()
        pg.key.set_repeat(500, 100)

    def new(self):
        """ Initialize everything needed for a new game."""
        self.background = self.create_layer(Tile)
        # Holds all layers.
        self.layers = [self.background]
        self.player_sprite = pg.sprite.Group()
        self.player = Player(self, 0, 0)
        self.camera = Camera(self.background.width, self.background.height)

    def create_layer(self, object_type):
        """Create a layer and populate it with the appropriate object."""
        layer = Grid(object_type)
        layer.init_chunks()
        layer.init_objects()
        return layer

    def run(self):
        """Runs pygame."""
        while True:
            self.dt = self.clock.tick(FPS) / 1000
            self.events()
            self.update()
            self.draw()

    def events(self):
        """Catch all events here."""
        for event in pg.event.get():
            if event.type == pg.QUIT:
                pg.quit()
                sys.exit()
            if event.type == pg.KEYDOWN:
                if event.key == pg.K_ESCAPE:
                    pg.quit()
                    sys.exit()
                # Moves the player and camera.
                if event.key == pg.K_LEFT:
                    self.player.move(dx=-1)
                if event.key == pg.K_RIGHT:
                    self.player.move(dx=1)
                if event.key == pg.K_UP:
                    self.player.move(dy=-1)
                if event.key == pg.K_DOWN:
                    self.player.move(dy=1)

    def update(self):
        """Everything that needs to be updated is done here."""
        # Update player sprite.
        self.player_sprite.update()
        self.camera.update(self.player)
        # Uses player position to know which chunks to render around it.
        for layer in self.layers:
            layer.render = layer.render_chunks(*self.player.get())
        # Set new limits for the camera.
        self.camera._update_max_size(self.background)

    def draw(self):
        """Draws images and displays it on the screen."""
        # Covers previous screen. Essentially wipes it.
        self.screen.fill(BGCOLOR)
        # Get fps of the game.
        pg.display.set_caption("{:.2f}".format(self.clock.get_fps()))
        for layer in self.layers:
            for chunk in layer.render:
                for tile in chunk:
                    self.screen.blit(tile[0], self.camera.apply_rect(tile[1]))
        for sprite in self.player_sprite:
            self.screen.blit(sprite.image, self.camera.apply(sprite))
        pg.display.flip()
Example #5
0
class Game(object):
    def __init__(self):
        self.screen = pg.display.set_mode(SIZE)
        self.clock = pg.time.Clock()
        self.running = True
        self.paused = False
        self.debug = False
        self.shift = False
        self.follow = False
        self.minimap = False
        self.FPS = 60
        self.bg = Background(SIZE)
        self.camera = Camera(w=WIDTH, h=HEIGHT)
        self.blocks = []
        self.fading = []
        self.fading_zombies = []
        self.screenshot_counter = 0
        self.destroyers = pg.sprite.Group()
        self.player = Ninja(position=(200, 100), screen=self.bg.rect)
        zombie1 = Zombie((100, 500), self.bg.rect, False)
        zombie2 = Zombie((700, 50), self.bg.rect, True)
        self.zombies = pg.sprite.Group(zombie1, zombie2)

        self.reset()

        self.run()

    def reset(self):
        for char in self.zombies.sprites() + [self.player]:
            char.reset()
            # TODO: readd zombies
        level, deco, self.objects, level_rect, cam_origin = load_level()
        self.fixed_sprites = level + deco + self.objects
        del self.blocks[:]
        self.blocks.extend([block.rect for block in level])
        if cam_origin:
            self.camera.reset()
            self.camera.move(*cam_origin)
            self.camera.pos.bottom = min(self.camera.pos.bottom,
                                         level_rect.bottom)
        else:
            self.camera.pos.center = level_rect.center
            self.camera.pos.bottom = level_rect.bottom
        self.level_rect = level_rect

    def toggle_debug(self):
        self.debug = not self.debug

    def toggle_paused(self):
        if self.minimap: return

        self.paused = not self.paused

    def toggle_follow(self):
        self.follow = not self.follow

    def toggle_slomo(self):
        # slow motion
        self.FPS = 30 if self.FPS == 60 else 60

    def toggle_minimap(self):
        self.minimap = not self.minimap
        self.paused = self.minimap

    def ranged_attack(self):
        if self.paused: return

        kunai = self.player.throw()
        if kunai:
            self.destroyers.add(kunai)

    def right(self):
        if self.shift:
            self.camera.move(100, 0)
        elif not self.paused:
            self.player.move_right()

    def left(self):
        if self.shift:
            self.camera.move(-100, 0)
        elif not self.paused:
            self.player.move_left()

    def up(self):
        if self.shift:
            self.camera.move(0, -100)
        elif not self.paused:
            self.player.move_up()

    def down(self):
        if self.shift:
            self.camera.move(0, 100)
        elif not self.paused:
            self.player.move_down()

    def screenshot(self):
        filename = "screenshot{c}.jpg".format(c=self.screenshot_counter)
        self.screenshot_counter += 1
        pg.image.save(self.screen, filename)

    def draw(self):
        if self.follow:
            cam = self.camera.pos
            cam.center = self.player.rect.center
            cam.bottom = min(cam.bottom, self.level_rect.bottom)
        # scrolling background
        self.screen.fill(BACKGROUND_COLOR)
        bg_rect = self.camera.apply(self.bg)
        bg_rect.x %= WIDTH
        bg_rect.y = max(bg_rect.y, HEIGHT - bg_rect.h)
        bg_rect.y = min(bg_rect.y, 0)
        self.screen.blit(self.bg.image, bg_rect)
        self.screen.blit(self.bg.image, bg_rect.move(bg_rect.width, 0))
        self.screen.blit(self.bg.image, bg_rect.move(-bg_rect.width, 0))

        # draw sprites
        for sprite in self.fixed_sprites + self.fading:
            self.screen.blit(sprite.image, self.camera.apply(sprite))
        for sprite in self.destroyers:
            self.screen.blit(sprite.image, self.camera.apply(sprite))
        self.player.draw(self.screen, self.camera, self.debug)
        for zombie in self.zombies.sprites() + self.fading_zombies:
            zombie.draw(self.screen, self.camera, self.debug)

        if self.minimap:
            mm = pg.Rect(100, 60, WIDTH - 200, HEIGHT - 120)
            map_cam = Camera(*mm)
            map_cam.move(
                -220,
                -200)  # TODO: dynamic offset & scale factor to fit whole level
            pg.draw.rect(self.screen, pg.Color('gray'), mm, 0)
            for sprite in self.fixed_sprites:
                self.screen.blit(sprite.map_image,
                                 map_cam.apply_rect(sprite.map_rect))
            # draw current screen
            cur_screen = self.camera.pos.copy()
            cur_screen.w *= 0.5
            cur_screen.h *= 0.5
            cur_screen.x *= 0.5
            cur_screen.y *= 0.5
            pg.draw.rect(self.screen, pg.Color('red'),
                         map_cam.apply_rect(cur_screen), 1)

    def run(self):
        while self.running:

            dt = self.clock.tick(
                self.FPS) / 1000  # Amount of seconds between each loop.

            def nop():
                return lambda: None

            def stop():
                if self.paused: return
                self.player.stop()

            keydown_handlers = defaultdict(
                nop, {
                    pg.K_ESCAPE:
                    sys.exit,
                    pg.K_F1:
                    self.toggle_debug,
                    pg.K_F2:
                    self.toggle_slomo,
                    pg.K_F3:
                    self.toggle_follow,
                    pg.K_F12:
                    self.screenshot,
                    pg.K_RIGHT:
                    self.right,
                    pg.K_LEFT:
                    self.left,
                    pg.K_UP:
                    self.up,
                    pg.K_DOWN:
                    self.down,
                    pg.K_SPACE:
                    lambda: None if self.paused else self.player.jump(),
                    pg.K_LCTRL:
                    lambda: None if self.paused else self.player.attack(),
                    pg.K_x:
                    lambda: None if self.paused else self.player.die(),
                    pg.K_c:
                    lambda: None if self.paused else self.player.glide(),
                    pg.K_v:
                    self.ranged_attack,
                    pg.K_r:
                    self.reset,
                    pg.K_p:
                    self.toggle_paused,
                    pg.K_m:
                    self.toggle_minimap,
                    pg.K_b:
                    lambda: [zombie.die() for zombie in self.zombies],
                    pg.K_a:
                    lambda: [zombie.attack() for zombie in self.zombies],
                })
            keyup_handlers = defaultdict(
                nop,
                {
                    pg.K_RIGHT: stop,
                    pg.K_LEFT: stop,
                    pg.K_UP: stop,
                    pg.K_DOWN: stop,
                    # pg.K_DOWN or pg.K_UP: self.player.velocity.y = 0
                })
            for event in pg.event.get():
                mods = pg.key.get_mods()
                self.shift = mods & pg.KMOD_SHIFT
                if event.type == pg.QUIT:
                    self.running = False
                elif event.type == pg.KEYDOWN:
                    keydown_handlers[event.key]()
                elif event.type == pg.KEYUP:
                    keyup_handlers[event.key]()

            if not self.paused:
                # update character geometry
                self.player.fall()
                for zombie in self.zombies:
                    zombie.fall()
                self.player.update(
                    self.blocks +
                    [o.rect for o in self.objects + self.zombies.sprites()],
                    self.camera)
                for zombie in self.zombies:
                    zombie.update(
                        self.blocks +
                        [o.rect for o in self.objects + [self.player]])
                for zombie in self.fading_zombies:
                    zombie.update([])

                # ranged attacks
                for destr in self.destroyers:
                    if destr.update(self.blocks, self.camera):
                        self.destroyers.remove(destr)
                    idx = destr.rect.collidelist(self.objects)
                    if idx != -1:
                        self.destroyers.remove(destr)
                        obj = self.objects[idx]
                        self.fading.append(obj)
                        self.objects.remove(obj)
                        self.fixed_sprites.remove(obj)
                    for zombie in self.zombies:
                        if destr.rect.colliderect(zombie.rect):
                            if zombie.suffer(50):
                                self.zombies.remove(zombie)
                                self.fading_zombies.append(zombie)
                            self.destroyers.remove(destr)

                # melee attack
                death_box = self.player.get_attack_box()
                if death_box:
                    idx = death_box.collidelist(self.objects)
                    if idx != -1:
                        obj = self.objects[idx]
                        self.fading.append(obj)
                        self.objects.remove(obj)
                        self.fixed_sprites.remove(obj)
                    idx = death_box.collidelist([z.rect for z in self.zombies])
                    for zombie in self.zombies:
                        if death_box.colliderect(zombie.rect):
                            if zombie.suffer(2):
                                self.fading_zombies.append(zombie)
                                self.zombies.remove(zombie)

            # fade-outs
            self.fading = [obj for obj in self.fading if not obj.fade()]
            self.fading_zombies = [
                z for z in self.fading_zombies if not z.fade()
            ]

            self.draw()

            if self.debug:
                # show animation progression
                anim, idx = self.player.get_anim()
                x = y = 20
                scale_factor = -0.5
                for i, a in enumerate(anim):
                    rect = a.get_rect()
                    rect.inflate_ip(rect.w * scale_factor,
                                    rect.h * scale_factor)
                    image = pg.transform.scale(a, rect[-2:])
                    rect.move_ip(x, y)
                    x += rect.width
                    self.screen.blit(image, rect)
                    if i == idx + 1:
                        pg.draw.rect(self.screen, RED, rect, 1)

                pg.draw.rect(self.screen, RED, self.camera.apply(self.player),
                             1)
                for sprite in self.fixed_sprites + self.destroyers.sprites():
                    pg.draw.rect(self.screen, RED, self.camera.apply(sprite),
                                 1)

                if self.player.current_animation == 'Attack':
                    r = self.player.rect.h // 2
                    top = self.player.rect.top
                    x = self.player.rect.right if self.player.facing_right else self.player.rect.left
                    y = top + r
                    pg.draw.circle(self.screen, RED,
                                   self.camera.apply_coords((x, y)), r, 1)
                    death_box = self.player.get_attack_box()
                    if death_box:
                        pg.draw.rect(self.screen, RED,
                                     self.camera.apply_rect(death_box), 1)

            pg.display.update()