@@ -68,18 +68,19 @@ export default class ToolFormattedTilesParallaxScene extends Scene {
6868
6969 applyTileExportData ( tileExport ) {
7070 const tileset = tileExport ?. tileset || null ;
71- const primaryLayer = Array . isArray ( tileExport ?. layers )
72- ? tileExport . layers . find ( ( layer ) => layer ?. kind === 'tile-layer' )
73- : null ;
74- const cells = Array . isArray ( primaryLayer ?. cells )
75- ? primaryLayer . cells
76- : ( Array . isArray ( tileExport ?. cells ) ? tileExport . cells : [ [ ] ] ) ;
77- const tileSize = Number ( tileExport ?. tileSize || tileset ?. tileWidth ) || 48 ;
71+ const atlas = extractTilesetAtlas ( tileExport ) ;
72+ const primaryLayer = getPrimaryTileLayer ( tileExport ) ;
73+ const cells = extractTileCells ( tileExport , primaryLayer ) ;
74+ const tileSize = extractTileSize ( tileExport ) ;
7875 const tilePalette = extractTileEntries ( tileExport ) ;
7976 const definitions = { } ;
80- this . tilesetAssetPath = typeof tileset ?. image === 'string' ? tileset . image : '' ;
77+ this . tilesetAssetPath = extractTilesetImagePath ( tileExport , atlas ) ;
8178 this . tilesetImage = null ;
8279 this . tileFrameById = { } ;
80+ const atlasColumns = Number ( atlas ?. columns )
81+ || ( ( Number ( atlas ?. imageWidth ) > 0 && Number ( atlas ?. tileWidth ) > 0 )
82+ ? Math . floor ( Number ( atlas . imageWidth ) / Number ( atlas . tileWidth ) )
83+ : 0 ) ;
8384
8485 for ( const tileDefinition of tilePalette ) {
8586 const tileId = Number ( tileDefinition ?. tileId ?? tileDefinition ?. id ) ;
@@ -98,8 +99,22 @@ export default class ToolFormattedTilesParallaxScene extends Scene {
9899 this . tileFrameById [ tileId ] = {
99100 x : Number ( source . x ) || 0 ,
100101 y : Number ( source . y ) || 0 ,
101- w : Number ( source . w ) || tileSize ,
102- h : Number ( source . h ) || tileSize ,
102+ w : Number ( source . w ?? source . width ) || tileSize ,
103+ h : Number ( source . h ?? source . height ) || tileSize ,
104+ } ;
105+ } else if ( atlasColumns > 0 && tileId > 0 ) {
106+ const index = tileId - 1 ;
107+ const col = index % atlasColumns ;
108+ const row = Math . floor ( index / atlasColumns ) ;
109+ const atlasTileWidth = Number ( atlas ?. tileWidth ) || tileSize ;
110+ const atlasTileHeight = Number ( atlas ?. tileHeight ) || tileSize ;
111+ const spacing = Number ( atlas ?. spacing ) || 0 ;
112+ const margin = Number ( atlas ?. margin ) || 0 ;
113+ this . tileFrameById [ tileId ] = {
114+ x : margin + col * ( atlasTileWidth + spacing ) ,
115+ y : margin + row * ( atlasTileHeight + spacing ) ,
116+ w : atlasTileWidth ,
117+ h : atlasTileHeight ,
103118 } ;
104119 }
105120
@@ -117,8 +132,7 @@ export default class ToolFormattedTilesParallaxScene extends Scene {
117132 height : this . tilemap . height * this . tilemap . tileSize ,
118133 } ;
119134
120- const viewportWidth = Number ( tileExport ?. camera ?. viewportWidth ) || 860 ;
121- const viewportHeight = Number ( tileExport ?. camera ?. viewportHeight ) || 300 ;
135+ const { viewportWidth, viewportHeight } = extractCameraViewport ( tileExport ) ;
122136
123137 this . camera = new Camera2D ( {
124138 viewportWidth,
@@ -133,8 +147,7 @@ export default class ToolFormattedTilesParallaxScene extends Scene {
133147 this . world . height
134148 ) ;
135149
136- const spawn = tileExport ?. spawnPoints ?. hero
137- || tileExport ?. heroSpawn
150+ const spawn = extractSpawnPoint ( tileExport , tileSize , this . hero )
138151 || { x : 120 , y : this . world . height - tileSize - this . hero . height } ;
139152 this . hero . x = clamp ( Number ( spawn . x ) || 120 , 0 , Math . max ( 0 , this . world . width - this . hero . width ) ) ;
140153 this . hero . y = clamp (
@@ -171,8 +184,16 @@ export default class ToolFormattedTilesParallaxScene extends Scene {
171184
172185 const loadOperations = layerDefinitions . map ( async ( layerDefinition , index ) => {
173186 const image = await loadImageFromRelativePath ( layerDefinition . asset , import . meta. url ) ;
174- const sourceWidth = image . naturalWidth || image . width ;
175- const sourceHeight = image . naturalHeight || image . height ;
187+ const sourceWidth = Number ( layerDefinition . sourceWidth )
188+ || image . naturalWidth
189+ || image . width
190+ || Number ( layerDefinition . segmentWidth )
191+ || 1024 ;
192+ const sourceHeight = Number ( layerDefinition . sourceHeight )
193+ || image . naturalHeight
194+ || image . height
195+ || Number ( layerDefinition . height )
196+ || 300 ;
176197 return {
177198 id : layerDefinition . id || `layer-${ index } ` ,
178199 image,
@@ -322,26 +343,13 @@ export default class ToolFormattedTilesParallaxScene extends Scene {
322343 }
323344
324345 drawParallax ( renderer ) {
325- renderer . drawRect (
326- this . screen . x ,
327- this . screen . y ,
328- this . camera . viewportWidth ,
329- this . camera . viewportHeight ,
330- '#9fd2ff'
331- ) ;
332- renderer . drawCircle (
333- this . screen . x + 160 ,
334- this . screen . y + 54 ,
335- 28 ,
336- 'rgba(255, 245, 190, 0.75)'
337- ) ;
338-
339346 for ( const layer of this . parallaxLayers ) {
340- const segment = layer . segmentWidth ;
347+ const segment = Math . max ( 1 , layer . segmentWidth ) ;
341348 const offset = - ( ( this . camera . x * layer . scrollFactor ) % segment ) ;
342349 const endX = this . screen . x + this . camera . viewportWidth + segment ;
343350 const layerTop = this . screen . y + layer . y ;
344- const layerHeight = Math . max ( 1 , this . camera . viewportHeight - layer . y ) ;
351+ const viewportBottom = this . screen . y + this . camera . viewportHeight ;
352+ const layerHeight = Math . max ( 1 , viewportBottom - layerTop ) ;
345353
346354 for ( let x = this . screen . x + offset - segment ; x < endX ; x += segment ) {
347355 renderer . drawImageFrame (
@@ -481,6 +489,18 @@ function getFallbackTileExport() {
481489}
482490
483491function extractTileEntries ( tileExport ) {
492+ if ( tileExport ?. schema === 'toolbox.tilemap/1' && Array . isArray ( tileExport ?. tileset ) ) {
493+ return tileExport . tileset
494+ . map ( ( entry ) => ( {
495+ tileId : Number ( entry ?. id ) ,
496+ name : entry ?. name || `tile-${ entry ?. id } ` ,
497+ solid : Number ( entry ?. id ) > 0 ,
498+ fallbackColor : entry ?. color || '#1f2937' ,
499+ source : normalizeTilesetSource ( entry ?. source ) ,
500+ } ) )
501+ . filter ( ( entry ) => Number . isInteger ( entry . tileId ) && entry . tileId > 0 ) ;
502+ }
503+
484504 if ( Array . isArray ( tileExport ?. tileset ?. entries ) ) {
485505 return tileExport . tileset . entries ;
486506 }
@@ -499,3 +519,119 @@ function placePlatform(cells, row, startCol, endCol, tileId) {
499519 cells [ row ] [ col ] = tileId ;
500520 }
501521}
522+
523+ function getPrimaryTileLayer ( tileExport ) {
524+ if ( ! Array . isArray ( tileExport ?. layers ) ) {
525+ return null ;
526+ }
527+ if ( tileExport ?. schema === 'toolbox.tilemap/1' ) {
528+ return tileExport . layers . find ( ( layer ) => layer ?. kind === 'tile' ) || null ;
529+ }
530+ return tileExport . layers . find ( ( layer ) => layer ?. kind === 'tile-layer' ) || null ;
531+ }
532+
533+ function extractTileCells ( tileExport , primaryLayer ) {
534+ if ( tileExport ?. schema === 'toolbox.tilemap/1' ) {
535+ if ( Array . isArray ( primaryLayer ?. data ) ) {
536+ return primaryLayer . data ;
537+ }
538+ } else if ( Array . isArray ( primaryLayer ?. cells ) ) {
539+ return primaryLayer . cells ;
540+ }
541+
542+ if ( Array . isArray ( tileExport ?. cells ) ) {
543+ return tileExport . cells ;
544+ }
545+ return [ [ ] ] ;
546+ }
547+
548+ function extractTileSize ( tileExport ) {
549+ if ( tileExport ?. schema === 'toolbox.tilemap/1' ) {
550+ return Number ( tileExport ?. map ?. tileSize )
551+ || Number ( tileExport ?. tilesetAtlas ?. tileWidth )
552+ || 48 ;
553+ }
554+ return Number ( tileExport ?. tileSize || tileExport ?. tileset ?. tileWidth ) || 48 ;
555+ }
556+
557+ function extractTilesetAtlas ( tileExport ) {
558+ if ( tileExport ?. schema === 'toolbox.tilemap/1' ) {
559+ return tileExport ?. tilesetAtlas || null ;
560+ }
561+ return tileExport ?. tileset || null ;
562+ }
563+
564+ function extractTilesetImagePath ( tileExport , atlas ) {
565+ if ( typeof tileExport ?. tileset ?. image === 'string' && tileExport . tileset . image ) {
566+ return tileExport . tileset . image ;
567+ }
568+ if ( typeof atlas ?. imageName === 'string' && atlas . imageName ) {
569+ return atlas . imageName ;
570+ }
571+ if ( typeof atlas ?. imageDataUrl === 'string' && atlas . imageDataUrl ) {
572+ return atlas . imageDataUrl ;
573+ }
574+ return '' ;
575+ }
576+
577+ function extractCameraViewport ( tileExport ) {
578+ const markerCamera = Array . isArray ( tileExport ?. markers )
579+ ? tileExport . markers . find ( ( marker ) => marker ?. type === 'spawn' && marker ?. properties )
580+ : null ;
581+
582+ return {
583+ viewportWidth : Number ( tileExport ?. camera ?. viewportWidth )
584+ || Number ( tileExport ?. map ?. viewportWidth )
585+ || Number ( markerCamera ?. properties ?. cameraViewportWidth )
586+ || 860 ,
587+ viewportHeight : Number ( tileExport ?. camera ?. viewportHeight )
588+ || Number ( tileExport ?. map ?. viewportHeight )
589+ || Number ( markerCamera ?. properties ?. cameraViewportHeight )
590+ || 300 ,
591+ } ;
592+ }
593+
594+ function extractSpawnPoint ( tileExport , tileSize , hero ) {
595+ const explicit = tileExport ?. spawnPoints ?. hero || tileExport ?. heroSpawn || null ;
596+ if ( explicit && Number . isFinite ( Number ( explicit . x ) ) && Number . isFinite ( Number ( explicit . y ) ) ) {
597+ return { x : Number ( explicit . x ) , y : Number ( explicit . y ) } ;
598+ }
599+
600+ if ( Array . isArray ( tileExport ?. markers ) ) {
601+ const spawnMarker = tileExport . markers . find ( ( marker ) => marker ?. type === 'spawn' ) ;
602+ if ( spawnMarker ?. properties ) {
603+ const px = Number ( spawnMarker . properties . spawnX ) ;
604+ const py = Number ( spawnMarker . properties . spawnY ) ;
605+ if ( Number . isFinite ( px ) && Number . isFinite ( py ) ) {
606+ return { x : px , y : py } ;
607+ }
608+ }
609+ if ( spawnMarker && Number . isFinite ( Number ( spawnMarker . col ) ) && Number . isFinite ( Number ( spawnMarker . row ) ) ) {
610+ const col = Number ( spawnMarker . col ) ;
611+ const row = Number ( spawnMarker . row ) ;
612+ return {
613+ x : col * tileSize + ( tileSize - hero . width ) * 0.5 ,
614+ y : ( row + 1 ) * tileSize - hero . height ,
615+ } ;
616+ }
617+ }
618+
619+ return null ;
620+ }
621+
622+ function normalizeTilesetSource ( source ) {
623+ if ( ! source || typeof source !== 'object' ) {
624+ return null ;
625+ }
626+
627+ if ( source . kind === 'atlas' || ( 'x' in source && 'y' in source ) ) {
628+ return {
629+ x : Number ( source . x ) || 0 ,
630+ y : Number ( source . y ) || 0 ,
631+ w : Number ( source . width ?? source . w ) || 0 ,
632+ h : Number ( source . height ?? source . h ) || 0 ,
633+ } ;
634+ }
635+
636+ return null ;
637+ }
0 commit comments