Esempio n. 1
0
def _screen_from_json(json_data: Any, sprites: Dict[str, Sprite]) -> Screen:
    background_data = json_data.get("background")
    background_color = None
    background_tilemap = None
    if background_data:
        background_color = background_data.get("background_color")
        tilemap_data = background_data.get("background_tilemap")
        if tilemap_data:
            background_tilemap = Tilemap(tilemap_id=tilemap_data["tilemap_id"],
                                         rect_uv=Rect.from_list(
                                             tilemap_data["tilemap_uv"]))

    screen_elements = []
    if json_data.get("elements"):
        screen_elements = [
            ScreenElement(position=Point.from_list(data["position"]),
                          sprite=sprites.get(data.get("sprite_ref")),
                          text=data.get("text"))
            for data in json_data["elements"]
        ]
    menu_position = None
    menu_scrollbar_rect = None
    if json_data.get("menu"):
        menu_data = json_data["menu"]
        menu_position = \
            Point.from_list(menu_data["position"]) if menu_data.get("position") else None
        menu_scrollbar_rect = \
            Rect.from_list(menu_data["scrollbar_rect"]) if menu_data.get("scrollbar_rect") else None

    return Screen(background_color=background_color,
                  background_tilemap=background_tilemap,
                  elements=tuple(screen_elements),
                  menu_position=menu_position,
                  menu_scrollbar_rect=menu_scrollbar_rect)
Esempio n. 2
0
def process_sprites(input_data: Dict[str, Any],
                    base_dir: Path) -> Dict[str, Any]:
    """Process and pack sprites from input resource file into sprite sheet.

    :param input_data: input data from JSON file (root -> sprites)
    :param base_dir:
    :return: processed sprites (ready to be serialized to JSON)
    """
    sprite_packers = [
        SpriteSheetPacker(
            0,
            Rect.from_coords(0, 128, IMAGE_BANK_WIDTH,
                             IMAGE_BANK_HEIGHT - 128)),
        SpriteSheetPacker(
            1, Rect.from_coords(0, 0, IMAGE_BANK_WIDTH, IMAGE_BANK_HEIGHT))
    ]
    sprites = {}
    sprites_ids: List[Dict[str, int]] = [{}, {}]

    for sprite_name, sprite_data in input_data.items():
        image_bank = sprite_data["image_bank"]
        sprite_path = Path(base_dir).joinpath(sprite_data["image"])
        sprites_ids[image_bank][sprite_name] = sprite_packers[
            image_bank].add_sprite(sprite_path)
        num_layers = LEVEL_NUM_LAYERS if sprite_data.get("multilayer",
                                                         False) else 1
        transparency_color = -1
        if sprite_data.get("transparency_color"):
            transparency_color = int(sprite_data["transparency_color"], 16)

        sprites[sprite_name] = {
            "image_bank": image_bank,
            "directional": sprite_data.get("directional", False),
            "transparency_color": transparency_color,
            "num_frames": sprite_data.get("num_frames", 1),
            "num_layers": num_layers
        }

    sprite_uv_rects = [packer.pack() for packer in sprite_packers]

    for sprite_name, sprite in sprites.items():
        image_bank = sprite["image_bank"]
        sprite_id = sprites_ids[image_bank][sprite_name]
        uv_rect = sprite_uv_rects[image_bank][sprite_id]
        sprite["uv_rect"] = uv_rect.as_list
        logging.info("Sprite '%s' (%dx%d) added to image bank %d", sprite_name,
                     uv_rect.w, uv_rect.h, image_bank)

    logging.info("Total sprites: %d", len(sprites))
    return sprites
