1 /**************************************************************************** 2 Copyright (c) 2008-2010 Ricardo Quesada 3 Copyright (c) 2011-2012 cocos2d-x.org 4 Copyright (c) 2013-2014 Chukong Technologies Inc. 5 6 http://www.cocos2d-x.org 7 8 Permission is hereby granted, free of charge, to any person obtaining a copy 9 of this software and associated documentation files (the "Software"), to deal 10 in the Software without restriction, including without limitation the rights 11 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 copies of the Software, and to permit persons to whom the Software is 13 furnished to do so, subject to the following conditions: 14 15 The above copyright notice and this permission notice shall be included in 16 all copies or substantial portions of the Software. 17 18 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 19 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 20 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 21 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 22 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 23 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 24 THE SOFTWARE. 25 ****************************************************************************/ 26 27 /** 28 * @constant 29 * @type Number 30 */ 31 cc.TMX_PROPERTY_NONE = 0; 32 33 /** 34 * @constant 35 * @type Number 36 */ 37 cc.TMX_PROPERTY_MAP = 1; 38 39 /** 40 * @constant 41 * @type Number 42 */ 43 cc.TMX_PROPERTY_LAYER = 2; 44 45 /** 46 * @constant 47 * @type Number 48 */ 49 cc.TMX_PROPERTY_OBJECTGROUP = 3; 50 51 /** 52 * @constant 53 * @type Number 54 */ 55 cc.TMX_PROPERTY_OBJECT = 4; 56 57 /** 58 * @constant 59 * @type Number 60 */ 61 cc.TMX_PROPERTY_TILE = 5; 62 63 /** 64 * @constant 65 * @type Number 66 */ 67 cc.TMX_TILE_HORIZONTAL_FLAG = 0x80000000; 68 69 70 /** 71 * @constant 72 * @type Number 73 */ 74 cc.TMX_TILE_VERTICAL_FLAG = 0x40000000; 75 76 /** 77 * @constant 78 * @type Number 79 */ 80 cc.TMX_TILE_DIAGONAL_FLAG = 0x20000000; 81 82 /** 83 * @constant 84 * @type Number 85 */ 86 cc.TMX_TILE_FLIPPED_ALL = (cc.TMX_TILE_HORIZONTAL_FLAG | cc.TMX_TILE_VERTICAL_FLAG | cc.TMX_TILE_DIAGONAL_FLAG) >>> 0; 87 88 /** 89 * @constant 90 * @type Number 91 */ 92 cc.TMX_TILE_FLIPPED_MASK = (~(cc.TMX_TILE_FLIPPED_ALL)) >>> 0; 93 94 // Bits on the far end of the 32-bit global tile ID (GID's) are used for tile flags 95 96 /** 97 * <p>cc.TMXLayerInfo contains the information about the layers like: <br /> 98 * - Layer name<br /> 99 * - Layer size <br /> 100 * - Layer opacity at creation time (it can be modified at runtime) <br /> 101 * - Whether the layer is visible (if it's not visible, then the CocosNode won't be created) <br /> 102 * <br /> 103 * This information is obtained from the TMX file.</p> 104 * @class 105 * @extends cc.Class 106 * 107 * @property {Array} properties - Properties of the layer info. 108 */ 109 cc.TMXLayerInfo = cc.Class.extend(/** @lends cc.TMXLayerInfo# */{ 110 properties:null, 111 112 name:"", 113 _layerSize:null, 114 _tiles:null, 115 visible:null, 116 _opacity:null, 117 ownTiles:true, 118 _minGID:100000, 119 _maxGID:0, 120 offset:null, 121 122 ctor:function () { 123 this.properties = []; 124 this.name = ""; 125 this._layerSize = null; 126 this._tiles = null; 127 this.visible = true; 128 this._opacity = 0; 129 this.ownTiles = true; 130 this._minGID = 100000; 131 this._maxGID = 0; 132 this.offset = cc.p(0,0); 133 }, 134 135 /** 136 * Gets the Properties. 137 * @return {Array} 138 */ 139 getProperties:function () { 140 return this.properties; 141 }, 142 143 /** 144 * Set the Properties. 145 * @param {object} value 146 */ 147 setProperties:function (value) { 148 this.properties = value; 149 } 150 }); 151 152 /** 153 * <p>cc.TMXTilesetInfo contains the information about the tilesets like: <br /> 154 * - Tileset name<br /> 155 * - Tileset spacing<br /> 156 * - Tileset margin<br /> 157 * - size of the tiles<br /> 158 * - Image used for the tiles<br /> 159 * - Image size<br /> 160 * 161 * This information is obtained from the TMX file. </p> 162 * @class 163 * @extends cc.Class 164 * 165 * @property {string} name - Tileset name 166 * @property {number} firstGid - First grid 167 * @property {number} spacing - Spacing 168 * @property {number} margin - Margin 169 * @property {string} sourceImage - Filename containing the tiles (should be sprite sheet / texture atlas) 170 * @property {cc.Size|null} imageSize - Size in pixels of the image 171 */ 172 cc.TMXTilesetInfo = cc.Class.extend(/** @lends cc.TMXTilesetInfo# */{ 173 174 //Tileset name 175 name:"", 176 177 //First grid 178 firstGid:0, 179 _tileSize:null, 180 181 //Spacing 182 spacing:0, 183 184 //Margin 185 margin:0, 186 187 //Filename containing the tiles (should be sprite sheet / texture atlas) 188 sourceImage:"", 189 190 //Size in pixels of the image 191 imageSize:null, 192 193 ctor:function () { 194 this._tileSize = cc.size(0, 0); 195 this.imageSize = cc.size(0, 0); 196 }, 197 198 /** 199 * Return rect 200 * @param {Number} gid 201 * @return {cc.Rect} 202 */ 203 rectForGID:function (gid, result) { 204 var rect = result || cc.rect(0, 0, 0, 0); 205 rect.width = this._tileSize.width; 206 rect.height = this._tileSize.height; 207 gid &= cc.TMX_TILE_FLIPPED_MASK; 208 gid = gid - parseInt(this.firstGid, 10); 209 var max_x = parseInt((this.imageSize.width - this.margin * 2 + this.spacing) / (this._tileSize.width + this.spacing), 10); 210 rect.x = parseInt((gid % max_x) * (this._tileSize.width + this.spacing) + this.margin, 10); 211 rect.y = parseInt(parseInt(gid / max_x, 10) * (this._tileSize.height + this.spacing) + this.margin, 10); 212 return rect; 213 } 214 }); 215 216 /** 217 * <p>cc.TMXMapInfo contains the information about the map like: <br/> 218 *- Map orientation (hexagonal, isometric or orthogonal)<br/> 219 *- Tile size<br/> 220 *- Map size</p> 221 * 222 * <p>And it also contains: <br/> 223 * - Layers (an array of TMXLayerInfo objects)<br/> 224 * - Tilesets (an array of TMXTilesetInfo objects) <br/> 225 * - ObjectGroups (an array of TMXObjectGroupInfo objects) </p> 226 * 227 * <p>This information is obtained from the TMX file. </p> 228 * @class 229 * @extends cc.saxParser 230 * 231 * @property {Array} properties - Properties of the map info. 232 * @property {Number} orientation - Map orientation. 233 * @property {Object} parentElement - Parent element. 234 * @property {Number} parentGID - Parent GID. 235 * @property {Object} layerAttrs - Layer attributes. 236 * @property {Boolean} storingCharacters - Is reading storing characters stream. 237 * @property {String} tmxFileName - TMX file name. 238 * @property {String} currentString - Current string stored from characters stream. 239 * @property {Number} mapWidth - Width of the map 240 * @property {Number} mapHeight - Height of the map 241 * @property {Number} tileWidth - Width of a tile 242 * @property {Number} tileHeight - Height of a tile 243 * 244 * @param {String} tmxFile fileName or content string 245 * @param {String} resourcePath If tmxFile is a file name ,it is not required.If tmxFile is content string ,it is must required. 246 * @example 247 * 1. 248 * //create a TMXMapInfo with file name 249 * var tmxMapInfo = new cc.TMXMapInfo("res/orthogonal-test1.tmx"); 250 * 2. 251 * //create a TMXMapInfo with content string and resource path 252 * var resources = "res/TileMaps"; 253 * var filePath = "res/TileMaps/orthogonal-test1.tmx"; 254 * var xmlStr = cc.loader.getRes(filePath); 255 * var tmxMapInfo = new cc.TMXMapInfo(xmlStr, resources); 256 */ 257 cc.TMXMapInfo = cc.SAXParser.extend(/** @lends cc.TMXMapInfo# */{ 258 properties:null, 259 orientation:null, 260 parentElement:null, 261 parentGID:null, 262 layerAttrs:0, 263 storingCharacters:false, 264 tmxFileName:null, 265 currentString:null, 266 267 _objectGroups:null, 268 _mapSize:null, 269 _tileSize:null, 270 _layers:null, 271 _tilesets:null, 272 // tile properties 273 _tileProperties:null, 274 _resources:"", 275 _currentFirstGID:0, 276 277 /** 278 * Creates a TMX Format with a tmx file or content string <br/> 279 * Constructor of cc.TMXMapInfo 280 * @param {String} tmxFile fileName or content string 281 * @param {String} resourcePath If tmxFile is a file name ,it is not required.If tmxFile is content string ,it is must required. 282 */ 283 ctor:function (tmxFile, resourcePath) { 284 cc.SAXParser.prototype.ctor.apply(this); 285 this._mapSize = cc.size(0, 0); 286 this._tileSize = cc.size(0, 0); 287 this._layers = []; 288 this._tilesets = []; 289 this._objectGroups = []; 290 this.properties = []; 291 this._tileProperties = {}; 292 293 this._currentFirstGID = 0; 294 295 if (resourcePath !== undefined) { 296 this.initWithXML(tmxFile,resourcePath); 297 } else if(tmxFile !== undefined){ 298 this.initWithTMXFile(tmxFile); 299 } 300 }, 301 /** 302 * Gets Map orientation. 303 * @return {Number} 304 */ 305 getOrientation:function () { 306 return this.orientation; 307 }, 308 309 /** 310 * Set the Map orientation. 311 * @param {Number} value 312 */ 313 setOrientation:function (value) { 314 this.orientation = value; 315 }, 316 317 /** 318 * Map width & height 319 * @return {cc.Size} 320 */ 321 getMapSize:function () { 322 return cc.size(this._mapSize.width,this._mapSize.height); 323 }, 324 325 /** 326 * Map width & height 327 * @param {cc.Size} value 328 */ 329 setMapSize:function (value) { 330 this._mapSize.width = value.width; 331 this._mapSize.height = value.height; 332 }, 333 334 _getMapWidth: function () { 335 return this._mapSize.width; 336 }, 337 _setMapWidth: function (width) { 338 this._mapSize.width = width; 339 }, 340 _getMapHeight: function () { 341 return this._mapSize.height; 342 }, 343 _setMapHeight: function (height) { 344 this._mapSize.height = height; 345 }, 346 347 /** 348 * Tiles width & height 349 * @return {cc.Size} 350 */ 351 getTileSize:function () { 352 return cc.size(this._tileSize.width, this._tileSize.height); 353 }, 354 355 /** 356 * Tiles width & height 357 * @param {cc.Size} value 358 */ 359 setTileSize:function (value) { 360 this._tileSize.width = value.width; 361 this._tileSize.height = value.height; 362 }, 363 364 _getTileWidth: function () { 365 return this._tileSize.width; 366 }, 367 _setTileWidth: function (width) { 368 this._tileSize.width = width; 369 }, 370 _getTileHeight: function () { 371 return this._tileSize.height; 372 }, 373 _setTileHeight: function (height) { 374 this._tileSize.height = height; 375 }, 376 377 /** 378 * Layers 379 * @return {Array} 380 */ 381 getLayers:function () { 382 return this._layers; 383 }, 384 385 /** 386 * Layers 387 * @param {cc.TMXLayerInfo} value 388 */ 389 setLayers:function (value) { 390 this._layers.push(value); 391 }, 392 393 /** 394 * tilesets 395 * @return {Array} 396 */ 397 getTilesets:function () { 398 return this._tilesets; 399 }, 400 401 /** 402 * tilesets 403 * @param {cc.TMXTilesetInfo} value 404 */ 405 setTilesets:function (value) { 406 this._tilesets.push(value); 407 }, 408 409 /** 410 * ObjectGroups 411 * @return {Array} 412 */ 413 getObjectGroups:function () { 414 return this._objectGroups; 415 }, 416 417 /** 418 * ObjectGroups 419 * @param {cc.TMXObjectGroup} value 420 */ 421 setObjectGroups:function (value) { 422 this._objectGroups.push(value); 423 }, 424 425 /** 426 * parent element 427 * @return {Object} 428 */ 429 getParentElement:function () { 430 return this.parentElement; 431 }, 432 433 /** 434 * parent element 435 * @param {Object} value 436 */ 437 setParentElement:function (value) { 438 this.parentElement = value; 439 }, 440 441 /** 442 * parent GID 443 * @return {Number} 444 */ 445 getParentGID:function () { 446 return this.parentGID; 447 }, 448 449 /** 450 * parent GID 451 * @param {Number} value 452 */ 453 setParentGID:function (value) { 454 this.parentGID = value; 455 }, 456 457 /** 458 * Layer attribute 459 * @return {Object} 460 */ 461 getLayerAttribs:function () { 462 return this.layerAttrs; 463 }, 464 465 /** 466 * Layer attribute 467 * @param {Object} value 468 */ 469 setLayerAttribs:function (value) { 470 this.layerAttrs = value; 471 }, 472 473 /** 474 * Is reading storing characters stream 475 * @return {Boolean} 476 */ 477 getStoringCharacters:function () { 478 return this.storingCharacters; 479 }, 480 481 /** 482 * Is reading storing characters stream 483 * @param {Boolean} value 484 */ 485 setStoringCharacters:function (value) { 486 this.storingCharacters = value; 487 }, 488 489 /** 490 * Properties 491 * @return {Array} 492 */ 493 getProperties:function () { 494 return this.properties; 495 }, 496 497 /** 498 * Properties 499 * @param {object} value 500 */ 501 setProperties:function (value) { 502 this.properties = value; 503 }, 504 505 /** 506 * Initializes a TMX format with a tmx file 507 * @param {String} tmxFile 508 * @return {Element} 509 */ 510 initWithTMXFile:function (tmxFile) { 511 this._internalInit(tmxFile, null); 512 return this.parseXMLFile(tmxFile); 513 }, 514 515 /** 516 * initializes a TMX format with an XML string and a TMX resource path 517 * @param {String} tmxString 518 * @param {String} resourcePath 519 * @return {Boolean} 520 */ 521 initWithXML:function (tmxString, resourcePath) { 522 this._internalInit(null, resourcePath); 523 return this.parseXMLString(tmxString); 524 }, 525 526 /** Initalises parsing of an XML file, either a tmx (Map) file or tsx (Tileset) file 527 * @param {String} tmxFile 528 * @param {boolean} [isXmlString=false] 529 * @return {Element} 530 */ 531 parseXMLFile:function (tmxFile, isXmlString) { 532 isXmlString = isXmlString || false; 533 var xmlStr = isXmlString ? tmxFile : cc.loader.getRes(tmxFile); 534 if(!xmlStr) throw new Error("Please load the resource first : " + tmxFile); 535 536 var mapXML = this._parseXML(xmlStr); 537 var i, j; 538 539 // PARSE <map> 540 var map = mapXML.documentElement; 541 542 var version = map.getAttribute('version'); 543 var orientationStr = map.getAttribute('orientation'); 544 545 if (map.nodeName === "map") { 546 if (version !== "1.0" && version !== null) 547 cc.log("cocos2d: TMXFormat: Unsupported TMX version:" + version); 548 549 if (orientationStr === "orthogonal") 550 this.orientation = cc.TMX_ORIENTATION_ORTHO; 551 else if (orientationStr === "isometric") 552 this.orientation = cc.TMX_ORIENTATION_ISO; 553 else if (orientationStr === "hexagonal") 554 this.orientation = cc.TMX_ORIENTATION_HEX; 555 else if (orientationStr !== null) 556 cc.log("cocos2d: TMXFomat: Unsupported orientation:" + orientationStr); 557 558 var mapSize = cc.size(0, 0); 559 mapSize.width = parseFloat(map.getAttribute('width')); 560 mapSize.height = parseFloat(map.getAttribute('height')); 561 this.setMapSize(mapSize); 562 563 mapSize = cc.size(0, 0); 564 mapSize.width = parseFloat(map.getAttribute('tilewidth')); 565 mapSize.height = parseFloat(map.getAttribute('tileheight')); 566 this.setTileSize(mapSize); 567 568 // The parent element is the map 569 var propertyArr = map.querySelectorAll("map > properties > property"); 570 if (propertyArr) { 571 var aPropertyDict = {}; 572 for (i = 0; i < propertyArr.length; i++) { 573 aPropertyDict[propertyArr[i].getAttribute('name')] = propertyArr[i].getAttribute('value'); 574 } 575 this.properties = aPropertyDict; 576 } 577 } 578 579 // PARSE <tileset> 580 var tilesets = map.getElementsByTagName('tileset'); 581 if (map.nodeName !== "map") { 582 tilesets = []; 583 tilesets.push(map); 584 } 585 586 for (i = 0; i < tilesets.length; i++) { 587 var selTileset = tilesets[i]; 588 // If this is an external tileset then start parsing that 589 var tsxName = selTileset.getAttribute('source'); 590 if (tsxName) { 591 //this._currentFirstGID = parseInt(selTileset.getAttribute('firstgid')); 592 var tsxPath = isXmlString ? cc.path.join(this._resources, tsxName) : cc.path.changeBasename(tmxFile, tsxName); 593 this.parseXMLFile(tsxPath); 594 } else { 595 var tileset = new cc.TMXTilesetInfo(); 596 tileset.name = selTileset.getAttribute('name') || ""; 597 //TODO need fix 598 //if(this._currentFirstGID === 0){ 599 tileset.firstGid = parseInt(selTileset.getAttribute('firstgid')) || 0; 600 //}else{ 601 // tileset.firstGid = this._currentFirstGID; 602 // this._currentFirstGID = 0; 603 //} 604 605 tileset.spacing = parseInt(selTileset.getAttribute('spacing')) || 0; 606 tileset.margin = parseInt(selTileset.getAttribute('margin')) || 0; 607 608 var tilesetSize = cc.size(0, 0); 609 tilesetSize.width = parseFloat(selTileset.getAttribute('tilewidth')); 610 tilesetSize.height = parseFloat(selTileset.getAttribute('tileheight')); 611 tileset._tileSize = tilesetSize; 612 613 var image = selTileset.getElementsByTagName('image')[0]; 614 var imagename = image.getAttribute('source'); 615 var num = -1; 616 if(this.tmxFileName) 617 num = this.tmxFileName.lastIndexOf("/"); 618 if (num !== -1) { 619 var dir = this.tmxFileName.substr(0, num + 1); 620 tileset.sourceImage = dir + imagename; 621 } else { 622 tileset.sourceImage = this._resources + (this._resources ? "/" : "") + imagename; 623 } 624 this.setTilesets(tileset); 625 626 // PARSE <tile> 627 var tiles = selTileset.getElementsByTagName('tile'); 628 if (tiles) { 629 for (var tIdx = 0; tIdx < tiles.length; tIdx++) { 630 var t = tiles[tIdx]; 631 this.parentGID = parseInt(tileset.firstGid) + parseInt(t.getAttribute('id') || 0); 632 var tp = t.querySelectorAll("properties > property"); 633 if (tp) { 634 var dict = {}; 635 for (j = 0; j < tp.length; j++) { 636 var name = tp[j].getAttribute('name'); 637 dict[name] = tp[j].getAttribute('value'); 638 } 639 this._tileProperties[this.parentGID] = dict; 640 } 641 } 642 } 643 } 644 } 645 646 // PARSE <layer> 647 var layers = map.getElementsByTagName('layer'); 648 if (layers) { 649 for (i = 0; i < layers.length; i++) { 650 var selLayer = layers[i]; 651 var data = selLayer.getElementsByTagName('data')[0]; 652 653 var layer = new cc.TMXLayerInfo(); 654 layer.name = selLayer.getAttribute('name'); 655 656 var layerSize = cc.size(0, 0); 657 layerSize.width = parseFloat(selLayer.getAttribute('width')); 658 layerSize.height = parseFloat(selLayer.getAttribute('height')); 659 layer._layerSize = layerSize; 660 661 var visible = selLayer.getAttribute('visible'); 662 layer.visible = !(visible == "0"); 663 664 var opacity = selLayer.getAttribute('opacity') || 1; 665 666 if (opacity) 667 layer._opacity = parseInt(255 * parseFloat(opacity)); 668 else 669 layer._opacity = 255; 670 layer.offset = cc.p(parseFloat(selLayer.getAttribute('x')) || 0, parseFloat(selLayer.getAttribute('y')) || 0); 671 672 var nodeValue = ''; 673 for (j = 0; j < data.childNodes.length; j++) { 674 nodeValue += data.childNodes[j].nodeValue 675 } 676 nodeValue = nodeValue.trim(); 677 678 // Unpack the tilemap data 679 var compression = data.getAttribute('compression'); 680 var encoding = data.getAttribute('encoding'); 681 if(compression && compression !== "gzip" && compression !== "zlib"){ 682 cc.log("cc.TMXMapInfo.parseXMLFile(): unsupported compression method"); 683 return null; 684 } 685 var tiles; 686 switch (compression) { 687 case 'gzip': 688 tiles = cc.unzipBase64AsArray(nodeValue, 4); 689 break; 690 case 'zlib': 691 var inflator = new Zlib.Inflate(cc.Codec.Base64.decodeAsArray(nodeValue, 1)); 692 tiles = cc.uint8ArrayToUint32Array(inflator.decompress()); 693 break; 694 case null: 695 case '': 696 // Uncompressed 697 if (encoding === "base64") 698 tiles = cc.Codec.Base64.decodeAsArray(nodeValue, 4); 699 else if (encoding === "csv") { 700 tiles = []; 701 var csvTiles = nodeValue.split(','); 702 for (var csvIdx = 0; csvIdx < csvTiles.length; csvIdx++) 703 tiles.push(parseInt(csvTiles[csvIdx])); 704 } else { 705 //XML format 706 var selDataTiles = data.getElementsByTagName("tile"); 707 tiles = []; 708 for (var xmlIdx = 0; xmlIdx < selDataTiles.length; xmlIdx++) 709 tiles.push(parseInt(selDataTiles[xmlIdx].getAttribute("gid"))); 710 } 711 break; 712 default: 713 if(this.layerAttrs === cc.TMXLayerInfo.ATTRIB_NONE) 714 cc.log("cc.TMXMapInfo.parseXMLFile(): Only base64 and/or gzip/zlib maps are supported"); 715 break; 716 } 717 if (tiles) { 718 layer._tiles = new Uint32Array(tiles); 719 } 720 721 // The parent element is the last layer 722 var layerProps = selLayer.querySelectorAll("properties > property"); 723 if (layerProps) { 724 var layerProp = {}; 725 for (j = 0; j < layerProps.length; j++) { 726 layerProp[layerProps[j].getAttribute('name')] = layerProps[j].getAttribute('value'); 727 } 728 layer.properties = layerProp; 729 } 730 this.setLayers(layer); 731 } 732 } 733 734 // PARSE <objectgroup> 735 var objectGroups = map.getElementsByTagName('objectgroup'); 736 if (objectGroups) { 737 for (i = 0; i < objectGroups.length; i++) { 738 var selGroup = objectGroups[i]; 739 var objectGroup = new cc.TMXObjectGroup(); 740 objectGroup.groupName = selGroup.getAttribute('name'); 741 objectGroup.setPositionOffset(cc.p(parseFloat(selGroup.getAttribute('x')) * this.getTileSize().width || 0, 742 parseFloat(selGroup.getAttribute('y')) * this.getTileSize().height || 0)); 743 744 var groupProps = selGroup.querySelectorAll("objectgroup > properties > property"); 745 if (groupProps) { 746 for (j = 0; j < groupProps.length; j++) { 747 var groupProp = {}; 748 groupProp[groupProps[j].getAttribute('name')] = groupProps[j].getAttribute('value'); 749 // Add the property to the layer 750 objectGroup.properties = groupProp; 751 } 752 } 753 754 var objects = selGroup.querySelectorAll('object'); 755 var getContentScaleFactor = cc.director.getContentScaleFactor(); 756 if (objects) { 757 for (j = 0; j < objects.length; j++) { 758 var selObj = objects[j]; 759 // The value for "type" was blank or not a valid class name 760 // Create an instance of TMXObjectInfo to store the object and its properties 761 var objectProp = {}; 762 763 // Set the name of the object to the value for "name" 764 objectProp["name"] = selObj.getAttribute('name') || ""; 765 766 // Assign all the attributes as key/name pairs in the properties dictionary 767 objectProp["type"] = selObj.getAttribute('type') || ""; 768 769 objectProp["width"] = parseInt(selObj.getAttribute('width')) || 0; 770 objectProp["height"] = parseInt(selObj.getAttribute('height')) || 0; 771 772 objectProp["x"] = (((selObj.getAttribute('x') || 0) | 0) + objectGroup.getPositionOffset().x) / getContentScaleFactor; 773 var y = ((selObj.getAttribute('y') || 0) | 0) + objectGroup.getPositionOffset().y / getContentScaleFactor; 774 // Correct y position. (Tiled uses Flipped, cocos2d uses Standard) 775 objectProp["y"] = (parseInt(this.getMapSize().height * this.getTileSize().height) - y - objectProp["height"]) / cc.director.getContentScaleFactor(); 776 777 objectProp["rotation"] = parseInt(selObj.getAttribute('rotation')) || 0; 778 779 var docObjProps = selObj.querySelectorAll("properties > property"); 780 if (docObjProps) { 781 for (var k = 0; k < docObjProps.length; k++) 782 objectProp[docObjProps[k].getAttribute('name')] = docObjProps[k].getAttribute('value'); 783 } 784 785 //polygon 786 var polygonProps = selObj.querySelectorAll("polygon"); 787 if(polygonProps && polygonProps.length > 0) { 788 var selPgPointStr = polygonProps[0].getAttribute('points'); 789 if(selPgPointStr) 790 objectProp["points"] = this._parsePointsString(selPgPointStr); 791 } 792 793 //polyline 794 var polylineProps = selObj.querySelectorAll("polyline"); 795 if(polylineProps && polylineProps.length > 0) { 796 var selPlPointStr = polylineProps[0].getAttribute('points'); 797 if(selPlPointStr) 798 objectProp["polylinePoints"] = this._parsePointsString(selPlPointStr); 799 } 800 801 // Add the object to the objectGroup 802 objectGroup.setObjects(objectProp); 803 } 804 } 805 806 this.setObjectGroups(objectGroup); 807 } 808 } 809 return map; 810 }, 811 812 _parsePointsString:function(pointsString){ 813 if(!pointsString) 814 return null; 815 816 var points = []; 817 var pointsStr = pointsString.split(' '); 818 for(var i = 0; i < pointsStr.length; i++){ 819 var selPointStr = pointsStr[i].split(','); 820 points.push({'x':selPointStr[0], 'y':selPointStr[1]}); 821 } 822 return points; 823 }, 824 825 /** 826 * initializes parsing of an XML string, either a tmx (Map) string or tsx (Tileset) string 827 * @param {String} xmlString 828 * @return {Boolean} 829 */ 830 parseXMLString:function (xmlString) { 831 return this.parseXMLFile(xmlString, true); 832 }, 833 834 /** 835 * Gets the tile properties. 836 * @return {object} 837 */ 838 getTileProperties:function () { 839 return this._tileProperties; 840 }, 841 842 /** 843 * Set the tile properties. 844 * @param {object} tileProperties 845 */ 846 setTileProperties:function (tileProperties) { 847 this._tileProperties.push(tileProperties); 848 }, 849 850 /** 851 * Gets the currentString 852 * @return {String} 853 */ 854 getCurrentString:function () { 855 return this.currentString; 856 }, 857 858 /** 859 * Set the currentString 860 * @param {String} currentString 861 */ 862 setCurrentString:function (currentString) { 863 this.currentString = currentString; 864 }, 865 866 /** 867 * Gets the tmxFileName 868 * @return {String} 869 */ 870 getTMXFileName:function () { 871 return this.tmxFileName; 872 }, 873 874 /** 875 * Set the tmxFileName 876 * @param {String} fileName 877 */ 878 setTMXFileName:function (fileName) { 879 this.tmxFileName = fileName; 880 }, 881 882 _internalInit:function (tmxFileName, resourcePath) { 883 this._tilesets.length = 0; 884 this._layers.length = 0; 885 886 this.tmxFileName = tmxFileName; 887 if (resourcePath) 888 this._resources = resourcePath; 889 890 this._objectGroups.length = 0; 891 this.properties.length = 0; 892 this._tileProperties.length = 0; 893 894 // tmp vars 895 this.currentString = ""; 896 this.storingCharacters = false; 897 this.layerAttrs = cc.TMXLayerInfo.ATTRIB_NONE; 898 this.parentElement = cc.TMX_PROPERTY_NONE; 899 this._currentFirstGID = 0; 900 } 901 }); 902 903 var _p = cc.TMXMapInfo.prototype; 904 905 // Extended properties 906 /** @expose */ 907 _p.mapWidth; 908 cc.defineGetterSetter(_p, "mapWidth", _p._getMapWidth, _p._setMapWidth); 909 /** @expose */ 910 _p.mapHeight; 911 cc.defineGetterSetter(_p, "mapHeight", _p._getMapHeight, _p._setMapHeight); 912 /** @expose */ 913 _p.tileWidth; 914 cc.defineGetterSetter(_p, "tileWidth", _p._getTileWidth, _p._setTileWidth); 915 /** @expose */ 916 _p.tileHeight; 917 cc.defineGetterSetter(_p, "tileHeight", _p._getTileHeight, _p._setTileHeight); 918 919 920 /** 921 * Creates a TMX Format with a tmx file or content string 922 * @deprecated since v3.0 please use new cc.TMXMapInfo(tmxFile, resourcePath) instead. 923 * @param {String} tmxFile fileName or content string 924 * @param {String} resourcePath If tmxFile is a file name ,it is not required.If tmxFile is content string ,it is must required. 925 * @return {cc.TMXMapInfo} 926 */ 927 cc.TMXMapInfo.create = function (tmxFile, resourcePath) { 928 return new cc.TMXMapInfo(tmxFile, resourcePath); 929 }; 930 931 932 cc.loader.register(["tmx", "tsx"], cc._txtLoader); 933 934 935 /** 936 * @constant 937 * @type Number 938 */ 939 cc.TMXLayerInfo.ATTRIB_NONE = 1 << 0; 940 /** 941 * @constant 942 * @type Number 943 */ 944 cc.TMXLayerInfo.ATTRIB_BASE64 = 1 << 1; 945 /** 946 * @constant 947 * @type Number 948 */ 949 cc.TMXLayerInfo.ATTRIB_GZIP = 1 << 2; 950 /** 951 * @constant 952 * @type Number 953 */ 954 cc.TMXLayerInfo.ATTRIB_ZLIB = 1 << 3; 955