@@ -10,7 +10,9 @@ class GodotTilemapExporter {
10
10
this . tileOffset = 65536 ;
11
11
this . tileMapsString = "" ;
12
12
this . tilesetsString = "" ;
13
+ this . subResourcesString = "" ;
13
14
this . extResourceId = 0 ;
15
+ this . subResourceId = 0 ;
14
16
15
17
/**
16
18
* Tiled doesn't have tileset ID so we create a map
@@ -35,6 +37,28 @@ class GodotTilemapExporter {
35
37
console . info ( `Tilemap exported successfully to ${ this . fileName } ` ) ;
36
38
}
37
39
40
+ /**
41
+ * Adds a new subresource to the genrated file
42
+ *
43
+ * @param {string } type the type of subresource
44
+ * @param {object } contentProperties key:value map of properties
45
+ * @returns {int } the created sub resource id
46
+ */
47
+ addSubResource ( type , contentProperties ) {
48
+ const id = this . subResourceId ++ ;
49
+
50
+ this . subResourcesString += `
51
+
52
+ [sub_resource type="${ type } " id=${ id } ]
53
+ ` ;
54
+ removeUndefined ( contentProperties ) ;
55
+ for ( const [ key , value ] of Object . entries ( contentProperties ) ) {
56
+ this . subResourcesString += stringifyKeyValue ( key , value , false , true ) + '\n' ;
57
+ }
58
+
59
+ return id ;
60
+ }
61
+
38
62
/**
39
63
* Generate a string with all tilesets in the map.
40
64
* Godot allows only one tileset per tilemap so if you use more than one tileset per layer it's n ot going to work.
@@ -76,14 +100,22 @@ class GodotTilemapExporter {
76
100
if ( ! ld . isEmpty ) {
77
101
const tileMapName = idx === 0 ? layer . name || "TileMap " + i : ld . tileset . name || "TileMap " + i + "_" + idx ;
78
102
this . mapLayerToTileset ( layer . name , ld . tilesetID ) ;
79
- this . tileMapsString += this . getTileMapTemplate ( tileMapName , ld . tilesetID , ld . poolIntArrayString , ld . parent , layer . map . tileWidth , layer . map . tileHeight ) ;
103
+ this . tileMapsString += this . getTileMapTemplate ( tileMapName , ld . tilesetID , ld . poolIntArrayString , ld . parent , layer . map . tileWidth , layer . map . tileHeight , layer . property ( "groups" ) ) ;
80
104
}
81
105
}
82
106
} else if ( layer . isObjectLayer ) {
83
- this . tileMapsString += `
84
-
85
- [node name="${ layer . name } " type="Node2D" parent="."]` ;
107
+ // create layer
108
+ this . tileMapsString += stringifyNode ( {
109
+ name : layer . name ,
110
+ type : "Node2D" ,
111
+ parent : "." ,
112
+ groups : splitCommaSeparated ( layer . property ( "groups" ) )
113
+ } ) ;
114
+
115
+ // add entities
86
116
for ( const object of layer . objects ) {
117
+ const groups = splitCommaSeparated ( object . property ( "groups" ) ) ;
118
+
87
119
if ( object . tile ) {
88
120
let tilesetsIndexKey = object . tile . tileset . name + "_Image" ;
89
121
let textureResourceId = 0 ;
@@ -103,13 +135,54 @@ class GodotTilemapExporter {
103
135
let objectPositionX = object . x + ( object . tile . width / 2 ) ;
104
136
let objectPositionY = object . y - ( object . tile . height / 2 ) ;
105
137
106
- this . tileMapsString += `
107
-
108
- [node name="${ object . name } " type="Sprite" parent="${ layer . name } "]
109
- position = Vector2( ${ objectPositionX } , ${ objectPositionY } )
110
- texture = ExtResource( ${ textureResourceId } )
111
- region_enabled = true
112
- region_rect = Rect2( ${ tileOffset . x } , ${ tileOffset . y } , ${ object . tile . width } , ${ object . tile . height } )` ;
138
+ this . tileMapsString += stringifyNode ( {
139
+ name : object . name ,
140
+ type : "Sprite" ,
141
+ parent : layer . name
142
+ } , {
143
+ position : `Vector2( ${ objectPositionX } , ${ objectPositionY } )` ,
144
+ texture : `ExtResource( ${ textureResourceId } )` ,
145
+ region_enabled : true ,
146
+ region_rect : `Rect2( ${ tileOffset . x } , ${ tileOffset . y } , ${ object . tile . width } , ${ object . tile . height } )`
147
+ } ) ;
148
+ } else if ( object . type == "Area2D" && object . width && object . height ) {
149
+ // Creates an Area2D node with a rectangle shape inside
150
+ // Does not support rotation
151
+ const width = object . width / 2 ;
152
+ const height = object . height / 2 ;
153
+ const objectPositionX = object . x + width ;
154
+ const objectPositionY = object . y + height ;
155
+
156
+ this . tileMapsString += stringifyNode ( {
157
+ name : object . name ,
158
+ type : "Area2D" ,
159
+ parent : layer . name ,
160
+ groups : groups
161
+ } , {
162
+ collision_layer : object . property ( "collision_layer" ) ,
163
+ collision_mask : object . property ( "collision_mask" )
164
+ } ) ;
165
+
166
+ const shapeId = this . addSubResource ( "RectangleShape2D" , {
167
+ extents : `Vector2( ${ width } , ${ height } )`
168
+ } ) ;
169
+ this . tileMapsString += stringifyNode ( {
170
+ name : "CollisionShape2D" ,
171
+ type : "CollisionShape2D" ,
172
+ parent : `${ layer . name } /${ object . name } `
173
+ } , {
174
+ shape : `SubResource( ${ shapeId } )` ,
175
+ position : `Vector2( ${ objectPositionX } , ${ objectPositionY } )` ,
176
+ } ) ;
177
+ } else if ( object . type == "Node2D" ) {
178
+ this . tileMapsString += stringifyNode ( {
179
+ name : object . name ,
180
+ type : "Node2D" ,
181
+ parent : layer . name ,
182
+ groups : groups
183
+ } , {
184
+ position : `Vector2( ${ object . x } , ${ object . y } )`
185
+ } ) ;
113
186
}
114
187
}
115
188
}
@@ -347,9 +420,12 @@ region_rect = Rect2( ${tileOffset.x}, ${tileOffset.y}, ${object.tile.width}, ${o
347
420
* @returns {string }
348
421
*/
349
422
getSceneTemplate ( ) {
350
- return `[gd_scene load_steps=2 format=2]
423
+ const loadSteps = 2 + this . subResourceId ;
424
+
425
+ return `[gd_scene load_steps=${ loadSteps } format=2]
351
426
352
427
${ this . tilesetsString }
428
+ ${ this . subResourcesString }
353
429
[node name="Node2D" type="Node2D"]
354
430
${ this . tileMapsString }
355
431
` ;
@@ -370,14 +446,20 @@ ${this.tileMapsString}
370
446
* Template for a tilemap node
371
447
* @returns {string }
372
448
*/
373
- getTileMapTemplate ( tileMapName , tilesetID , poolIntArrayString , parent = "." , tileWidth = 16 , tileHeight = 16 ) {
374
- return `[node name="${ tileMapName } " type="TileMap" parent="${ parent } "]
375
- tile_set = ExtResource( ${ tilesetID } )
376
- cell_size = Vector2( ${ tileWidth } , ${ tileHeight } )
377
- cell_custom_transform = Transform2D( 16, 0, 0, 16, 0, 0 )
378
- format = 1
379
- tile_data = PoolIntArray( ${ poolIntArrayString } )
380
- ` ;
449
+ getTileMapTemplate ( tileMapName , tilesetID , poolIntArrayString , parent = "." , tileWidth = 16 , tileHeight = 16 , groups = undefined ) {
450
+ groups = splitCommaSeparated ( groups ) ;
451
+ return stringifyNode ( {
452
+ name : tileMapName ,
453
+ type : "TileMap" ,
454
+ parent : parent ,
455
+ groups : groups
456
+ } , {
457
+ tile_set : `ExtResource( ${ tilesetID } )` ,
458
+ cell_size : `Vector2( ${ tileWidth } , ${ tileHeight } )` ,
459
+ cell_custom_transform : `Transform2D( 16, 0, 0, 16, 0, 0 )` ,
460
+ format : "1" ,
461
+ tile_data : `PoolIntArray( ${ poolIntArrayString } )`
462
+ } ) ;
381
463
}
382
464
383
465
mapLayerToTileset ( layerName , tilesetID ) {
0 commit comments