class TmxFile(xml.sax.handler.ContentHandler): """ This class loads a TMX MAP file into the memory from an exported TMX XML. You can export TMX file to XML using the TILED map editor: http://www.mapeditor.org/ To export a TMX to XML do the followings: - Goto: Edit-->Preferences - Set "Store layer data as:" to XML - Goto: File-->Export as (ctrl+e) - Choose a filename and SAVE I used the xml.sax to parse the XML data. See: http://docs.python.org/2/library/xml.sax.html UPDATE-2013/02/13: At the end of the loading process, the program copies all tile properties to the layers' tiles, so the tileset's tileProperties only will contain the default values for the tiles, at runtime you should use the tmxTile.getTilePropertyValue(...). """ tileMap = None # tilemap to store data from XML _currentLayout = None # current TMX layer _currentTileset = None # current Tileset _loaded = False # flag to mark the end of the loading _currentGid = 0 # to store the current gid for the tile _currentGidProperties = {} # the properties of the current gid _currentBlock = "" # the XML block which is currently processing _currentTileCount = 0 # the current tile's count _currentObjectGroup = None # current object group def __init__(self): """ Set up some initial value """ self._loaded = False def isLoaded(self): """ Returns True when the class finished the TMX processing. (When the file loaded.) """ return self._loaded def startElement(self, name, attributes): """ This method processes the start of the XML elements In this method the following startelements will be processed: object objectgroup map tileset image tile property layer """ #new object started if name == "object": self._currentObjectGroup.addObject( TmxObject(attributes['name'], attributes['type'], pygame.Rect(int(attributes['x']), int(attributes['y']), int(attributes['width']), int(attributes['height'])) )) # objectgroup started elif name == "objectgroup": self._currentObjectGroup = TmxObjectGroup( attributes['name'], int(attributes['width']), int(attributes['height'])) # new tilemap started elif name == "map": self.tileMap = TmxMap(attributes['version'], attributes['orientation'], int(attributes['width']), int(attributes['height']), int(attributes['tilewidth']), int(attributes['tileheight'])) # new tileset started elif name == "tileset": if 'spacing' in attributes: tsSpacing = attributes['spacing'] else: tsSpacing = 0 if 'margin' in attributes: tsMargin = attributes['margin'] else: tsMargin = 0 self._currentTileset = TmxTileset(attributes['name'], int(attributes['tilewidth']), int(attributes['tileheight']), int(attributes['firstgid']), int(tsSpacing), int(tsMargin)) self._currentBlock = "tileset" # image tag for tileset elif name == "image": if (self._currentTileset is not None): self._currentTileset.setImage( pygame.image.load( GameUtils.formatPath(attributes['source'], CFG_IMGSDIR)), int(attributes['width']), int(attributes['height'])) # tile/layer - tile properties elif name == "tile": if self._currentBlock == "tileset": self._currentGid = int(attributes['id']) if self._currentBlock == "layer": self._currentLayer.addTile(self._currentTileCount, int(attributes['gid']), self.tileMap.getTilesetByGid(int(attributes['gid']))) self._currentTileCount += 1 # tile/layer property elif name == "property": if self._currentBlock == "tileset": # BUG: it is not the tileset's property. It is the # tile's property self._currentTileset.addTileProperty(self._currentGid, attributes['name'], attributes['value']) elif self._currentBlock == "layer": self._currentLayer.addProperty(attributes['name'], attributes['value']) # new layer started elif name == "layer": self._currentLayer = TmxLayer(attributes['name'], int(attributes['width']), int(attributes['height']) ) self._currentTileCount = 0 self._currentBlock = "layer" def characters(self, data): """ Not used. """ pass def endElement(self, name): """ This method processes the endelements in the XML. The following endelements will be processed: objectgroup tileset layer """ if name == "objectgroup": # objectgroup's end, add it to objectgroups self.tileMap.addObjectGroup(self._currentObjectGroup) del self._currentObjectGroup elif name == "tileset": # tileset's end, add it to the tilesets self.tileMap.addTileset(self._currentTileset) del self._currentTileset elif name == "layer": # layer's end, add it to the layers self.tileMap.addLayer(self._currentLayer) del self._currentLayer def loadTmx(self, filename): """ This method starts the TMX loading. You need to specify the filename and when it finishes the process the isLoaded() method will return True. """ self._loaded = False parser = xml.sax.make_parser() parser.setContentHandler(self) # DO NOT USE DTD reference in "Tiled", because # without a http connection, it can ruin the loading # process parser.parse(filename) self._loaded = True return self.tileMap