コード例 #1
0
class Player(Renderable):
    def __init__(self, world: 'World'):
        super().__init__(world.window)
        self.world = world

        self.size = Vector(*PLAYER_SIZE)

        self.pos = world.level.start_pos
        self.last_pos = self.pos.copy()
        self.last_x = 0
        self.vel = Vector(0, 0)
        self.accel = Vector(0, 0)

        self.on_ground = False
        self.jumping = False
        self.moving_x = False
        self.is_dying = False
        self.desired_platform = None

        self.score = 0
        self.lives = 3

        self.sprite_cols = 8
        self.sprite = Sprite('assets/player.png', self.sprite_cols, 1)
        self.roll = 0

    def jump(self):
        self.on_ground = False
        self.vel.y = -PLAYER_VELOCITY[1]
        self.accel.y = -ACCEL_GRAVITY

    def get_bounds(self) -> BoundingBox:
        pos = self.pos
        size = self.size
        return BoundingBox(pos, pos + size)

    def get_render_bounds(self) -> BoundingBox:
        bounds = self.get_bounds()
        dpi_factor = self.window.hidpi_factor
        return BoundingBox(bounds.min * dpi_factor, bounds.max * dpi_factor)

    def on_key_down(self, key: int):
        if not self.is_dying:
            if key == Key.SPACE:
                self.jumping = True  # Allow holding jump button.
                if self.on_ground:
                    self.jump()

            elif key == Key.KEY_A:
                self.vel.x = -PLAYER_VELOCITY[0]

            elif key == Key.KEY_D:
                self.vel.x = PLAYER_VELOCITY[0]

    def on_key_up(self, key: int):
        if not self.is_dying:
            if key == Key.SPACE:
                self.jumping = False

            elif key == Key.KEY_A:
                if self.vel.x < 0:
                    self.vel.x = 0

            elif key == Key.KEY_D:
                if self.vel.x > 0:
                    self.vel.x = 0

    def on_death(self):
        self.lives -= 1

        if self.lives == 0:
            self.world.window.handler = self.world.source
        else:
            self.vel.x = 0
            self.vel.y = 0
            if self.desired_platform is None:
                self.pos = Vector(PLAYER_RESPAWN_X_OFFSET, -self.size.y)
            else:
                bounds = self.desired_platform.get_bounds()

                if bounds.max.x <= 0:
                    self.pos = Vector(PLAYER_RESPAWN_X_OFFSET, -self.size.y)
                else:
                    # Place player on platform they last touched
                    self.pos = Vector(
                        bounds.max.x - self.size.x - PLAYER_RESPAWN_X_OFFSET,
                        bounds.min.y - self.size.y)

            self.is_dying = False

    def render(self, canvas: simplegui.Canvas):
        bounds = self.get_bounds()
        dpi_factor = self.window.hidpi_factor

        # Draw player.
        if PLAYER_POTATO:
            dest_center = self.pos + self.size / 2
            index = (self.roll // self.sprite_cols) % self.sprite_cols
            self.sprite.draw(canvas, dest_center * dpi_factor,
                             self.size * dpi_factor, (index, 0))
        else:
            point_list = [p.multiply(dpi_factor).into_tuple() for p in bounds]
            color = Color(120, 120, 200)

            canvas.draw_polygon(point_list, 1, str(color), str(color))

        # Update position.
        self.last_pos = self.pos.copy()
        self.pos.add(self.vel)

        self.roll += self.vel.x * 2 / PLAYER_VELOCITY[0]
        self.roll += 1

        if abs(self.vel.x) > PLAYER_VELOCITY[0]:
            self.vel.x = math.copysign(PLAYER_VELOCITY[0], self.vel.x)

        # Check collisions position.
        self.on_ground = False

        bounds = self.get_bounds()
        if not self.is_dying:
            for item in self.world.level.items:
                if item.collides_with(bounds):
                    item.on_collide(self)

        self.vel.add(self.accel)

        # Do gravity and platform collision.
        if self.on_ground:
            self.vel.y = 0
            self.accel.y = 0
        else:
            self.accel.y = -ACCEL_GRAVITY

        if bounds.max.y >= WINDOW_SIZE[1] or bounds.min.x <= 0:
            self.on_death()
コード例 #2
0
class Level(object):
    """
    A game level.
    """

    def __init__(self, world: 'World', level: int, start_pos: Tuple[int, int],
                 scroll: Vector = Vector(0.05, 0)):
        self.level = level
        self.start_pos = Vector(
            start_pos[0] * BLOCK_SIZE,
            (GRID_SIZE[1] - start_pos[1] - 1) * BLOCK_SIZE
        )

        self.offset = Vector(0, 0)
        self.scroll = scroll

        self.items: List[LevelItem] = []
        self.finished = False

        self.counter = 0
        self.world = world
        self.world.source.last_active_level = self

        self.window_size = world.window.get_size()

        # Just some initialisation stuff here; less to compute later.
        self.background_offset = self.window_size[0] / 2
        self.background_image = load_image(LEVEL_BACKGROUND_IMAGE)
        self.bg_size = (self.background_image.get_width(), self.background_image.get_height())
        self.bg_center = (self.bg_size[0] / 2, self.bg_size[1] / 2)

    def get_score(self):
        return self.world.player.score

    def add_item(self, item: LevelItem):
        """
        Adds the item to the level.
        """
        self.items.append(item)

    def finish(self):
        """
        Finishes the level.
        """
        self.finished = True

    def render(self, world: 'World', canvas: simplegui.Canvas):
        """
        Called on every game tick to render the level.
        """

        # Draw background
        if LEVEL_USE_BACKGROUND:
            center_dest1 = (
                -(self.offset.x % self.window_size[0]) + self.background_offset,
                self.window_size[1] / 2
            )
            center_dest2 = (
                center_dest1[0] + self.window_size[0],
                center_dest1[1]
            )
            canvas.draw_image(self.background_image, self.bg_center, self.bg_size,
                              center_dest1, self.window_size)
            canvas.draw_image(self.background_image, self.bg_center, self.bg_size,
                              center_dest2, self.window_size)

        self.counter += 1

        if self.counter % BLOCK_SIZE == 0:
            self.counter = 0
            world.player.score += 1

        dpi_factor = world.window.hidpi_factor

        font = world.text_font
        font_color = world.text_font_color
        score_text = "SCORE // {0:d}".format(world.player.score)
        lives_text = "LIVES // {0:d}".format(world.player.lives)

        canvas.draw_text(score_text, (10 * dpi_factor, 20 * dpi_factor), font.get_size(),
                         str(font_color),
                         font.get_face())
        canvas.draw_text(lives_text, (10 * dpi_factor, 40 * dpi_factor), font.get_size(),
                         str(font_color),
                         font.get_face())

        # Render items
        for item in self.items:
            bounds = item.get_bounds()
            if bounds.max.x > 0 and bounds.min.x < WINDOW_SIZE[0]:
                item.render(canvas)

        # Render player
        world.player.render(canvas)

        # Add the level scroll, mutating the current offset.
        self.offset.add(self.scroll * BLOCK_SIZE)

        # Load next level.
        if self.finished:
            levels = world.levels

            next_level = self.level + 1
            if len(levels) >= next_level:
                target_level = levels[next_level - 1]
                world.player.pos = target_level.start_pos
                world.level = target_level
            else:
                world.level = None