Example #1
0
class Cutscene(Minigame):
    GAME_NAME = "Cutscene"
    _default_layer = 1

    def __init__(self,
                 scene_name="cutscene001",
                 scene_file_name="test-cutscene.yaml"):
        self.running = False
        self.script_runner = ScriptRunner()
        self._scene_name = scene_name
        self._scene_file_name = scene_file_name
        self._border = None
        self._sprites = LayeredUpdates()
        self._animations = Group()
        self._dialog_open = False
        self._dialog_rect = None
        self._caption = None
        self._text = None

    def initialize(self, context):
        with open(get_data_asset(self._scene_file_name)) as fp:
            config = yaml.load(fp)
        self.script_runner.start(self, config[self._scene_name])

    @staticmethod
    def new_sprite(image, rect):
        sprite = Sprite()
        sprite.image = image
        sprite.rect = rect
        return sprite

    def animate(self, *args, **kwargs):
        ani = animation.Animation(*args, **kwargs)
        self._animations.add(ani)
        return ani

    def add_sprite(self, image, rect, layer=None):
        self._sprites.add(self.new_sprite(image, rect),
                          layer=ternone(layer, self._default_layer))

    def set_background(self, filename):
        surf = smoothscale(load_image(filename), SCREEN_SIZE).convert()
        rect = (0, 0), SCREEN_SIZE
        self.add_sprite(surf, rect, 0)

    def set_portrait(self, filename):
        size = 340, 680

        # HACK to remove old portrait
        for sprite in self._sprites:
            if sprite.image.get_size() == size:
                self._sprites.remove(sprite)

        if filename is not None:
            surf = smoothscale(load_image(filename), size).convert_alpha()
            rect = (900, 60), size
            self.add_sprite(surf, rect, 1)

    def set_caption(self, value):
        if value is None:
            self._caption = None
            return

        get = self.script_runner.vars.get
        fcolor = Color(get('caption-fg', 'black'))
        font = load_font('pixChicago.ttf', 16)
        if 'caption-bg' in self.script_runner.vars and get(
                'caption-bg') is not None:
            bcolor = Color(get('caption-bg'))
            image = font.render(value, 0, fcolor, bcolor)
            margins = image.get_rect().inflate(45, 0)
            background = pygame.Surface(margins.size)
            background.fill(bcolor)
            background.blit(image, (24, 0))
            self._caption = background
        else:
            self._caption = font.render(value, 0, fcolor)

    def set_text(self, value):
        get = self.script_runner.vars.get
        fcolor = Color(get('text-fg', 'black'))
        bcolor = none_or_not(self.script_runner.vars, 'text-bg', Color)
        font = load_font('pixChicago.ttf', 16)
        w, h = self.final_rect().size
        w -= 48
        final_rect = Rect((0, 0), (w, h))
        self._text = pygame.Surface(final_rect.size, pygame.SRCALPHA)
        draw_text(self._text, value, final_rect, font, fcolor, bcolor)

    def final_rect(self):
        sw, sh = SCREEN_SIZE
        return Rect(sw * .05, sh * .6, sw * .62, sh * .35)

    def queue_dialog_text(self, value):
        self.set_text(value)

    def open_dialog(self):
        self._dialog_open = True
        final_rect = self.final_rect()
        self._dialog_rect = Rect(0, 0, 64, 64, center=final_rect.center)
        ani = self.animate(self._dialog_rect,
                           height=final_rect.height,
                           width=final_rect.width,
                           duration=100)
        ani.schedule(
            lambda: setattr(self._dialog_rect, "center", final_rect.center),
            'on update')

    def close_dialog(self):
        self._dialog_open = False

    def run(self, context):
        flip = pygame.display.flip
        update = self.update
        draw = self.draw
        handle_events = self.handle_event
        screen = pygame.display.get_surface()
        clock = time.time
        frame_time = (1 / 60.) * 1000
        last_draw = 0
        times = deque(maxlen=10)

        self.running = True
        last_frame = clock()
        while self.running:
            dt = (clock() - last_frame) * 1000
            last_frame = clock()
            times.append(dt)
            dt = sum(times) / 10
            last_draw += dt
            handle_events()
            update(dt)
            if last_draw >= frame_time:
                draw(screen)
                flip()
                last_draw = 0

        pygame.mixer.music.fadeout(800)

    def draw(self, screen):
        self._sprites.draw(screen)

        if self._dialog_open:
            self.draw_dialog(screen)

    def draw_dialog(self, surface):
        with surface_clipping_context(surface, self._dialog_rect):
            self._border.draw(surface, self._dialog_rect)

        internal = self._dialog_rect.inflate(-48, -6)
        with surface_clipping_context(surface, internal):
            if self._caption:
                rect = self._caption.get_rect()
                rect.top = internal.top
                rect.centerx = internal.centerx
                surface.blit(self._caption, rect)

            if self._text:
                rect = internal.copy()
                rect.top = internal.top + 75
                rect.left = internal.left
                surface.blit(self._text, rect)

    def update(self, dt):
        self._animations.update(dt)

    def button_press(self):
        """ Handles the ACTION button

        :return:
        """
        self.script_runner.dialog_event('press')

    def handle_event(self):
        for event in pygame.event.get():
            if event.type == KEYDOWN:
                if event.key == K_ESCAPE:
                    self.running = False
                if event.key == K_SPACE:
                    self.button_press()
            if event.type == QUIT:  # this will allow pressing the windows (X) to close the game
                sys.exit(0)
