Exemplo n.º 1
0
class Stage(pyglet.event.EventDispatcher):
    progress_bar = pyglet.sprite.Sprite(pyglet.resource.image('img/gui/progress_bar.png'), 0, 344)
    progress_ball = pyglet.sprite.Sprite(pyglet.resource.image('img/gui/progress_ball.png'), 0, 344)

    def __init__(self, name):
        self.name = name
        self.sections = []
        self.game_objects = set()

        self.offset = VECTOR_NULL
        self.is_scrolling = False
        self.actual_scroll_speed = VECTOR_NULL
        self.target_scroll_speed = SCROLL_SPEED
        self.active_section = None
        self.despawned_objects = set()

        log.debug(D_INIT.format(type(self).__name__, self.name))

    def setup(self):
        self.reset()
        if self.seed is not None:
            random.seed(self.seed)
        bg_pattern = pyglet.image.SolidColorImagePattern(
            self.background_color)
        bg_img = bg_pattern.create_image(640, 360)  # TODO: Magic number.
        self.background = SH.show_sprite(SH.BG, 0)
        self.background.image = bg_img

        for sect in self.sections:
            sect.setup()

        self.section_iter = iter(self.sections)
        self.advance_section()
        self.is_scrolling = True
        self.hero = Hero(Vector(100, 100))
        self.spawn_game_objects(set([self.hero]))
        self.hero.push_handlers(self)

    def reset(self):
        self.despawn_game_objects(self.game_objects)

        self.actual_scroll_speed = VECTOR_NULL
        self.offset = VECTOR_NULL
        self.active_section = None

        log.info('Reset Stage {}.'.format(self.name))

    def update(self, dt):
        self.update_stage_position(dt)
        self.update_game_objects(dt)

        self.update_sprites()
        self.check_collisions()
        self.update_progress_ball()

    def update_stage_position(self, dt):
        if self.is_scrolling:
            self.update_scroll_speed(dt)
            self.offset += self.actual_scroll_speed * dt
        if self.active_section is not None:
            if self.offset.x >= self.active_section.offset.x:
                self.advance_section()

    def update_scroll_speed(self, dt):
        if self.target_scroll_speed != self.actual_scroll_speed:
            delta = 50 * dt
            diff = self.target_scroll_speed - self.actual_scroll_speed
            self.actual_scroll_speed += diff.unit * min(delta, diff.length)

    def start_scrolling(self, scroll_speed):
        self.target_scroll_speed = scroll_speed
        self.is_scrolling = True

    def stop_scrolling(self):
        self.actual_scroll_speed = VECTOR_NULL
        self.is_scrolling = False

    def update_game_objects(self, dt):
        self.game_objects -= self.despawned_objects
        for obj in self.despawned_objects:
            obj.despawn()
        self.despawned_objects = set()
        for gob in self.game_objects:
            gob.update(dt)

    def update_sprites(self):
        for gob in self.game_objects:
            gob.align_sprite(self.offset)

    def advance_section(self):
        if self.active_section is not None:
            self.exit_section(self.active_section)
        try:
            new_section = self.section_iter.next()
            self.enter_section(new_section)
        except StopIteration:
            self.stop_scrolling()

    def exit_section(self, old_section):
        if old_section is not None:
            self.spawn_game_objects(old_section.second_actors)
            old_section.reset()
        self.active_section = None
        self.dispatch_event('on_exit_section', old_section.name)

        log.info(I_EXIT_SECTION.format(old_section.name))

    def enter_section(self, new_section):
        if new_section is not None:
            self.spawn_game_objects(new_section.props)
            self.spawn_game_objects(new_section.actors)
        self.active_section = new_section
        self.dispatch_event('on_enter_section', new_section.name)

        log.info(I_ENTER_SECTION.format(new_section.name))

    def add_section(self, section):
        section.offset = Vector(self.width, 0)
        self.sections.append(section)

        log.debug(D_ADD_SECTION.format(section.name, self.name))

    def spawn_game_objects(self, game_objects):
        for gob in game_objects:
            gob.allocate_sprite()
            gob.show()
            gob.push_handlers(self)
            log.debug(D_SPAWN.format(type(gob).__name__,
                len(self.game_objects)))
        self.game_objects |= game_objects

    def spawn_projectile(self, projectile):
        projectile.allocate_sprite()
        projectile.align_sprite(self.offset)
        projectile.show()
        log.debug(D_SPAWN_BULLET.format(type(projectile).__name__))
        self.game_objects.add(projectile)
        projectile.push_handlers(self)

    def despawn_game_objects(self, game_objects):
        for gob in game_objects:
            gob.despawn()
        self.game_objects -= game_objects

    def check_collisions(self):
        collisions = collider.aabb_collide(list(self.game_objects))
        for group in collisions:
            a, b = group
            a.collide(b, VECTOR_NULL, VECTOR_NULL)
            b.collide(a, VECTOR_NULL, VECTOR_NULL)

    @property
    def current_props(self):
        if self.active_section is not None:
            return self.active_section.props
        else:
            return set()

    @property
    def width(self):
        return world.constants['WIN_WIDTH'] * len(self.sections)

    @property
    def height(self):
        return world.constants['WIN_HEIGHT']

    @property
    def active_rect(self):
        return (self.offset.x - 100, 0,
            self.offset.x + world.constants['WIN_WIDTH'] + 100,
            world.constants['WIN_HEIGHT'])

    @property
    def left(self):
        return self.offset.x

    @property
    def right(self):
        return self.offset.x + world.constants['WIN_WIDTH']

    @property
    def bottom(self):
        return self.offset.y

    @property
    def top(self):
        return self.offset.y + world.constants['WIN_HEIGHT']

    def send_keys_to_hero(self, keys, pressed=None, released=None):
        if self.hero is not None:
            self.hero.fixSpeed(keys)
        if pressed is not None:
            self.hero.throw_pebble()

    def on_hero_moved(self, the_hero, position):
        if position.x < self.offset.x - 100:
            pass  ## log.info('Hero left to the left.')
        elif position.x > self.offset.x + world.constants['WIN_WIDTH'] + 10:
            ## log.info('Hero left to the right.')
            if self.right < self.width:
                if the_hero.status != 'knockback':
                    the_hero.send_effect('knockback')
                    self.target_scroll_speed *= 1.2
                    the_hero.max_speed *= 1.2
            else:
                self.dispatch_event('on_end_stage')

    def on_emit(self, projectile):
        self.spawn_projectile(projectile)

    def on_object_moved(self, obj, position):
        if obj.despawn_on_exit:
            if obj.right <= self.left:  ## or obj.left >= self.right
                self.despawn(obj)
            elif obj.bottom >= self.top or obj.top <= self.bottom:
                self.despawn(obj)

    def despawn(self, obj):
        self.despawned_objects.add(obj)
        log.debug('Despawning {}'.format(type(obj).__name__))

    def update_progress_ball(self):
        self.progress_ball.x = min(624, int(624 * self.hero.x / self.width))