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 Orthogonal orientation 29 * @constant 30 * @type Number 31 */ 32 cc.TMX_ORIENTATION_ORTHO = 0; 33 34 /** 35 * Hexagonal orientation 36 * @constant 37 * @type Number 38 */ 39 40 cc.TMX_ORIENTATION_HEX = 1; 41 42 /** 43 * Isometric orientation 44 * @constant 45 * @type Number 46 */ 47 cc.TMX_ORIENTATION_ISO = 2; 48 49 /** 50 * <p>cc.TMXTiledMap knows how to parse and render a TMX map.</p> 51 * 52 * <p>It adds support for the TMX tiled map format used by http://www.mapeditor.org <br /> 53 * It supports isometric, hexagonal and orthogonal tiles.<br /> 54 * It also supports object groups, objects, and properties.</p> 55 * 56 * <p>Features: <br /> 57 * - Each tile will be treated as an cc.Sprite<br /> 58 * - The sprites are created on demand. They will be created only when you call "layer.getTileAt(position)" <br /> 59 * - Each tile can be rotated / moved / scaled / tinted / "opacitied", since each tile is a cc.Sprite<br /> 60 * - Tiles can be added/removed in runtime<br /> 61 * - The z-order of the tiles can be modified in runtime<br /> 62 * - Each tile has an anchorPoint of (0,0) <br /> 63 * - The anchorPoint of the TMXTileMap is (0,0) <br /> 64 * - The TMX layers will be added as a child <br /> 65 * - The TMX layers will be aliased by default <br /> 66 * - The tileset image will be loaded using the cc.TextureCache <br /> 67 * - Each tile will have a unique tag<br /> 68 * - Each tile will have a unique z value. top-left: z=1, bottom-right: z=max z<br /> 69 * - Each object group will be treated as an cc.MutableArray <br /> 70 * - Object class which will contain all the properties in a dictionary<br /> 71 * - Properties can be assigned to the Map, Layer, Object Group, and Object</p> 72 * 73 * <p>Limitations: <br /> 74 * - It only supports one tileset per layer. <br /> 75 * - Embedded images are not supported <br /> 76 * - It only supports the XML format (the JSON format is not supported)</p> 77 * 78 * <p>Technical description: <br /> 79 * Each layer is created using an cc.TMXLayer (subclass of cc.SpriteBatchNode). If you have 5 layers, then 5 cc.TMXLayer will be created, <br /> 80 * unless the layer visibility is off. In that case, the layer won't be created at all. <br /> 81 * You can obtain the layers (cc.TMXLayer objects) at runtime by: <br /> 82 * - map.getChildByTag(tag_number); // 0=1st layer, 1=2nd layer, 2=3rd layer, etc...<br /> 83 * - map.getLayer(name_of_the_layer); </p> 84 * 85 * <p>Each object group is created using a cc.TMXObjectGroup which is a subclass of cc.MutableArray.<br /> 86 * You can obtain the object groups at runtime by: <br /> 87 * - map.getObjectGroup(name_of_the_object_group); </p> 88 * 89 * <p>Each object is a cc.TMXObject.</p> 90 * 91 * <p>Each property is stored as a key-value pair in an cc.MutableDictionary.<br /> 92 * You can obtain the properties at runtime by: </p> 93 * 94 * <p>map.getProperty(name_of_the_property); <br /> 95 * layer.getProperty(name_of_the_property); <br /> 96 * objectGroup.getProperty(name_of_the_property); <br /> 97 * object.getProperty(name_of_the_property);</p> 98 * @class 99 * @extends cc.Node 100 * @param {String} tmxFile tmxFile fileName or content string 101 * @param {String} resourcePath If tmxFile is a file name ,it is not required.If tmxFile is content string ,it is must required. 102 103 * 104 * @property {Array} properties - Properties from the map. They can be added using tilemap editors 105 * @property {Number} mapOrientation - Map orientation 106 * @property {Array} objectGroups - Object groups of the map 107 * @property {Number} mapWidth - Width of the map 108 * @property {Number} mapHeight - Height of the map 109 * @property {Number} tileWidth - Width of a tile 110 * @property {Number} tileHeight - Height of a tile 111 * 112 * @example 113 * //example 114 * 1. 115 * //create a TMXTiledMap with file name 116 * var tmxTiledMap = new cc.TMXTiledMap("res/orthogonal-test1.tmx"); 117 * 2. 118 * //create a TMXTiledMap with content string and resource path 119 * var resources = "res/TileMaps"; 120 * var filePath = "res/TileMaps/orthogonal-test1.tmx"; 121 * var xmlStr = cc.loader.getRes(filePath); 122 * var tmxTiledMap = new cc.TMXTiledMap(xmlStr, resources); 123 */ 124 cc.TMXTiledMap = cc.Node.extend(/** @lends cc.TMXTiledMap# */{ 125 properties: null, 126 mapOrientation: null, 127 objectGroups: null, 128 129 //the map's size property measured in tiles 130 _mapSize: null, 131 _tileSize: null, 132 //tile properties 133 _tileProperties: null, 134 _className: "TMXTiledMap", 135 136 /** 137 * Creates a TMX Tiled Map with a TMX file or content string. <br/> 138 * Constructor of cc.TMXTiledMap 139 * @param {String} tmxFile tmxFile fileName or content string 140 * @param {String} resourcePath If tmxFile is a file name ,it is not required.If tmxFile is content string ,it is must required. 141 */ 142 ctor:function(tmxFile,resourcePath){ 143 cc.Node.prototype.ctor.call(this); 144 this._mapSize = cc.size(0, 0); 145 this._tileSize = cc.size(0, 0); 146 147 if(resourcePath !== undefined){ 148 this.initWithXML(tmxFile,resourcePath); 149 }else if(tmxFile !== undefined){ 150 this.initWithTMXFile(tmxFile); 151 } 152 }, 153 154 /** 155 * Gets the map size. 156 * @return {cc.Size} 157 */ 158 getMapSize:function () { 159 return cc.size(this._mapSize.width, this._mapSize.height); 160 }, 161 162 /** 163 * Set the map size. 164 * @param {cc.Size} Var 165 */ 166 setMapSize:function (Var) { 167 this._mapSize.width = Var.width; 168 this._mapSize.height = Var.height; 169 }, 170 171 _getMapWidth: function () { 172 return this._mapSize.width; 173 }, 174 _setMapWidth: function (width) { 175 this._mapSize.width = width; 176 }, 177 _getMapHeight: function () { 178 return this._mapSize.height; 179 }, 180 _setMapHeight: function (height) { 181 this._mapSize.height = height; 182 }, 183 184 /** 185 * Gets the tile size. 186 * @return {cc.Size} 187 */ 188 getTileSize:function () { 189 return cc.size(this._tileSize.width, this._tileSize.height); 190 }, 191 192 /** 193 * Set the tile size 194 * @param {cc.Size} Var 195 */ 196 setTileSize:function (Var) { 197 this._tileSize.width = Var.width; 198 this._tileSize.height = Var.height; 199 }, 200 201 _getTileWidth: function () { 202 return this._tileSize.width; 203 }, 204 _setTileWidth: function (width) { 205 this._tileSize.width = width; 206 }, 207 _getTileHeight: function () { 208 return this._tileSize.height; 209 }, 210 _setTileHeight: function (height) { 211 this._tileSize.height = height; 212 }, 213 214 /** 215 * map orientation 216 * @return {Number} 217 */ 218 getMapOrientation:function () { 219 return this.mapOrientation; 220 }, 221 222 /** 223 * map orientation 224 * @param {Number} Var 225 */ 226 setMapOrientation:function (Var) { 227 this.mapOrientation = Var; 228 }, 229 230 /** 231 * object groups 232 * @return {Array} 233 */ 234 getObjectGroups:function () { 235 return this.objectGroups; 236 }, 237 238 /** 239 * object groups 240 * @param {Array} Var 241 */ 242 setObjectGroups:function (Var) { 243 this.objectGroups = Var; 244 }, 245 246 /** 247 * Gets the properties 248 * @return {object} 249 */ 250 getProperties:function () { 251 return this.properties; 252 }, 253 254 /** 255 * Set the properties 256 * @param {object} Var 257 */ 258 setProperties:function (Var) { 259 this.properties = Var; 260 }, 261 262 /** 263 * Initializes the instance of cc.TMXTiledMap with tmxFile 264 * @param {String} tmxFile 265 * @return {Boolean} Whether the initialization was successful. 266 * @example 267 * //example 268 * var map = new cc.TMXTiledMap() 269 * map.initWithTMXFile("hello.tmx"); 270 */ 271 initWithTMXFile:function (tmxFile) { 272 if(!tmxFile || tmxFile.length === 0) 273 throw new Error("cc.TMXTiledMap.initWithTMXFile(): tmxFile should be non-null or non-empty string."); 274 this.width = 0; 275 this.height = 0; 276 var mapInfo = new cc.TMXMapInfo(tmxFile); 277 if (!mapInfo) 278 return false; 279 280 var locTilesets = mapInfo.getTilesets(); 281 if(!locTilesets || locTilesets.length === 0) 282 cc.log("cc.TMXTiledMap.initWithTMXFile(): Map not found. Please check the filename."); 283 this._buildWithMapInfo(mapInfo); 284 return true; 285 }, 286 287 /** 288 * Initializes the instance of cc.TMXTiledMap with tmxString 289 * @param {String} tmxString 290 * @param {String} resourcePath 291 * @return {Boolean} Whether the initialization was successful. 292 */ 293 initWithXML:function(tmxString, resourcePath){ 294 this.width = 0; 295 this.height = 0; 296 297 var mapInfo = new cc.TMXMapInfo(tmxString, resourcePath); 298 var locTilesets = mapInfo.getTilesets(); 299 if(!locTilesets || locTilesets.length === 0) 300 cc.log("cc.TMXTiledMap.initWithXML(): Map not found. Please check the filename."); 301 this._buildWithMapInfo(mapInfo); 302 return true; 303 }, 304 305 _buildWithMapInfo:function (mapInfo) { 306 this._mapSize = mapInfo.getMapSize(); 307 this._tileSize = mapInfo.getTileSize(); 308 this.mapOrientation = mapInfo.orientation; 309 this.objectGroups = mapInfo.getObjectGroups(); 310 this.properties = mapInfo.properties; 311 this._tileProperties = mapInfo.getTileProperties(); 312 313 var idx = 0; 314 var layers = mapInfo.getLayers(); 315 if (layers) { 316 var layerInfo = null; 317 for (var i = 0, len = layers.length; i < len; i++) { 318 layerInfo = layers[i]; 319 if (layerInfo && layerInfo.visible) { 320 var child = this._parseLayer(layerInfo, mapInfo); 321 this.addChild(child, idx, idx); 322 // update content size with the max size 323 this.width = Math.max(this.width, child.width); 324 this.height = Math.max(this.height, child.height); 325 idx++; 326 } 327 } 328 } 329 }, 330 331 /** 332 * Return All layers array. 333 * @returns {Array} 334 */ 335 allLayers: function () { 336 var retArr = [], locChildren = this._children; 337 for(var i = 0, len = locChildren.length;i< len;i++){ 338 var layer = locChildren[i]; 339 if(layer && layer instanceof cc.TMXLayer) 340 retArr.push(layer); 341 } 342 return retArr; 343 }, 344 345 /** 346 * return the TMXLayer for the specific layer 347 * @param {String} layerName 348 * @return {cc.TMXLayer} 349 */ 350 getLayer:function (layerName) { 351 if(!layerName || layerName.length === 0) 352 throw new Error("cc.TMXTiledMap.getLayer(): layerName should be non-null or non-empty string."); 353 var locChildren = this._children; 354 for (var i = 0; i < locChildren.length; i++) { 355 var layer = locChildren[i]; 356 if (layer && layer.layerName === layerName) 357 return layer; 358 } 359 // layer not found 360 return null; 361 }, 362 363 /** 364 * Return the TMXObjectGroup for the specific group 365 * @param {String} groupName 366 * @return {cc.TMXObjectGroup} 367 */ 368 getObjectGroup:function (groupName) { 369 if(!groupName || groupName.length === 0) 370 throw new Error("cc.TMXTiledMap.getObjectGroup(): groupName should be non-null or non-empty string."); 371 if (this.objectGroups) { 372 for (var i = 0; i < this.objectGroups.length; i++) { 373 var objectGroup = this.objectGroups[i]; 374 if (objectGroup && objectGroup.groupName === groupName) { 375 return objectGroup; 376 } 377 } 378 } 379 // objectGroup not found 380 return null; 381 }, 382 383 /** 384 * Return the value for the specific property name 385 * @param {String} propertyName 386 * @return {String} 387 */ 388 getProperty:function (propertyName) { 389 return this.properties[propertyName.toString()]; 390 }, 391 392 /** 393 * Return properties dictionary for tile GID 394 * @param {Number} GID 395 * @return {object} 396 * @deprecated 397 */ 398 propertiesForGID:function (GID) { 399 cc.log("propertiesForGID is deprecated. Please use getPropertiesForGID instead."); 400 return this.getPropertiesForGID[GID]; 401 }, 402 403 /** 404 * Return properties dictionary for tile GID 405 * @param {Number} GID 406 * @return {object} 407 */ 408 getPropertiesForGID: function(GID) { 409 return this._tileProperties[GID]; 410 }, 411 412 _parseLayer:function (layerInfo, mapInfo) { 413 var tileset = this._tilesetForLayer(layerInfo, mapInfo); 414 var layer = new cc.TMXLayer(tileset, layerInfo, mapInfo); 415 // tell the layerinfo to release the ownership of the tiles map. 416 layerInfo.ownTiles = false; 417 return layer; 418 }, 419 420 _tilesetForLayer:function (layerInfo, mapInfo) { 421 var size = layerInfo._layerSize; 422 var tilesets = mapInfo.getTilesets(); 423 if (tilesets) { 424 for (var i = tilesets.length - 1; i >= 0; i--) { 425 var tileset = tilesets[i]; 426 if (tileset) { 427 for (var y = 0; y < size.height; y++) { 428 for (var x = 0; x < size.width; x++) { 429 var pos = x + size.width * y; 430 var gid = layerInfo._tiles[pos]; 431 if (gid !== 0) { 432 // Optimization: quick return 433 // if the layer is invalid (more than 1 tileset per layer) an cc.assert will be thrown later 434 if (((gid & cc.TMX_TILE_FLIPPED_MASK)>>>0) >= tileset.firstGid) { 435 return tileset; 436 } 437 } 438 439 } 440 } 441 } 442 } 443 } 444 445 // If all the tiles are 0, return empty tileset 446 cc.log("cocos2d: Warning: TMX Layer " + layerInfo.name + " has no tiles"); 447 return null; 448 } 449 }); 450 451 var _p = cc.TMXTiledMap.prototype; 452 453 // Extended properties 454 /** @expose */ 455 _p.mapWidth; 456 cc.defineGetterSetter(_p, "mapWidth", _p._getMapWidth, _p._setMapWidth); 457 /** @expose */ 458 _p.mapHeight; 459 cc.defineGetterSetter(_p, "mapHeight", _p._getMapHeight, _p._setMapHeight); 460 /** @expose */ 461 _p.tileWidth; 462 cc.defineGetterSetter(_p, "tileWidth", _p._getTileWidth, _p._setTileWidth); 463 /** @expose */ 464 _p.tileHeight; 465 cc.defineGetterSetter(_p, "tileHeight", _p._getTileHeight, _p._setTileHeight); 466 467 468 /** 469 * Creates a TMX Tiled Map with a TMX file or content string. 470 * Implementation cc.TMXTiledMap 471 * @deprecated since v3.0 please use new cc.TMXTiledMap(tmxFile,resourcePath) instead. 472 * @param {String} tmxFile tmxFile fileName or content string 473 * @param {String} resourcePath If tmxFile is a file name ,it is not required.If tmxFile is content string ,it is must required. 474 * @return {cc.TMXTiledMap|undefined} 475 */ 476 cc.TMXTiledMap.create = function (tmxFile,resourcePath) { 477 return new cc.TMXTiledMap(tmxFile,resourcePath); 478 }; 479