def read_tiled_map(filename: str, scaling) -> TiledMap: """ Given a filename, this will read in a tiled map, and return a TiledMap object. """ # Create a map object to store this stuff in my_map = TiledMap() # Read in and parse the file tree = etree.parse(filename) # Root node should be 'map' map_tag = tree.getroot() # Pull attributes that should be in the file for the map my_map.version = map_tag.attrib["version"] my_map.orientation = map_tag.attrib["orientation"] my_map.renderorder = map_tag.attrib["renderorder"] my_map.width = int(map_tag.attrib["width"]) my_map.height = int(map_tag.attrib["height"]) my_map.tilewidth = int(map_tag.attrib["tilewidth"]) my_map.tileheight = int(map_tag.attrib["tileheight"]) # Background color is optional, and may or may not be in there if "backgroundcolor" in map_tag.attrib: # Decode the background color string backgroundcolor_string = map_tag.attrib["backgroundcolor"] red_hex = "0x" + backgroundcolor_string[1:3] green_hex = "0x" + backgroundcolor_string[3:5] blue_hex = "0x" + backgroundcolor_string[5:7] red = int(red_hex, 16) green = int(green_hex, 16) blue = int(blue_hex, 16) my_map.backgroundcolor = (red, green, blue) my_map.nextobjectid = map_tag.attrib["nextobjectid"] # Grab all the tilesets tileset_tag_list = map_tag.findall('./tileset') # --- Tileset Data --- # Loop through each tileset for tileset_tag in tileset_tag_list: firstgid = int(tileset_tag.attrib["firstgid"]) if "source" in tileset_tag.attrib: source = tileset_tag.attrib["source"] tileset_tree = etree.parse(source) # Root node should be 'map' tileset_root = tileset_tree.getroot() tile_tag_list = tileset_root.findall("tile") else: # Grab each tile tile_tag_list = tileset_tag.findall("tile") # Loop through each tile for tile_tag in tile_tag_list: # Make a tile object my_tile = Tile() image = tile_tag.find("image") my_tile.local_id = tile_tag.attrib["id"] my_tile.width = int(image.attrib["width"]) my_tile.height = int(image.attrib["height"]) my_tile.source = image.attrib["source"] key = str(firstgid) my_map.global_tile_set[key] = my_tile firstgid += 1 objectgroup = tile_tag.find("objectgroup") if objectgroup: my_object = objectgroup.find("object") if my_object: offset_x = round(float(my_object.attrib['x'])) offset_y = round(float(my_object.attrib['y'])) polygon = my_object.find("polygon") if polygon is not None: point_list = parse_points(polygon.attrib['points']) for point in point_list: point[0] += offset_x point[1] += offset_y point[1] = my_tile.height - point[1] point[0] -= my_tile.width // 2 point[1] -= my_tile.height // 2 point[0] *= scaling point[1] *= scaling point[0] = int(point[0]) point[1] = int(point[1]) my_tile.points = point_list # --- Map Data --- # Grab each layer layer_tag_list = map_tag.findall('./layer') for layer_tag in layer_tag_list: layer_width = int(layer_tag.attrib['width']) # Unzip and unencode each layer data = layer_tag.find("data") data_text = data.text.strip() encoding = data.attrib['encoding'] if 'compression' in data.attrib: compression = data.attrib['compression'] else: compression = None if encoding == "csv": layer_grid_ints = _process_csv_encoding(data_text) elif encoding == "base64": layer_grid_ints = _process_base64_encoding(data_text, compression, layer_width) else: print(f"Error, unexpected encoding: {encoding}.") break # Great, we have a grid of ints. Save that according to the layer name my_map.layers_int_data[layer_tag.attrib["name"]] = layer_grid_ints # Now create grid objects for each tile layer_grid_objs = [] for row_index, row in enumerate(layer_grid_ints): layer_grid_objs.append([]) for column_index, column in enumerate(row): grid_location = GridLocation() if layer_grid_ints[row_index][column_index] != 0: key = str(layer_grid_ints[row_index][column_index]) grid_location.tile = my_map.global_tile_set[key] if my_map.renderorder == "right-down": adjusted_row_index = my_map.height - row_index - 1 else: adjusted_row_index = row_index if my_map.orientation == "orthogonal": grid_location.center_x = column_index * my_map.tilewidth + my_map.tilewidth // 2 grid_location.center_y = adjusted_row_index * my_map.tileheight + my_map.tilewidth // 2 else: grid_location.center_x, grid_location.center_y = isometric_grid_to_screen(column_index, row_index, my_map.width, my_map.height, my_map.tilewidth, my_map.tileheight) layer_grid_objs[row_index].append(grid_location) my_map.layers[layer_tag.attrib["name"]] = layer_grid_objs return my_map
def read_tiled_map(tmx_file: str, scaling: float = 1, tsx_file: str = None) -> TiledMap: """ read_tiled_map has been deprecated. Use arcade.tilemap.read_tmx instead. Given a tmx_file, this will read in a tiled map, and return a TiledMap object. Given a tsx_file, the map will use it as the tileset. If tsx_file is not specified, it will use the tileset specified within the tmx_file. Important: Tiles must be a "collection" of images. Hitboxes can be drawn around tiles in the tileset editor, but only polygons are supported. (This is a great area for PR's to improve things.) :param str tmx_file: String with name of our TMX file :param float scaling: Scaling factor. 0.5 will half all widths and heights :param str tsx_file: Tileset to use (can be specified in TMX file) :returns: Map :rtype: TiledMap """ from warnings import warn warn('read_tiled_map has been deprecated. Use arcade.tilemap.read_tmx instead.', DeprecationWarning) # Create a map object to store this stuff in my_map = TiledMap() # If we should pull from local resources, replace with proper path if tmx_file.startswith(":resources:"): import os path = os.path.dirname(os.path.abspath(__file__)) tmx_file = f"{path}/resources/{tmx_file[11:]}" # Read in and parse the file tree = ElementTree.parse(tmx_file) # Root node should be 'map' map_tag = tree.getroot() # Pull attributes that should be in the file for the map my_map.version = map_tag.attrib["version"] my_map.orientation = map_tag.attrib["orientation"] my_map.renderorder = map_tag.attrib["renderorder"] my_map.width = int(map_tag.attrib["width"]) my_map.height = int(map_tag.attrib["height"]) my_map.tilewidth = int(map_tag.attrib["tilewidth"]) my_map.tileheight = int(map_tag.attrib["tileheight"]) # Background color is optional, and may or may not be in there if "backgroundcolor" in map_tag.attrib: # Decode the background color string background_color_string = map_tag.attrib["backgroundcolor"] red_hex = "0x" + background_color_string[1:3] green_hex = "0x" + background_color_string[3:5] blue_hex = "0x" + background_color_string[5:7] red = int(red_hex, 16) green = int(green_hex, 16) blue = int(blue_hex, 16) my_map.backgroundcolor = (red, green, blue) my_map.nextobjectid = map_tag.attrib["nextobjectid"] # Grab all the tilesets tileset_tag_list = map_tag.findall('./tileset') # --- Tileset Data --- # Loop through each tileset for tileset_tag in tileset_tag_list: firstgid = int(tileset_tag.attrib["firstgid"]) if tsx_file is not None or "source" in tileset_tag.attrib: if tsx_file is not None: tileset_tree = ElementTree.parse(tsx_file) else: source = tileset_tag.attrib["source"] try: tileset_tree = ElementTree.parse(source) except FileNotFoundError: source = Path(tmx_file).parent / Path(source) tileset_tree = ElementTree.parse(source) # Root node should be 'map' tileset_root = tileset_tree.getroot() tile_tag_list = tileset_root.findall("tile") else: # Grab each tile tile_tag_list = tileset_tag.findall("tile") # Loop through each tile for tile_tag in tile_tag_list: # Make a tile object my_tile = Tile() image = tile_tag.find("image") my_tile.local_id = tile_tag.attrib["id"] my_tile.width = int(image.attrib["width"]) my_tile.height = int(image.attrib["height"]) my_tile.source = image.attrib["source"] key = str(int(my_tile.local_id) + 1) my_map.global_tile_set[key] = my_tile firstgid += 1 objectgroup = tile_tag.find("objectgroup") if objectgroup: my_object = objectgroup.find("object") if my_object: offset_x = round(float(my_object.attrib['x'])) offset_y = round(float(my_object.attrib['y'])) polygon = my_object.find("polygon") if polygon is not None: point_list = _parse_points(polygon.attrib['points']) for point in point_list: point[0] += offset_x point[1] += offset_y point[1] = my_tile.height - point[1] point[0] -= my_tile.width // 2 point[1] -= my_tile.height // 2 point[0] *= scaling point[1] *= scaling point[0] = int(point[0]) point[1] = int(point[1]) my_tile.points = point_list polygon = my_object.find("polyline") if polygon is not None: point_list = _parse_points(polygon.attrib['points']) for point in point_list: point[0] += offset_x point[1] += offset_y point[1] = my_tile.height - point[1] point[0] -= my_tile.width // 2 point[1] -= my_tile.height // 2 point[0] *= scaling point[1] *= scaling point[0] = int(point[0]) point[1] = int(point[1]) if point_list[0][0] != point_list[-1][0] or point_list[0][1] != point_list[-1][1]: point_list.append([point_list[0][0], point_list[0][1]]) my_tile.points = point_list # --- Map Data --- # Grab each layer layer_tag_list = map_tag.findall('./layer') for layer_tag in layer_tag_list: layer_width = int(layer_tag.attrib['width']) # Unzip and unencode each layer data = layer_tag.find("data") data_text = data.text.strip() encoding = data.attrib['encoding'] if 'compression' in data.attrib: compression = data.attrib['compression'] else: compression = None if encoding == "csv": layer_grid_ints = _process_csv_encoding(data_text) elif encoding == "base64": layer_grid_ints = _process_base64_encoding(data_text, compression, layer_width) else: print(f"Error, unexpected encoding: {encoding}.") break # Great, we have a grid of ints. Save that according to the layer name my_map.layers_int_data[layer_tag.attrib["name"]] = layer_grid_ints # Now create grid objects for each tile layer_grid_objs = [] for row_index, row in enumerate(layer_grid_ints): layer_grid_objs.append([]) for column_index, column in enumerate(row): grid_loc = GridLocation() if layer_grid_ints[row_index][column_index] != 0: key = str(layer_grid_ints[row_index][column_index]) if key not in my_map.global_tile_set: print(f"Warning, tried to load '{key}' and it is not in the tileset.") else: grid_loc.tile = my_map.global_tile_set[key] if my_map.renderorder == "right-down": adjusted_row_index = my_map.height - row_index - 1 else: adjusted_row_index = row_index if my_map.orientation == "orthogonal": grid_loc.center_x = column_index * my_map.tilewidth + my_map.tilewidth // 2 grid_loc.center_y = adjusted_row_index * my_map.tileheight + my_map.tilewidth // 2 else: grid_loc.center_x, grid_loc.center_y = isometric_grid_to_screen(column_index, row_index, my_map.width, my_map.height, my_map.tilewidth, my_map.tileheight) layer_grid_objs[row_index].append(grid_loc) my_map.layers[layer_tag.attrib["name"]] = layer_grid_objs return my_map
def read_tiled_map(filename: str) -> TiledMap: # Create a map to store this stuff in my_map = TiledMap() # Read in and parse the file tree = etree.parse(filename) # Root node should be 'map' map_tag = tree.getroot() my_map.version = map_tag.attrib["version"] my_map.orientation = map_tag.attrib["orientation"] my_map.renderorder = map_tag.attrib["renderorder"] my_map.width = int(map_tag.attrib["width"]) my_map.height = int(map_tag.attrib["height"]) my_map.tilewidth = int(map_tag.attrib["tilewidth"]) my_map.tileheight = int(map_tag.attrib["tileheight"]) if "backgroundcolor" in map_tag.attrib: backgroundcolor_string = map_tag.attrib["backgroundcolor"] red_hex = "0x" + backgroundcolor_string[1:3] green_hex = "0x" + backgroundcolor_string[3:5] blue_hex = "0x" + backgroundcolor_string[5:7] red = int(red_hex, 16) green = int(green_hex, 16) blue = int(blue_hex, 16) my_map.backgroundcolor = (red, green, blue) my_map.nextobjectid = map_tag.attrib["nextobjectid"] # Grab all the tilesets tileset_tag_list = map_tag.findall('./tileset') # --- Tileset Data --- # Loop through each tileset for tileset_tag in tileset_tag_list: firstgid = int(tileset_tag.attrib["firstgid"]) # Grab each tile tile_tag_list = tileset_tag.findall("tile") # Loop through each tile for tile_tag in tile_tag_list: # Make a tile object my_tile = Tile() image = tile_tag.find("image") my_tile.local_id = tile_tag.attrib["id"] my_tile.width = int(image.attrib["width"]) my_tile.height = int(image.attrib["height"]) my_tile.source = image.attrib["source"] key = str(firstgid) my_map.global_tile_set[key] = my_tile firstgid += 1 # --- Map Data --- # Grab each layer layer_tag_list = map_tag.findall('./layer') for layer_tag in layer_tag_list: layer_width = int(layer_tag.attrib['width']) layer_grid_ints = [[]] # Unzip and unencode each layer data = layer_tag.find("data") data_text = data.text.strip() unencoded_data = base64.b64decode(data_text) unzipped_data = zlib.decompress(unencoded_data) # Turn bytes into 4-byte integers byte_count = 0 int_count = 0 int_value = 0 row_count = 0 for byte in unzipped_data: int_value += byte << (byte_count * 8) byte_count += 1 if byte_count % 4 == 0: byte_count = 0 int_count += 1 layer_grid_ints[row_count].append(int_value) int_value = 0 if int_count % layer_width == 0: row_count += 1 layer_grid_ints.append([]) layer_grid_ints.pop() my_map.layers_int_data[layer_tag.attrib["name"]] = layer_grid_ints layer_grid_objs = [] for row_index, row in enumerate(layer_grid_ints): layer_grid_objs.append([]) for column_index, column in enumerate(row): grid_location = GridLocation() if layer_grid_ints[row_index][column_index] != 0: key = str(layer_grid_ints[row_index][column_index]) grid_location.tile = my_map.global_tile_set[key] if my_map.renderorder == "right-down": adjusted_row_index = my_map.height - row_index - 1 else: adjusted_row_index = row_index if my_map.orientation == "orthogonal": grid_location.center_x = column_index * my_map.tilewidth + my_map.tilewidth // 2 grid_location.center_y = adjusted_row_index * my_map.tileheight + my_map.tilewidth // 2 else: grid_location.center_x, grid_location.center_y = isometric_grid_to_screen( column_index, row_index, my_map.width, my_map.height, my_map.tilewidth, my_map.tileheight) layer_grid_objs[row_index].append(grid_location) my_map.layers[layer_tag.attrib["name"]] = layer_grid_objs return my_map