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 * - Embeded 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 * 101 * @property {Array} properties - Properties from the map. They can be added using tilemap editors 102 * @property {Number} mapOrientation - Map orientation 103 * @property {Array} objectGroups - Object groups of the map 104 * @property {Number} mapWidth - Width of the map 105 * @property {Number} mapHeight - Height of the map 106 * @property {Number} tileWidth - Width of a tile 107 * @property {Number} tileHeight - Height of a tile 108 */ 109 cc.TMXTiledMap = cc.NodeRGBA.extend(/** @lends cc.TMXTiledMap# */{ 110 properties: null, 111 mapOrientation: null, 112 objectGroups: null, 113 114 //the map's size property measured in tiles 115 _mapSize: null, 116 _tileSize: null, 117 //tile properties 118 _tileProperties: null, 119 _className: "TMXTiledMap", 120 121 /** 122 * Creates a TMX Tiled Map with a TMX file or content string. <br/> 123 * Constructor of cc.TMXTiledMap 124 * @param {String} tmxFile tmxFile fileName or content string 125 * @param {String} resourcePath If tmxFile is a file name ,it is not required.If tmxFile is content string ,it is must required. 126 * @example 127 * //example 128 * 1. 129 * //create a TMXTiledMap with file name 130 * var tmxTiledMap = new cc.TMXTiledMap("res/orthogonal-test1.tmx"); 131 * 2. 132 * //create a TMXTiledMap with content string and resource path 133 * var resources = "res/TileMaps"; 134 * var filePath = "res/TileMaps/orthogonal-test1.tmx"; 135 * var xmlStr = cc.loader.getRes(filePath); 136 * var tmxTiledMap = new cc.TMXTiledMap(xmlStr, resources); 137 */ 138 ctor:function(tmxFile,resourcePath){ 139 cc.Node.prototype.ctor.call(this); 140 this._mapSize = cc.size(0, 0); 141 this._tileSize = cc.size(0, 0); 142 143 if(resourcePath !== undefined){ 144 this.initWithXML(tmxFile,resourcePath); 145 }else if(tmxFile !== undefined){ 146 this.initWithTMXFile(tmxFile); 147 } 148 }, 149 150 /** 151 * @return {cc.Size} 152 */ 153 getMapSize:function () { 154 return cc.size(this._mapSize.width, this._mapSize.height); 155 }, 156 157 /** 158 * @param {cc.Size} Var 159 */ 160 setMapSize:function (Var) { 161 this._mapSize.width = Var.width; 162 this._mapSize.height = Var.height; 163 }, 164 165 _getMapWidth: function () { 166 return this._mapSize.width; 167 }, 168 _setMapWidth: function (width) { 169 this._mapSize.width = width; 170 }, 171 _getMapHeight: function () { 172 return this._mapSize.height; 173 }, 174 _setMapHeight: function (height) { 175 this._mapSize.height = height; 176 }, 177 178 /** 179 * @return {cc.Size} 180 */ 181 getTileSize:function () { 182 return cc.size(this._tileSize.width, this._tileSize.height); 183 }, 184 185 /** 186 * @param {cc.Size} Var 187 */ 188 setTileSize:function (Var) { 189 this._tileSize.width = Var.width; 190 this._tileSize.height = Var.height; 191 }, 192 193 _getTileWidth: function () { 194 return this._tileSize.width; 195 }, 196 _setTileWidth: function (width) { 197 this._tileSize.width = width; 198 }, 199 _getTileHeight: function () { 200 return this._tileSize.height; 201 }, 202 _setTileHeight: function (height) { 203 this._tileSize.height = height; 204 }, 205 206 /** 207 * map orientation 208 * @return {Number} 209 */ 210 getMapOrientation:function () { 211 return this.mapOrientation; 212 }, 213 214 /** 215 * @param {Number} Var 216 */ 217 setMapOrientation:function (Var) { 218 this.mapOrientation = Var; 219 }, 220 221 /** 222 * object groups 223 * @return {Array} 224 */ 225 getObjectGroups:function () { 226 return this.objectGroups; 227 }, 228 229 /** 230 * @param {Array} Var 231 */ 232 setObjectGroups:function (Var) { 233 this.objectGroups = Var; 234 }, 235 236 /** 237 * properties 238 * @return {object} 239 */ 240 getProperties:function () { 241 return this.properties; 242 }, 243 244 /** 245 * @param {object} Var 246 */ 247 setProperties:function (Var) { 248 this.properties = Var; 249 }, 250 251 /** 252 * @param {String} tmxFile 253 * @return {Boolean} 254 * @example 255 * //example 256 * var map = new cc.TMXTiledMap() 257 * map.initWithTMXFile("hello.tmx"); 258 */ 259 initWithTMXFile:function (tmxFile) { 260 if(!tmxFile || tmxFile.length == 0) 261 throw "cc.TMXTiledMap.initWithTMXFile(): tmxFile should be non-null or non-empty string."; 262 this.width = 0; 263 this.height = 0; 264 var mapInfo = cc.TMXMapInfo.create(tmxFile); 265 if (!mapInfo) 266 return false; 267 268 var locTilesets = mapInfo.getTilesets(); 269 if(!locTilesets || locTilesets.length === 0) 270 cc.log("cc.TMXTiledMap.initWithTMXFile(): Map not found. Please check the filename."); 271 this._buildWithMapInfo(mapInfo); 272 return true; 273 }, 274 275 initWithXML:function(tmxString, resourcePath){ 276 this.width = 0; 277 this.height = 0; 278 279 var mapInfo = cc.TMXMapInfo.create(tmxString, resourcePath); 280 var locTilesets = mapInfo.getTilesets(); 281 if(!locTilesets || locTilesets.length === 0) 282 cc.log("cc.TMXTiledMap.initWithXML(): Map not found. Please check the filename."); 283 this._buildWithMapInfo(mapInfo); 284 return true; 285 }, 286 287 _buildWithMapInfo:function (mapInfo) { 288 this._mapSize = mapInfo.getMapSize(); 289 this._tileSize = mapInfo.getTileSize(); 290 this.mapOrientation = mapInfo.orientation; 291 this.objectGroups = mapInfo.getObjectGroups(); 292 this.properties = mapInfo.properties; 293 this._tileProperties = mapInfo.getTileProperties(); 294 295 var idx = 0; 296 var layers = mapInfo.getLayers(); 297 if (layers) { 298 var layerInfo = null; 299 for (var i = 0, len = layers.length; i < len; i++) { 300 layerInfo = layers[i]; 301 if (layerInfo && layerInfo.visible) { 302 var child = this._parseLayer(layerInfo, mapInfo); 303 this.addChild(child, idx, idx); 304 // update content size with the max size 305 this.width = Math.max(this.width, child.width); 306 this.height = Math.max(this.height, child.height); 307 idx++; 308 } 309 } 310 } 311 }, 312 313 allLayers: function () { 314 var retArr = [], locChildren = this._children; 315 for(var i = 0, len = locChildren.length;i< len;i++){ 316 var layer = locChildren[i]; 317 if(layer && layer instanceof cc.TMXLayer) 318 retArr.push(layer); 319 } 320 return retArr; 321 }, 322 323 /** 324 * return the TMXLayer for the specific layer 325 * @param {String} layerName 326 * @return {cc.TMXLayer} 327 */ 328 getLayer:function (layerName) { 329 if(!layerName || layerName.length === 0) 330 throw "cc.TMXTiledMap.getLayer(): layerName should be non-null or non-empty string."; 331 var locChildren = this._children; 332 for (var i = 0; i < locChildren.length; i++) { 333 var layer = locChildren[i]; 334 if (layer && layer.layerName == layerName) 335 return layer; 336 } 337 // layer not found 338 return null; 339 }, 340 341 /** 342 * Return the TMXObjectGroup for the specific group 343 * @param {String} groupName 344 * @return {cc.TMXObjectGroup} 345 */ 346 getObjectGroup:function (groupName) { 347 if(!groupName || groupName.length === 0) 348 throw "cc.TMXTiledMap.getObjectGroup(): groupName should be non-null or non-empty string."; 349 if (this.objectGroups) { 350 for (var i = 0; i < this.objectGroups.length; i++) { 351 var objectGroup = this.objectGroups[i]; 352 if (objectGroup && objectGroup.groupName == groupName) { 353 return objectGroup; 354 } 355 } 356 } 357 // objectGroup not found 358 return null; 359 }, 360 361 /** 362 * Return the value for the specific property name 363 * @param {String} propertyName 364 * @return {String} 365 */ 366 getProperty:function (propertyName) { 367 return this.properties[propertyName.toString()]; 368 }, 369 370 /** 371 * Return properties dictionary for tile GID 372 * @param {Number} GID 373 * @return {object} 374 */ 375 propertiesForGID:function (GID) { 376 return this._tileProperties[GID]; 377 }, 378 379 _parseLayer:function (layerInfo, mapInfo) { 380 var tileset = this._tilesetForLayer(layerInfo, mapInfo); 381 var layer = cc.TMXLayer.create(tileset, layerInfo, mapInfo); 382 // tell the layerinfo to release the ownership of the tiles map. 383 layerInfo.ownTiles = false; 384 layer.setupTiles(); 385 return layer; 386 }, 387 388 _tilesetForLayer:function (layerInfo, mapInfo) { 389 var size = layerInfo._layerSize; 390 var tilesets = mapInfo.getTilesets(); 391 if (tilesets) { 392 for (var i = tilesets.length - 1; i >= 0; i--) { 393 var tileset = tilesets[i]; 394 if (tileset) { 395 for (var y = 0; y < size.height; y++) { 396 for (var x = 0; x < size.width; x++) { 397 var pos = x + size.width * y; 398 var gid = layerInfo._tiles[pos]; 399 if (gid != 0) { 400 // Optimization: quick return 401 // if the layer is invalid (more than 1 tileset per layer) an cc.assert will be thrown later 402 if (((gid & cc.TMX_TILE_FLIPPED_MASK)>>>0) >= tileset.firstGid) { 403 return tileset; 404 } 405 } 406 407 } 408 } 409 } 410 } 411 } 412 413 // If all the tiles are 0, return empty tileset 414 cc.log("cocos2d: Warning: TMX Layer " + layerInfo.name + " has no tiles"); 415 return null; 416 } 417 }); 418 419 var _p = cc.TMXTiledMap.prototype; 420 421 // Extended properties 422 /** @expose */ 423 _p.mapWidth; 424 cc.defineGetterSetter(_p, "mapWidth", _p._getMapWidth, _p._setMapWidth); 425 /** @expose */ 426 _p.mapHeight; 427 cc.defineGetterSetter(_p, "mapHeight", _p._getMapHeight, _p._setMapHeight); 428 /** @expose */ 429 _p.tileWidth; 430 cc.defineGetterSetter(_p, "tileWidth", _p._getTileWidth, _p._setTileWidth); 431 /** @expose */ 432 _p.tileHeight; 433 cc.defineGetterSetter(_p, "tileHeight", _p._getTileHeight, _p._setTileHeight); 434 435 436 /** 437 * Creates a TMX Tiled Map with a TMX file or content string. 438 * Implementation cc.TMXTiledMap 439 * @param {String} tmxFile tmxFile fileName or content string 440 * @param {String} resourcePath If tmxFile is a file name ,it is not required.If tmxFile is content string ,it is must required. 441 * @return {cc.TMXTiledMap|undefined} 442 * @example 443 * //example 444 * 1. 445 * //create a TMXTiledMap with file name 446 * var tmxTiledMap = cc.TMXTiledMap.create("res/orthogonal-test1.tmx"); 447 * 2. 448 * //create a TMXTiledMap with content string and resource path 449 * var resources = "res/TileMaps"; 450 * var filePath = "res/TileMaps/orthogonal-test1.tmx"; 451 * var xmlStr = cc.loader.getRes(filePath); 452 * var tmxTiledMap = cc.TMXTiledMap.create(xmlStr, resources); 453 */ 454 cc.TMXTiledMap.create = function (tmxFile,resourcePath) { 455 return new cc.TMXTiledMap(tmxFile,resourcePath); 456 }; 457