2017-11-10 21:57:38 +00:00
var Formats = require ( '../Formats' ) ;
var Tileset = require ( '../Tileset' ) ;
var Tile = require ( '../Tile' ) ;
2017-11-10 23:13:11 +00:00
var Extend = require ( '../../../utils/object/Extend' ) ;
2017-11-17 19:16:39 +00:00
var MapData = require ( '../mapdata/MapData' ) ;
var LayerData = require ( '../mapdata/LayerData' ) ;
2017-11-10 02:50:25 +00:00
2017-11-14 21:02:19 +00:00
var ParseJSONTiled = function ( key , json , insertNull )
2017-11-10 02:50:25 +00:00
{
2017-11-10 21:57:38 +00:00
if ( json . orientation !== 'orthogonal' )
{
console . warn ( 'Only orthogonal map types are supported in this version of Phaser' ) ;
return null ;
}
// Map data will consist of: layers, objects, images, tilesets, sizes
2017-11-17 19:16:39 +00:00
var mapData = new MapData ( {
2017-11-10 21:57:38 +00:00
width : json . width ,
height : json . height ,
name : key ,
tileWidth : json . tilewidth ,
tileHeight : json . tileheight ,
orientation : json . orientation ,
2017-11-18 14:41:57 +00:00
format : Formats . TILEMAP _TILED _JSON ,
2017-11-10 21:57:38 +00:00
version : json . version ,
2017-11-17 19:16:39 +00:00
properties : json . properties
} ) ;
2017-11-10 21:57:38 +00:00
// Tile Layers
var layers = [ ] ;
for ( var i = 0 ; i < json . layers . length ; i ++ )
{
if ( json . layers [ i ] . type !== 'tilelayer' )
{
continue ;
}
var curl = json . layers [ i ] ;
// Base64 decode data if necessary
// NOTE: uncompressed base64 only.
if ( ! curl . compression && curl . encoding && curl . encoding === 'base64' )
{
var binaryString = window . atob ( curl . data ) ;
var len = binaryString . length ;
var bytes = new Array ( len ) ;
// Interpret binaryString as an array of bytes representing
// little-endian encoded uint32 values.
2017-11-10 23:13:11 +00:00
for ( var j = 0 ; j < len ; j += 4 )
2017-11-10 21:57:38 +00:00
{
bytes [ j / 4 ] = (
binaryString . charCodeAt ( j ) |
binaryString . charCodeAt ( j + 1 ) << 8 |
binaryString . charCodeAt ( j + 2 ) << 16 |
binaryString . charCodeAt ( j + 3 ) << 24
) >>> 0 ;
}
curl . data = bytes ;
delete curl . encoding ;
}
else if ( curl . compression )
{
console . warn ( 'TilemapParser.parseTiledJSON - Layer compression is unsupported, skipping layer \'' + curl . name + '\'' ) ;
continue ;
}
2017-11-17 19:16:39 +00:00
var layerData = new LayerData ( {
2017-11-10 21:57:38 +00:00
name : curl . name ,
x : curl . x ,
y : curl . y ,
width : curl . width ,
height : curl . height ,
2017-11-16 19:27:52 +00:00
tileWidth : json . tilewidth ,
tileHeight : json . tileheight ,
2017-11-10 21:57:38 +00:00
alpha : curl . opacity ,
visible : curl . visible ,
properties : { } ,
indexes : [ ] ,
callbacks : [ ] ,
bodies : [ ]
2017-11-17 19:16:39 +00:00
} ) ;
2017-11-10 21:57:38 +00:00
if ( curl . properties )
{
2017-11-17 19:16:39 +00:00
layerData . properties = curl . properties ;
2017-11-10 21:57:38 +00:00
}
var x = 0 ;
var row = [ ] ;
var output = [ ] ;
var rotation , flipped , flippedVal , gid ;
// Loop through the data field in the JSON.
// This is an array containing the tile indexes, one after the other. -1 = no tile, everything else = the tile index (starting at 1 for Tiled, 0 for CSV)
// If the map contains multiple tilesets then the indexes are relative to that which the set starts from.
// Need to set which tileset in the cache = which tileset in the JSON, if you do this manually it means you can use the same map data but a new tileset.
for ( var t = 0 , len = curl . data . length ; t < len ; t ++ )
{
rotation = 0 ;
flipped = false ;
gid = curl . data [ t ] ;
flippedVal = 0 ;
// If true the current tile is flipped or rotated (Tiled TMX format)
if ( gid > 0x20000000 )
{
// FlippedX
if ( gid > 0x80000000 )
{
gid -= 0x80000000 ;
flippedVal += 4 ;
}
// FlippedY
if ( gid > 0x40000000 )
{
gid -= 0x40000000 ;
flippedVal += 2 ;
}
// FlippedAD (anti-diagonal = top-right is swapped with bottom-left corners)
if ( gid > 0x20000000 )
{
gid -= 0x20000000 ;
flippedVal += 1 ;
}
switch ( flippedVal )
{
case 5 :
rotation = Math . PI / 2 ;
break ;
case 6 :
rotation = Math . PI ;
break ;
case 3 :
rotation = 3 * Math . PI / 2 ;
break ;
case 4 :
rotation = 0 ;
flipped = true ;
break ;
case 7 :
rotation = Math . PI / 2 ;
flipped = true ;
break ;
case 2 :
rotation = Math . PI ;
flipped = true ;
break ;
case 1 :
rotation = 3 * Math . PI / 2 ;
flipped = true ;
break ;
}
}
// index, x, y, width, height
if ( gid > 0 )
{
2017-11-17 19:16:39 +00:00
var tile = new Tile ( layerData , gid , x , output . length , json . tilewidth , json . tileheight ) ;
2017-11-10 21:57:38 +00:00
tile . rotation = rotation ;
tile . flipped = flipped ;
if ( flippedVal !== 0 )
{
// The WebGL renderer uses this to flip UV coordinates before drawing
tile . flippedVal = flippedVal ;
}
row . push ( tile ) ;
}
else
{
2017-11-14 21:02:19 +00:00
var blankTile = insertNull
? null
2017-11-17 19:16:39 +00:00
: new Tile ( layerData , - 1 , x , output . length , json . tilewidth , json . tileheight ) ;
2017-11-14 21:02:19 +00:00
row . push ( blankTile ) ;
2017-11-10 21:57:38 +00:00
}
x ++ ;
if ( x === curl . width )
{
output . push ( row ) ;
x = 0 ;
row = [ ] ;
}
}
2017-11-17 19:16:39 +00:00
layerData . data = output ;
2017-11-10 21:57:38 +00:00
2017-11-17 19:16:39 +00:00
layers . push ( layerData ) ;
2017-11-10 21:57:38 +00:00
}
2017-11-17 19:16:39 +00:00
mapData . layers = layers ;
2017-11-10 21:57:38 +00:00
// Images
var images = [ ] ;
for ( var i = 0 ; i < json . layers . length ; i ++ )
{
if ( json . layers [ i ] . type !== 'imagelayer' )
{
continue ;
}
var curi = json . layers [ i ] ;
var image = {
name : curi . name ,
image : curi . image ,
x : curi . x ,
y : curi . y ,
alpha : curi . opacity ,
visible : curi . visible ,
properties : { }
} ;
if ( curi . properties )
{
image . properties = curi . properties ;
}
images . push ( image ) ;
}
2017-11-17 19:16:39 +00:00
mapData . images = images ;
2017-11-10 21:57:38 +00:00
// Tilesets & Image Collections
var tilesets = [ ] ;
var imagecollections = [ ] ;
var lastSet = null ;
for ( var i = 0 ; i < json . tilesets . length ; i ++ )
{
// name, firstgid, width, height, margin, spacing, properties
var set = json . tilesets [ i ] ;
if ( set . image )
{
var newSet = new Tileset ( set . name , set . firstgid , set . tilewidth , set . tileheight , set . margin , set . spacing , set . properties ) ;
if ( set . tileproperties )
{
newSet . tileProperties = set . tileproperties ;
}
// For a normal sliced tileset the row/count/size information is computed when updated.
// This is done (again) after the image is set.
newSet . updateTileData ( set . imagewidth , set . imageheight ) ;
tilesets . push ( newSet ) ;
}
else
{
// TODO: ImageCollection
// var newCollection = new Phaser.ImageCollection(set.name, set.firstgid, set.tilewidth, set.tileheight, set.margin, set.spacing, set.properties);
// for (var ti in set.tiles)
// {
// var image = set.tiles[ti].image;
// var gid = set.firstgid + parseInt(ti, 10);
// newCollection.addImage(gid, image);
// }
// imagecollections.push(newCollection);
}
// We've got a new Tileset, so set the lastgid into the previous one
if ( lastSet )
{
lastSet . lastgid = set . firstgid - 1 ;
}
lastSet = set ;
}
2017-11-17 19:16:39 +00:00
mapData . tilesets = tilesets ;
mapData . imagecollections = imagecollections ;
2017-11-10 21:57:38 +00:00
// Objects & Collision Data (polylines, etc)
var objects = { } ;
var collision = { } ;
2017-11-10 23:13:11 +00:00
function slice ( obj , fields )
{
2017-11-10 21:57:38 +00:00
var sliced = { } ;
for ( var k in fields )
{
var key = fields [ k ] ;
if ( typeof obj [ key ] !== 'undefined' )
{
sliced [ key ] = obj [ key ] ;
}
}
return sliced ;
}
for ( var i = 0 ; i < json . layers . length ; i ++ )
{
if ( json . layers [ i ] . type !== 'objectgroup' )
{
continue ;
}
var curo = json . layers [ i ] ;
objects [ curo . name ] = [ ] ;
collision [ curo . name ] = [ ] ;
for ( var v = 0 , len = curo . objects . length ; v < len ; v ++ )
{
// Object Tiles
if ( curo . objects [ v ] . gid )
{
var object = {
gid : curo . objects [ v ] . gid ,
name : curo . objects [ v ] . name ,
2017-11-10 23:13:11 +00:00
type : curo . objects [ v ] . hasOwnProperty ( 'type' ) ? curo . objects [ v ] . type : '' ,
2017-11-10 21:57:38 +00:00
x : curo . objects [ v ] . x ,
y : curo . objects [ v ] . y ,
visible : curo . objects [ v ] . visible ,
properties : curo . objects [ v ] . properties
} ;
if ( curo . objects [ v ] . rotation )
{
object . rotation = curo . objects [ v ] . rotation ;
}
objects [ curo . name ] . push ( object ) ;
}
else if ( curo . objects [ v ] . polyline )
{
var object = {
name : curo . objects [ v ] . name ,
type : curo . objects [ v ] . type ,
x : curo . objects [ v ] . x ,
y : curo . objects [ v ] . y ,
width : curo . objects [ v ] . width ,
height : curo . objects [ v ] . height ,
visible : curo . objects [ v ] . visible ,
properties : curo . objects [ v ] . properties
} ;
if ( curo . objects [ v ] . rotation )
{
object . rotation = curo . objects [ v ] . rotation ;
}
object . polyline = [ ] ;
// Parse the polyline into an array
for ( var p = 0 ; p < curo . objects [ v ] . polyline . length ; p ++ )
{
object . polyline . push ( [ curo . objects [ v ] . polyline [ p ] . x , curo . objects [ v ] . polyline [ p ] . y ] ) ;
}
collision [ curo . name ] . push ( object ) ;
objects [ curo . name ] . push ( object ) ;
}
2017-11-10 23:13:11 +00:00
2017-11-10 21:57:38 +00:00
// polygon
else if ( curo . objects [ v ] . polygon )
{
2017-11-10 23:13:11 +00:00
var object = slice ( curo . objects [ v ] , [ 'name' , 'type' , 'x' , 'y' , 'visible' , 'rotation' , 'properties' ] ) ;
2017-11-10 21:57:38 +00:00
// Parse the polygon into an array
object . polygon = [ ] ;
for ( var p = 0 ; p < curo . objects [ v ] . polygon . length ; p ++ )
{
2017-11-10 23:13:11 +00:00
object . polygon . push ( [ curo . objects [ v ] . polygon [ p ] . x , curo . objects [ v ] . polygon [ p ] . y ] ) ;
2017-11-10 21:57:38 +00:00
}
objects [ curo . name ] . push ( object ) ;
}
2017-11-10 23:13:11 +00:00
2017-11-10 21:57:38 +00:00
// ellipse
else if ( curo . objects [ v ] . ellipse )
{
2017-11-10 23:13:11 +00:00
var object = slice ( curo . objects [ v ] , [ 'name' , 'type' , 'ellipse' , 'x' , 'y' , 'width' , 'height' , 'visible' , 'rotation' , 'properties' ] ) ;
2017-11-10 21:57:38 +00:00
objects [ curo . name ] . push ( object ) ;
}
2017-11-10 23:13:11 +00:00
2017-11-10 21:57:38 +00:00
// otherwise it's a rectangle
else
{
2017-11-10 23:13:11 +00:00
var object = slice ( curo . objects [ v ] , [ 'name' , 'type' , 'x' , 'y' , 'width' , 'height' , 'visible' , 'rotation' , 'properties' ] ) ;
2017-11-10 21:57:38 +00:00
object . rectangle = true ;
objects [ curo . name ] . push ( object ) ;
}
}
}
2017-11-17 19:16:39 +00:00
mapData . objects = objects ;
mapData . collision = collision ;
2017-11-10 21:57:38 +00:00
2017-11-17 19:16:39 +00:00
mapData . tiles = [ ] ;
2017-11-10 21:57:38 +00:00
// Finally lets build our super tileset index
2017-11-17 19:16:39 +00:00
for ( var i = 0 ; i < mapData . tilesets . length ; i ++ )
2017-11-10 21:57:38 +00:00
{
2017-11-17 19:16:39 +00:00
var set = mapData . tilesets [ i ] ;
2017-11-10 21:57:38 +00:00
var x = set . tileMargin ;
var y = set . tileMargin ;
var count = 0 ;
var countX = 0 ;
var countY = 0 ;
for ( var t = set . firstgid ; t < set . firstgid + set . total ; t ++ )
{
// Can add extra properties here as needed
2017-11-17 19:16:39 +00:00
mapData . tiles [ t ] = [ x , y , i ] ;
2017-11-10 21:57:38 +00:00
x += set . tileWidth + set . tileSpacing ;
count ++ ;
if ( count === set . total )
{
break ;
}
countX ++ ;
if ( countX === set . columns )
{
x = set . tileMargin ;
y += set . tileHeight + set . tileSpacing ;
countX = 0 ;
countY ++ ;
if ( countY === set . rows )
{
break ;
}
}
}
}
// assign tile properties
2017-11-17 19:16:39 +00:00
var layerData ;
2017-11-10 21:57:38 +00:00
var tile ;
var sid ;
var set ;
// go through each of the map data layers
2017-11-17 19:16:39 +00:00
for ( var i = 0 ; i < mapData . layers . length ; i ++ )
2017-11-10 21:57:38 +00:00
{
2017-11-17 19:16:39 +00:00
layerData = mapData . layers [ i ] ;
2017-11-10 21:57:38 +00:00
set = null ;
// rows of tiles
2017-11-17 19:16:39 +00:00
for ( var j = 0 ; j < layerData . data . length ; j ++ )
2017-11-10 21:57:38 +00:00
{
2017-11-17 19:16:39 +00:00
row = layerData . data [ j ] ;
2017-11-10 21:57:38 +00:00
// individual tiles
for ( var k = 0 ; k < row . length ; k ++ )
{
tile = row [ k ] ;
if ( tile === null || tile . index < 0 )
{
continue ;
}
// find the relevant tileset
2017-11-17 19:16:39 +00:00
sid = mapData . tiles [ tile . index ] [ 2 ] ;
set = mapData . tilesets [ sid ] ;
2017-11-10 21:57:38 +00:00
// if that tile type has any properties, add them to the tile object
if ( set . tileProperties && set . tileProperties [ tile . index - set . firstgid ] )
{
tile . properties = Extend ( tile . properties , set . tileProperties [ tile . index - set . firstgid ] ) ;
}
}
}
}
2017-11-17 19:16:39 +00:00
return mapData ;
2017-11-10 02:50:25 +00:00
} ;
module . exports = ParseJSONTiled ;