Esempio n. 3
0
    def from_level_num(cls, level_num: int, tileset_index: int,
                       draw_offset: Point,
                       sprite_packs: LevelSpritePacks) -> "LevelTemplate":
        """Create a new level template for given level number.

        :param level_num: level number to create level template for
        :param tileset_index: index of first tile (starting tile) used in the template
        :param draw_offset: the initial offset of the level (u3sed when level is drawn)
        :param sprite_packs: sprite packs used in the level
        :return: newly created level template
        """
        tilemap_u = LEVEL_WIDTH * (level_num % TILE_SIZE)
        tilemap_v = LEVEL_HEIGHT * (level_num // TILE_SIZE)
        tilemap_uv_rect = Rect.from_coords(tilemap_u, tilemap_v, LEVEL_WIDTH,
                                           LEVEL_HEIGHT)
        tilemap = Tilemap(LEVEL_BASE_TILEMAP, tilemap_uv_rect,
                          LEVEL_NUM_LAYERS)
        tileset = Tileset(tileset_index)
        layers = tuple([
            Layer(i, opaque=(i == 0), global_offset=draw_offset)
            for i in range(LEVEL_NUM_LAYERS)
        ])
        return cls(level_num=level_num,
                   tilemap=tilemap,
                   tileset=tileset,
                   layers=layers,
                   sprite_packs=sprite_packs)
Esempio n. 4
0
    def pack(self, rect: Rect) -> List[Rect]:
        """Pack all boxes that were added to box packer.

        :param rect: destination rect to pack boxes in
        :return: collection of positions for all packed boxes (coords for given box can be found by
                 using box's id assigned during add_box call)
        """
        if not self.boxes:
            return []

        uv_rects: List[Rect] = [Rect.from_coords(0, 0, 0, 0)] * len(self.boxes)
        sorted_boxes = sorted(self.boxes,
                              key=lambda b: b.size.max_dimension,
                              reverse=True)
        root_node = _Node(rect)

        for box in sorted_boxes:
            node = _Node.find_node_for_box(root_node, box.size)
            if node:
                node.split(box.size.width, box.size.height)
                node.box_id = box.box_id
                uv_rects[box.box_id] = node.rect
            else:
                raise ResourceError(
                    f"Unable to fit box with size ({box.size.width}x{box.size.height})"
                )

        return uv_rects
Esempio n. 5
0
    def split(self, right: int, bottom: int) -> None:
        """Split node by creating bottom and right child.

        :param right: the offset for right node
        :param bottom: the offset for bottom node
        """
        if self.is_split:
            return

        self.bottom_child = _Node(
            Rect.from_coords(self.rect.x, self.rect.y + bottom, self.rect.w,
                             self.rect.h - bottom))
        self.right_child = _Node(
            Rect.from_coords(self.rect.x + right, self.rect.y,
                             self.rect.w - right, bottom))
        self.rect = Rect(self.rect.position, Size(right, bottom))
Esempio n. 6
0
def _process_frames(tilemap_num: int, frame_tileset_data: Any,
                    frame_tilesets: Dict[str, NineSlicingFrame]) -> None:
    tilemap_rect = tilemap_rect_nth(tilemap_num)
    for frame_data in frame_tileset_data:
        frame_tileset = frame_tilesets[frame_data["tileset_ref"]]
        frame_rect = Rect.from_list(frame_data["rect"]).offset(
            tilemap_rect.position)
        frame_tileset.draw_frame(BACKGROUND_TILEMAP_ID, frame_rect)
Esempio n. 7
0
def tilemap_rect_nth(index: int) -> Rect:
    """Create a rectangle representing position and size of n-th tilemap in Pyxel's mega-tilemap.

    :param index: index of tilemap to create rectangle for
    :return: tilemap's rect (representing position and size of a tilemap expressed in tiles)
    """
    levels_horizontally = TILEMAP_WIDTH // LEVEL_WIDTH
    return Rect.from_coords((index % levels_horizontally) * LEVEL_WIDTH,
                            (index // levels_horizontally) * LEVEL_HEIGHT,
                            LEVEL_WIDTH, LEVEL_HEIGHT)
Esempio n. 8
0
    def generate_tilemap(self, tilemap_id: int, tilemap_rect: Rect, seed: int) -> None:
        """Generate a tilemap using random tiles at given position in Pyxel's mega-tilemap.

        Tiles are randomized using specified seed and tiles weights.

        :param tilemap_id: Pyxel's mega-tilemap id
        :param tilemap_rect: tilemap rect where generated tiles will be put into
        :param seed: seed to be used during tiles generation
        """
        state = random.getstate()
        random.seed(seed)
        tilemap_points = tilemap_rect.inside_points()
        for point in tilemap_points:
            pyxel.tilemap(tilemap_id).set(point.x, point.y, self._next_tile())
        random.setstate(state)
Esempio n. 9
0
def create_sprites(json_data: Any) -> Dict[str, Sprite]:
    """Create sprites from metadata.

    :param json_data: input JSON containing sprites metadata
    :return: collection of sprites
    """
    return {
        name: Sprite(image_bank=data["image_bank"],
                     uv_rect=Rect.from_list(data["uv_rect"]),
                     directional=data["directional"],
                     transparency_color=data["transparency_color"],
                     num_layers=data["num_layers"],
                     num_frames=data["num_frames"])
        for name, data in json_data.items()
    }