bool CCTMXTiledMap::initWithTMXFile(const char *tmxFile) { CCAssert(tmxFile != NULL && strlen(tmxFile)>0, "TMXTiledMap: tmx file should not bi nil"); setContentSize(CCSizeZero); CCTMXMapInfo *mapInfo = CCTMXMapInfo::formatWithTMXFile(tmxFile); if (! mapInfo) { return false; } CCAssert( mapInfo->getTilesets()->count() != 0, "TMXTiledMap: Map not found. Please check the filename."); m_tMapSize = mapInfo->getMapSize(); m_tTileSize = mapInfo->getTileSize(); m_nMapOrientation = mapInfo->getOrientation(); setObjectGroups(mapInfo->getObjectGroups()); setProperties(mapInfo->getProperties()); CC_SAFE_RELEASE(m_pTileProperties); m_pTileProperties = mapInfo->getTileProperties(); CC_SAFE_RETAIN(m_pTileProperties); int idx = 0; CCMutableArray<CCTMXLayerInfo*>* layers = mapInfo->getLayers(); if (layers && layers->count()>0) { if (NULL == m_pTMXLayers) { m_pTMXLayers = new CCDictionary<std::string, CCTMXLayer*>(); CCAssert(m_pTMXLayers, "Allocate memory failed!"); } CCTMXLayerInfo *layerInfo = NULL; CCMutableArray<CCTMXLayerInfo*>::CCMutableArrayIterator it; for (it = layers->begin(); it != layers->end(); ++it) { layerInfo = *it; if (layerInfo && layerInfo->m_bVisible) { CCTMXLayer *child = parseLayer(layerInfo, mapInfo); addChild((CCNode*)child, idx, idx); // record the CCTMXLayer object by it's name std::string layerName = child->getLayerName(); m_pTMXLayers->setObject(child, layerName); // update content size with the max size CCSize childSize = child->getContentSize(); CCSize currentSize = this->getContentSize(); currentSize.width = MAX( currentSize.width, childSize.width ); currentSize.height = MAX( currentSize.height, childSize.height ); this->setContentSize(currentSize); idx++; } } } return true; }
// the XML parser calls here with all the elements void CCTMXMapInfo::startElement(void *ctx, const char *name, const char **atts) { CC_UNUSED_PARAM(ctx); CCTMXMapInfo *pTMXMapInfo = this; std::string elementName = (char*)name; std::map<std::string, std::string> *attributeDict = new std::map<std::string, std::string>(); if(atts && atts[0]) { for(int i = 0; atts[i]; i += 2) { std::string key = (char*)atts[i]; std::string value = (char*)atts[i+1]; attributeDict->insert(pair<std::string, std::string>(key, value)); } } if(elementName == "map") { std::string version = valueForKey("version", attributeDict); if ( version != "1.0") { CCLOG("cocos2d: TMXFormat: Unsupported TMX version: %@", version.c_str()); } std::string orientationStr = valueForKey("orientation", attributeDict); if( orientationStr == "orthogonal") pTMXMapInfo->setOrientation(CCTMXOrientationOrtho); else if ( orientationStr == "isometric") pTMXMapInfo->setOrientation(CCTMXOrientationIso); else if( orientationStr == "hexagonal") pTMXMapInfo->setOrientation(CCTMXOrientationHex); else CCLOG("cocos2d: TMXFomat: Unsupported orientation: %d", pTMXMapInfo->getOrientation()); CCSize s; s.width = (float)atof(valueForKey("width", attributeDict)); s.height = (float)atof(valueForKey("height", attributeDict)); pTMXMapInfo->setMapSize(s); s.width = (float)atof(valueForKey("tilewidth", attributeDict)); s.height = (float)atof(valueForKey("tileheight", attributeDict)); pTMXMapInfo->setTileSize(s); // The parent element is now "map" pTMXMapInfo->setParentElement(TMXPropertyMap); } else if(elementName == "tileset") { // If this is an external tileset then start parsing that std::string externalTilesetFilename = valueForKey("source", attributeDict); if (externalTilesetFilename != "") { if (m_sTMXFileName.length() == 0) { string pszFullPath = CCFileUtils::fullPathFromRelativePath(m_sResources.c_str()); if (pszFullPath.find_last_of("/\\") != pszFullPath.length()-1) { pszFullPath.append("/"); } externalTilesetFilename = CCFileUtils::fullPathFromRelativeFile(externalTilesetFilename.c_str(), pszFullPath.c_str() ); } else { externalTilesetFilename = CCFileUtils::fullPathFromRelativeFile(externalTilesetFilename.c_str(), pTMXMapInfo->getTMXFileName()); } pTMXMapInfo->parseXMLFile(externalTilesetFilename.c_str()); } else { CCTMXTilesetInfo *tileset = new CCTMXTilesetInfo(); tileset->m_sName = valueForKey("name", attributeDict); tileset->m_uFirstGid = (unsigned int)atoi(valueForKey("firstgid", attributeDict)); tileset->m_uSpacing = (unsigned int)atoi(valueForKey("spacing", attributeDict)); tileset->m_uMargin = (unsigned int)atoi(valueForKey("margin", attributeDict)); CCSize s; s.width = (float)atof(valueForKey("tilewidth", attributeDict)); s.height = (float)atof(valueForKey("tileheight", attributeDict)); tileset->m_tTileSize = s; pTMXMapInfo->getTilesets()->addObject(tileset); tileset->release(); } } else if(elementName == "tile") { CCTMXTilesetInfo* info = (CCTMXTilesetInfo*)pTMXMapInfo->getTilesets()->lastObject(); CCDictionary *dict = new CCDictionary(); pTMXMapInfo->setParentGID(info->m_uFirstGid + atoi(valueForKey("id", attributeDict))); pTMXMapInfo->getTileProperties()->setObject(dict, pTMXMapInfo->getParentGID()); CC_SAFE_RELEASE(dict); pTMXMapInfo->setParentElement(TMXPropertyTile); } else if(elementName == "layer") { CCTMXLayerInfo *layer = new CCTMXLayerInfo(); layer->m_sName = valueForKey("name", attributeDict); CCSize s; s.width = (float)atof(valueForKey("width", attributeDict)); s.height = (float)atof(valueForKey("height", attributeDict)); layer->m_tLayerSize = s; std::string visible = valueForKey("visible", attributeDict); layer->m_bVisible = !(visible == "0"); std::string opacity = valueForKey("opacity", attributeDict); if( opacity != "" ) { layer->m_cOpacity = (unsigned char)(255 * atof(opacity.c_str())); } else { layer->m_cOpacity = 255; } float x = (float)atof(valueForKey("x", attributeDict)); float y = (float)atof(valueForKey("y", attributeDict)); layer->m_tOffset = ccp(x,y); pTMXMapInfo->getLayers()->addObject(layer); layer->release(); // The parent element is now "layer" pTMXMapInfo->setParentElement(TMXPropertyLayer); } else if(elementName == "objectgroup") { CCTMXObjectGroup *objectGroup = new CCTMXObjectGroup(); objectGroup->setGroupName(valueForKey("name", attributeDict)); CCPoint positionOffset; positionOffset.x = (float)atof(valueForKey("x", attributeDict)) * pTMXMapInfo->getTileSize().width; positionOffset.y = (float)atof(valueForKey("y", attributeDict)) * pTMXMapInfo->getTileSize().height; objectGroup->setPositionOffset(positionOffset); pTMXMapInfo->getObjectGroups()->addObject(objectGroup); objectGroup->release(); // The parent element is now "objectgroup" pTMXMapInfo->setParentElement(TMXPropertyObjectGroup); } else if(elementName == "image") { CCTMXTilesetInfo* tileset = (CCTMXTilesetInfo*)pTMXMapInfo->getTilesets()->lastObject(); // build full path std::string imagename = valueForKey("source", attributeDict); if (m_sTMXFileName.length() == 0) { string pszFullPath = CCFileUtils::fullPathFromRelativePath(m_sResources.c_str()); if (pszFullPath.find_last_of("/\\") != pszFullPath.length()-1) { pszFullPath.append("/"); } tileset->m_sSourceImage = CCFileUtils::fullPathFromRelativeFile(imagename.c_str(), pszFullPath.c_str() ); } else { tileset->m_sSourceImage = CCFileUtils::fullPathFromRelativeFile(imagename.c_str(), pTMXMapInfo->getTMXFileName()); } } else if(elementName == "data") { std::string encoding = valueForKey("encoding", attributeDict); std::string compression = valueForKey("compression", attributeDict); if( encoding == "base64" ) { int layerAttribs = pTMXMapInfo->getLayerAttribs(); pTMXMapInfo->setLayerAttribs(layerAttribs | TMXLayerAttribBase64); pTMXMapInfo->setStoringCharacters(true); if( compression == "gzip" ) { layerAttribs = pTMXMapInfo->getLayerAttribs(); pTMXMapInfo->setLayerAttribs(layerAttribs | TMXLayerAttribGzip); } else if (compression == "zlib") { layerAttribs = pTMXMapInfo->getLayerAttribs(); pTMXMapInfo->setLayerAttribs(layerAttribs | TMXLayerAttribZlib); } CCAssert( compression == "" || compression == "gzip" || compression == "zlib", "TMX: unsupported compression method" ); } CCAssert( pTMXMapInfo->getLayerAttribs() != TMXLayerAttribNone, "TMX tile map: Only base64 and/or gzip/zlib maps are supported" ); } else if(elementName == "object") { char buffer[32] = {0}; CCTMXObjectGroup* objectGroup = (CCTMXObjectGroup*)pTMXMapInfo->getObjectGroups()->lastObject(); // The value for "type" was blank or not a valid class name // Create an instance of TMXObjectInfo to store the object and its properties CCDictionary *dict = new CCDictionary(); // Parse everything automatically const char* pArray[] = {"name", "type", "width", "height", "gid"}; for( int i = 0; i < sizeof(pArray)/sizeof(pArray[0]); ++i ) { const char* key = pArray[i]; CCString* obj = new CCString(valueForKey(key, attributeDict)); if( obj ) { obj->autorelease(); dict->setObject(obj, key); } } // But X and Y since they need special treatment // X const char* value = valueForKey("x", attributeDict); if( value ) { int x = atoi(value) + (int)objectGroup->getPositionOffset().x; sprintf(buffer, "%d", x); CCString* pStr = new CCString(buffer); pStr->autorelease(); dict->setObject(pStr, "x"); } // Y value = valueForKey("y", attributeDict); if( value ) { int y = atoi(value) + (int)objectGroup->getPositionOffset().y; // Correct y position. (Tiled uses Flipped, cocos2d uses Standard) y = (int)(m_tMapSize.height * m_tTileSize.height) - y - atoi(valueForKey("height", attributeDict)); sprintf(buffer, "%d", y); CCString* pStr = new CCString(buffer); pStr->autorelease(); dict->setObject(pStr, "y"); } // Add the object to the objectGroup objectGroup->getObjects()->addObject(dict); dict->release(); // The parent element is now "object" pTMXMapInfo->setParentElement(TMXPropertyObject); } else if(elementName == "property") { if ( pTMXMapInfo->getParentElement() == TMXPropertyNone ) { CCLOG( "TMX tile map: Parent element is unsupported. Cannot add property named '%s' with value '%s'", valueForKey("name", attributeDict), valueForKey("value",attributeDict) ); } else if ( pTMXMapInfo->getParentElement() == TMXPropertyMap ) { // The parent element is the map CCString *value = new CCString(valueForKey("value", attributeDict)); std::string key = valueForKey("name", attributeDict); pTMXMapInfo->getProperties()->setObject(value, key.c_str()); value->release(); } else if ( pTMXMapInfo->getParentElement() == TMXPropertyLayer ) { // The parent element is the last layer CCTMXLayerInfo* layer = (CCTMXLayerInfo*)pTMXMapInfo->getLayers()->lastObject(); CCString *value = new CCString(valueForKey("value", attributeDict)); std::string key = valueForKey("name", attributeDict); // Add the property to the layer layer->getProperties()->setObject(value, key.c_str()); value->release(); } else if ( pTMXMapInfo->getParentElement() == TMXPropertyObjectGroup ) { // The parent element is the last object group CCTMXObjectGroup* objectGroup = (CCTMXObjectGroup*)pTMXMapInfo->getObjectGroups()->lastObject(); CCString *value = new CCString(valueForKey("value", attributeDict)); const char* key = valueForKey("name", attributeDict); objectGroup->getProperties()->setObject(value, key); value->release(); } else if ( pTMXMapInfo->getParentElement() == TMXPropertyObject ) { // The parent element is the last object CCTMXObjectGroup* objectGroup = (CCTMXObjectGroup*)pTMXMapInfo->getObjectGroups()->lastObject(); CCDictionary* dict = (CCDictionary*)objectGroup->getObjects()->lastObject(); const char* propertyName = valueForKey("name", attributeDict); CCString *propertyValue = new CCString(valueForKey("value", attributeDict)); dict->setObject(propertyValue, propertyName); propertyValue->release(); } else if ( pTMXMapInfo->getParentElement() == TMXPropertyTile ) { CCDictionary* dict = (CCDictionary*)pTMXMapInfo->getTileProperties()->objectForKey(pTMXMapInfo->getParentGID()); const char* propertyName = valueForKey("name", attributeDict); CCString *propertyValue = new CCString(valueForKey("value", attributeDict)); dict->setObject(propertyValue, propertyName); propertyValue->release(); } } else if (elementName == "polygon") { // find parent object's dict and add polygon-points to it // CCTMXObjectGroup* objectGroup = (CCTMXObjectGroup*)m_pObjectGroups->lastObject(); // CCDictionary* dict = (CCDictionary*)objectGroup->getObjects()->lastObject(); // TODO: dict->setObject(attributeDict objectForKey:@"points"] forKey:@"polygonPoints"]; } else if (elementName == "polyline") { // find parent object's dict and add polyline-points to it // CCTMXObjectGroup* objectGroup = (CCTMXObjectGroup*)m_pObjectGroups->lastObject(); // CCDictionary* dict = (CCDictionary*)objectGroup->getObjects()->lastObject(); // TODO: dict->setObject:[attributeDict objectForKey:@"points"] forKey:@"polylinePoints"]; } if (attributeDict) { attributeDict->clear(); delete attributeDict; } }