1 /**************************************************************************** 2 Copyright (c) 2010-2012 cocos2d-x.org 3 Copyright (c) 2008-2010 Ricardo Quesada 4 Copyright (c) 2011 Zynga 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 cc.TMXTiledMap = cc.NodeRGBA.extend(/** @lends cc.TMXTiledMap# */{ 102 //the map's size property measured in tiles 103 _mapSize:null, 104 _tileSize:null, 105 _properties:null, 106 _objectGroups:null, 107 _mapOrientation:null, 108 //tile properties 109 _tileProperties:null, 110 111 ctor:function(){ 112 cc.Node.prototype.ctor.call(this); 113 this._mapSize = cc.SizeZero(); 114 this._tileSize = cc.SizeZero(); 115 this._properties = null; 116 this._objectGroups = null; 117 this._mapOrientation = null; 118 119 this._tileProperties = null; 120 }, 121 122 /** 123 * @return {cc.Size} 124 */ 125 getMapSize:function () { 126 return cc.size(this._mapSize.width, this._mapSize.height); 127 }, 128 129 /** 130 * @param {cc.Size} Var 131 */ 132 setMapSize:function (Var) { 133 this._mapSize.width = Var.width; 134 this._mapSize.height = Var.height; 135 }, 136 137 /** 138 * @return {cc.Size} 139 */ 140 getTileSize:function () { 141 return cc.size(this._tileSize.width, this._tileSize.height); 142 }, 143 144 /** 145 * @param {cc.Size} Var 146 */ 147 setTileSize:function (Var) { 148 this._tileSize.width = Var.width; 149 this._tileSize.height = Var.height; 150 }, 151 152 /** 153 * map orientation 154 * @return {Number} 155 */ 156 getMapOrientation:function () { 157 return this._mapOrientation; 158 }, 159 160 /** 161 * @param {Number} Var 162 */ 163 setMapOrientation:function (Var) { 164 this._mapOrientation = Var; 165 }, 166 167 /** 168 * object groups 169 * @return {Array} 170 */ 171 getObjectGroups:function () { 172 return this._objectGroups; 173 }, 174 175 /** 176 * @param {Array} Var 177 */ 178 setObjectGroups:function (Var) { 179 this._objectGroups = Var; 180 }, 181 182 /** 183 * properties 184 * @return {object} 185 */ 186 getProperties:function () { 187 return this._properties; 188 }, 189 190 /** 191 * @param {object} Var 192 */ 193 setProperties:function (Var) { 194 this._properties = Var; 195 }, 196 197 /** 198 * @param {String} tmxFile 199 * @param {String} [resourcePath=] 200 * @return {Boolean} 201 * @example 202 * //example 203 * var map = new cc.TMXTiledMap() 204 * map.initWithTMXFile("hello.tmx"); 205 */ 206 initWithTMXFile:function (tmxFile,resourcePath) { 207 if(!tmxFile || tmxFile.length == 0) 208 throw "cc.TMXTiledMap.initWithTMXFile(): tmxFile should be non-null or non-empty string."; 209 this.setContentSize(0, 0); 210 var mapInfo = cc.TMXMapInfo.create(tmxFile,resourcePath); 211 if (!mapInfo) 212 return false; 213 214 var locTilesets = mapInfo.getTilesets(); 215 if(!locTilesets || locTilesets.length === 0) 216 cc.log("cc.TMXTiledMap.initWithTMXFile(): Map not found. Please check the filename."); 217 this._buildWithMapInfo(mapInfo); 218 return true; 219 }, 220 221 initWithXML:function(tmxString, resourcePath){ 222 this.setContentSize(0, 0); 223 224 var mapInfo = cc.TMXMapInfo.createWithXML(tmxString, resourcePath); 225 var locTilesets = mapInfo.getTilesets(); 226 if(!locTilesets || locTilesets.length === 0) 227 cc.log("cc.TMXTiledMap.initWithXML(): Map not found. Please check the filename."); 228 this._buildWithMapInfo(mapInfo); 229 return true; 230 }, 231 232 _buildWithMapInfo:function (mapInfo) { 233 this._mapSize = mapInfo.getMapSize(); 234 this._tileSize = mapInfo.getTileSize(); 235 this._mapOrientation = mapInfo.getOrientation(); 236 this._objectGroups = mapInfo.getObjectGroups(); 237 this._properties = mapInfo.getProperties(); 238 this._tileProperties = mapInfo.getTileProperties(); 239 240 var idx = 0; 241 var layers = mapInfo.getLayers(); 242 if (layers) { 243 var layerInfo = null; 244 for (var i = 0, len = layers.length; i < len; i++) { 245 layerInfo = layers[i]; 246 if (layerInfo && layerInfo.visible) { 247 var child = this._parseLayer(layerInfo, mapInfo); 248 this.addChild(child, idx, idx); 249 // update content size with the max size 250 var childSize = child.getContentSize(); 251 var currentSize = this.getContentSize(); 252 this.setContentSize(cc.size(Math.max(currentSize.width, childSize.width), Math.max(currentSize.height, childSize.height))); 253 idx++; 254 } 255 } 256 } 257 }, 258 259 allLayers: function () { 260 var retArr = [], locChildren = this._children; 261 for(var i = 0, len = locChildren.length;i< len;i++){ 262 var layer = locChildren[i]; 263 if(layer && layer instanceof cc.TMXLayer) 264 retArr.push(layer); 265 } 266 return retArr; 267 }, 268 269 /** 270 * return the TMXLayer for the specific layer 271 * @param {String} layerName 272 * @return {cc.TMXLayer} 273 */ 274 getLayer:function (layerName) { 275 if(!layerName || layerName.length === 0) 276 throw "cc.TMXTiledMap.getLayer(): layerName should be non-null or non-empty string."; 277 var locChildren = this._children; 278 for (var i = 0; i < locChildren.length; i++) { 279 var layer = locChildren[i]; 280 if (layer && layer.getLayerName() == layerName) 281 return layer; 282 } 283 // layer not found 284 return null; 285 }, 286 287 /** 288 * Return the TMXObjectGroup for the specific group 289 * @param {String} groupName 290 * @return {cc.TMXObjectGroup} 291 */ 292 getObjectGroup:function (groupName) { 293 if(!groupName || groupName.length === 0) 294 throw "cc.TMXTiledMap.getObjectGroup(): groupName should be non-null or non-empty string."; 295 if (this._objectGroups) { 296 for (var i = 0; i < this._objectGroups.length; i++) { 297 var objectGroup = this._objectGroups[i]; 298 if (objectGroup && objectGroup.getGroupName() == groupName) { 299 return objectGroup; 300 } 301 } 302 } 303 // objectGroup not found 304 return null; 305 }, 306 307 /** 308 * Return the value for the specific property name 309 * @param {String} propertyName 310 * @return {String} 311 */ 312 getProperty:function (propertyName) { 313 return this._properties[propertyName.toString()]; 314 }, 315 316 /** 317 * Return properties dictionary for tile GID 318 * @param {Number} GID 319 * @return {object} 320 */ 321 propertiesForGID:function (GID) { 322 return this._tileProperties[GID]; 323 }, 324 325 _parseLayer:function (layerInfo, mapInfo) { 326 var tileset = this._tilesetForLayer(layerInfo, mapInfo); 327 var layer = cc.TMXLayer.create(tileset, layerInfo, mapInfo); 328 // tell the layerinfo to release the ownership of the tiles map. 329 layerInfo.ownTiles = false; 330 layer.setupTiles(); 331 return layer; 332 }, 333 334 _tilesetForLayer:function (layerInfo, mapInfo) { 335 var size = layerInfo._layerSize; 336 var tilesets = mapInfo.getTilesets(); 337 if (tilesets) { 338 for (var i = tilesets.length - 1; i >= 0; i--) { 339 var tileset = tilesets[i]; 340 if (tileset) { 341 for (var y = 0; y < size.height; y++) { 342 for (var x = 0; x < size.width; x++) { 343 var pos = x + size.width * y; 344 var gid = layerInfo._tiles[pos]; 345 if (gid != 0) { 346 // Optimization: quick return 347 // if the layer is invalid (more than 1 tileset per layer) an cc.Assert will be thrown later 348 if (((gid & cc.TMX_TILE_FLIPPED_MASK)>>>0) >= tileset.firstGid) { 349 return tileset; 350 } 351 } 352 353 } 354 } 355 } 356 } 357 } 358 359 // If all the tiles are 0, return empty tileset 360 cc.log("cocos2d: Warning: TMX Layer " + layerInfo.name + " has no tiles"); 361 return null; 362 } 363 }); 364 365 /** 366 * Creates a TMX Tiled Map with a TMX file. 367 * Implementation cc.TMXTiledMap 368 * @param {String} tmxFile 369 * @param {String} resourcePath 370 * @return {cc.TMXTiledMap|undefined} 371 * @example 372 * //example 373 * var map = cc.TMXTiledMap.create("hello.tmx"); 374 */ 375 cc.TMXTiledMap.create = function (tmxFile, resourcePath) { 376 var ret = new cc.TMXTiledMap(); 377 if (ret.initWithTMXFile(tmxFile,resourcePath)) { 378 return ret; 379 } 380 return null; 381 }; 382 383 /** 384 * initializes a TMX Tiled Map with a TMX formatted XML string and a path to TMX resources 385 * @param {String} tmxString 386 * @param {String} resourcePath 387 * @return {cc.TMXTiledMap|undefined} 388 */ 389 cc.TMXTiledMap.createWithXML = function(tmxString, resourcePath){ 390 var tileMap = new cc.TMXTiledMap(); 391 if(tileMap.initWithXML(tmxString,resourcePath)) 392 return tileMap; 393 return null; 394 }; 395