Example #2
0
class PlatformerScene(Scene):
    def __init__(self, game):
        super().__init__(game)
        self.player = None
        self.active = True

        self.geometry = list()
        self.space = pymunk.Space()
        self.space.gravity = (0, 1000)
        self.sprites = LayeredUpdates()
        self.event_handler = event_handling.EventQueueHandler()
        self.background = resources.gfx("background.png", convert=True)
        self.load()
        pygame.mixer.music.load(resources.music_path("zirkus.ogg"))
        pygame.mixer.music.play(-1)

    def add_static(self, vertices, rect):
        body = pymunk.Body(body_type=pymunk.Body.STATIC)
        body.position = rect.x, rect.y
        shape = pymunk.Poly(body, vertices)
        shape.friction = 1.0
        shape.elasticity = 1.0
        self.space.add(body, shape)

    def load(self):
        def box_vertices(x, y, w, h):
            lt = x, y
            rt = x + w, y
            rb = x + w, y + h
            lb = x, y + h
            return lt, rt, rb, lb

        filename = path_join("data", "maps", "untitled.tmx")
        tmxdata = pytmx.util_pygame.load_pygame(filename)
        for obj in tmxdata.objects:
            if obj.type == map_fixed:
                rect = Rect(obj.x, obj.y, obj.width, obj.height)
                vertices = box_vertices(0, 0, obj.width, obj.height)
                self.add_static(vertices, rect)

            elif obj.type == map_yarn_spawn:
                ball = sprite.Ball(Rect((obj.x, obj.y), (32, 32)))
                model = BasicModel()
                model.sprites = [ball]
                model.pymunk_objects = ball.pymunk_shapes
                self.add_model(model)
                self.player = model

            elif obj.type == map_player_spawn:
                self.player = unicyclecat.build(self.space, self.sprites)
                self.player.position = obj.x, obj.y

        self.fsm = SimpleFSM(control, "idle")

    def add_model(self, model):
        self.sprites.add(*model.sprites)
        self.space.add(model.pymunk_objects)

    def remove_model(self, model):
        self.sprites.remove(*model.sprites)
        self.space.remove(model.pymunk_objects)

    def render(self):
        surface = self._game.screen
        surface.blit(self.background, (0, 0))
        self.sprites.draw(surface)
        return [surface.get_rect()]

    def tick(self, dt):
        step_amount = (1 / 30.) / 30
        for i in range(30):
            self.space.step(step_amount)
        self.sprites.update(dt)

    def event(self, pg_event):
        events = self.event_handler.process_event(pg_event)
        position = self.player.position

        for event in events:
            try:
                cmd, arg = self.fsm((event.button, event.held))
            except ValueError as e:
                continue

            if cmd == "move":
                resources.sfx("cat_wheel.ogg", False, True)
                resources.sfx("cat_wheel.ogg", True)
                self.player.accelerate(arg)

            if cmd == "idle":
                self.player.brake()

            elif cmd == "jump":
                resources.sfx("cat_jump.ogg", True)
                self.player.main_body.apply_impulse_at_world_point((0, -600),
                                                                   position)
