def _parse_object(obj): my_id = obj.attrib["id"] my_x = float(obj.attrib["x"]) my_y = float(obj.attrib["y"]) my_location = objects.OrderedPair(x=my_x, y=my_y) if "width" in obj.attrib: my_width = float(obj.attrib["width"]) else: my_width = None if "height" in obj.attrib: my_height = float(obj.attrib["height"]) else: my_height = None my_name = obj.attrib["name"] properties: Optional[objects.Properties] properties_element = obj.find("./properties") if properties_element is not None: properties = _parse_properties_element(properties_element) else: properties = None # This is where it would be nice if we could assume a walrus # operator was part of our Python distribution. my_object = None polygon = obj.findall("./polygon") if polygon and len(polygon) > 0: points = _parse_points(polygon[0].attrib["points"]) my_object = objects.PolygonObject( id_=my_id, name=my_name, location=my_location, size=(my_width, my_height), points=points, properties=properties, ) if my_object is None: polyline = obj.findall("./polyline") if polyline and len(polyline) > 0: points = _parse_points(polyline[0].attrib["points"]) my_object = objects.PolylineObject( id_=my_id, name=my_name, location=my_location, size=(my_width, my_height), points=points, properties=properties, ) if my_object is None: ellipse = obj.findall("./ellipse") if ellipse and len(ellipse): my_object = objects.ElipseObject( id_=my_id, name=my_name, location=my_location, size=(my_width, my_height), properties=properties, ) if my_object is None: if "template" in obj.attrib: print("Warning, this .tmx file is using an unsupported" "'template' attribute. Ignoring.") if my_object is None: point = obj.findall("./point") if point: my_object = objects.PointObject( id_=my_id, name=my_name, location=my_location, properties=properties, ) if my_object is None: my_object = objects.RectangleObject( id_=my_id, name=my_name, location=my_location, size=(my_width, my_height), properties=properties, ) return my_object
def _parse_tiles( tile_element_list: List[etree.Element]) -> Dict[int, objects.Tile]: """Parse a list of tile elements. Args: tile_element_list (List[etree.Element]): List of tile elements. Returns: Dict[int, objects.Tile]: Dictionary containing Tile objects by their ID. """ tiles: Dict[int, objects.Tile] = {} for tile_element in tile_element_list: # id is not optional id_ = int(tile_element.attrib["id"]) # optional attributes _type = None try: _type = tile_element.attrib["type"] except KeyError: pass terrain = None try: tile_terrain_attrib = tile_element.attrib["terrain"] except KeyError: pass else: # below is an attempt to explain how terrains are handled. # 'terrain' attribute is a comma seperated list of 4 values, # each is either an integer or blank # convert to list of values terrain_list_attrib = re.split(",", tile_terrain_attrib) # terrain_list is list of indexes of Tileset.terrain_types terrain_list: List[Optional[int]] = [] # each index in terrain_list_attrib refers to a corner for corner in terrain_list_attrib: if not corner: terrain_list.append(None) else: terrain_list.append(int(corner)) terrain = objects.TileTerrain(*terrain_list) # tile element optional sub-elements properties: Optional[List[objects.Property]] = None tile_properties_element = tile_element.find("./properties") if tile_properties_element: properties = [] property_list = tile_properties_element.findall("./property") for property_ in property_list: name = property_.attrib["name"] value = property_.attrib["value"] obj = objects.Property(name, value) properties.append(obj) # tile element optional sub-elements animation: Optional[List[objects.Frame]] = None tile_animation_element = tile_element.find("./animation") if tile_animation_element: animation = [] frames = tile_animation_element.findall("./frame") for frame in frames: # tileid refers to the Tile.id of the animation frame animated_id = int(frame.attrib["tileid"]) # duration is in MS. Should perhaps be converted to seconds. # FIXME: make decision duration = int(frame.attrib["duration"]) animation.append(objects.Frame(animated_id, duration)) # tile element optional sub-elements objectgroup: Optional[List[objects.TiledObject]] = None objectgroup_element = tile_element.find("./objectgroup") if objectgroup_element: objectgroup = [] object_list = objectgroup_element.findall("./object") for object in object_list: my_id = object.attrib["id"] my_x = float(object.attrib["x"]) my_y = float(object.attrib["y"]) if "width" in object.attrib: my_width = float(object.attrib["width"]) else: my_width = None if "height" in object.attrib: my_height = float(object.attrib["height"]) else: my_height = None # This is where it would be nice if we could assume a walrus # operator was part of our Python distribution. my_object = None polygon = object.findall("./polygon") if polygon and len(polygon) > 0: points = _parse_points(polygon[0].attrib["points"]) my_object = objects.PolygonObject(id_=my_id, location=(my_x, my_y), size=(my_width, my_height), points=points) if my_object is None: polyline = object.findall("./polyline") if polyline and len(polyline) > 0: points = _parse_points(polyline[0].attrib["points"]) my_object = objects.PolylineObject(id_=my_id, location=(my_x, my_y), size=(my_width, my_height), points=points) if my_object is None: ellipse = object.findall("./ellipse") if ellipse and len(ellipse): my_object = objects.ElipseObject(id_=my_id, location=(my_x, my_y), size=(my_width, my_height)) if my_object is None: my_object = objects.RectangleObject(id_=my_id, location=(my_x, my_y), size=(my_width, my_height)) objectgroup.append(my_object) # if this is None, then the Tile is part of a spritesheet image = None image_element = tile_element.find("./image") if image_element is not None: image = _parse_image_element(image_element) # print(f"Adding '{id_}', {image}, {objectgroup}") tiles[id_] = objects.Tile(id_=id_, type_=_type, terrain=terrain, animation=animation, image=image, properties=properties, tileset=None, objectgroup=objectgroup) return tiles