Example #3
0
class PlatformerScene(Scene):
    """
    Platformer Scene class.
    """
    def __init__(self, game):
        super().__init__(game)
        self.player = None
        self.active = True
        self.fsm = None
        self.space = pymunk.Space()
        self.space.gravity = (0, 1000)
        self.sprites = LayeredUpdates()
        self.event_handler = event_handling.EventQueueHandler()
        self.event_handler.print_controls()
        self.background = resources.gfx("background.png", convert=True)
        self.load()
        pygame.mixer.music.load(resources.music_path("zirkus.ogg"))
        pygame.mixer.music.play(-1)

    def add_static(self, vertices, rect):
        """
        Add static object to scene.

        :param vertices:
        :param rect:
        """
        body = pymunk.Body(body_type=pymunk.Body.STATIC)
        body.position = rect.x, rect.y
        shape = pymunk.Poly(body, vertices)
        shape.friction = 1.0
        shape.elasticity = 1.0
        self.space.add(body, shape)

    def load(self):
        """
        Load a scene in TMX format.
        """
        def box_vertices(box_x, box_y, width, height):
            top_left = box_x, box_y
            top_right = box_x + width, box_y
            bottom_right = box_x + width, box_y + height
            bottom_left = box_x, box_y + height
            return top_left, top_right, bottom_right, bottom_left

        filename = path_join("data", "maps", "untitled.tmx")
        tmxdata = pytmx.util_pygame.load_pygame(filename)
        for obj in tmxdata.objects:
            if obj.type == MAP_FIXED:
                rect = Rect(obj.x, obj.y, obj.width, obj.height)
                vertices = box_vertices(0, 0, obj.width, obj.height)
                self.add_static(vertices, rect)

            elif obj.type == MAP_YARN_SPAWN:
                ball = sprite.Ball(Rect((obj.x, obj.y), (32, 32)))
                model = BasicModel()
                model.sprites = [ball]
                model.pymunk_objects = ball.pymunk_shapes
                self.add_model(model)
                self.player = model

            elif obj.type == MAP_PLAYER_SPAWN:
                self.player = unicyclecat.build(self.space, self.sprites)
                self.player.position = obj.x, obj.y

        self.fsm = SimpleFSM(CONTROL, "idle")

    def add_model(self, model):
        """
        Add a model.

        :param model: Model to add.
        """
        self.sprites.add(*model.sprites)
        self.space.add(model.pymunk_objects)

    def remove_model(self, model):
        """
        Remove a model.

        :param model: Model to remove.
        """
        self.sprites.remove(*model.sprites)
        self.space.remove(model.pymunk_objects)

    def render(self):
        """
        Render scene to the screen surface.

        """
        surface = self._game.screen
        surface.blit(self.background, (0, 0))
        self.sprites.draw(surface)
        return [surface.get_rect()]

    def tick(self, time_delta):
        """
        Tick the physics and game update loops.
        """
        step_amount = (1 / 30.0) / 30
        for _ in range(30):
            self.space.step(step_amount)
        self.sprites.update(time_delta=time_delta)

    def event(self, event):
        """
        Process an event.

        :param event: The event to process
        """
        events = self.event_handler.process_event(event)
        position = self.player.position

        for evt in events:
            try:
                cmd, arg = self.fsm((evt.button, evt.held))
            except ValueError:
                continue

            if cmd == "move":
                resources.sfx("cat_wheel.ogg", False, True)
                resources.sfx("cat_wheel.ogg", True)
                self.player.accelerate(arg)

            if cmd == "idle":
                self.player.brake()

            elif cmd == "jump":
                resources.sfx("cat_jump.ogg", True)
                self.player.main_body.apply_impulse_at_world_point((0, -600),
                                                                   position)