@@ -11,11 +11,14 @@ import { drawFrame, drawPanel } from '/src/engine/debug/index.js';
1111import { Tilemap , renderTilemap , resolveRectVsTilemap } from '/src/engine/tilemap/index.js' ;
1212
1313const theme = new Theme ( ThemeTokens ) ;
14+ const TILEMAP_PRESET_PATH = '/samples/phase-02/0221/sample-0221-tile-map-editor.json' ;
1415
1516export default class TilemapSystemScene extends Scene {
1617 constructor ( ) {
1718 super ( ) ;
1819 this . offset = { x : 160 , y : 180 } ;
20+ this . sampleStatus = 'Loading shared tilemap preset...' ;
21+ this . sampleError = '' ;
1922 this . tilemap = new Tilemap ( {
2023 tileSize : 48 ,
2124 tiles : [
@@ -39,6 +42,133 @@ export default class TilemapSystemScene extends Scene {
3942 speed : 220 ,
4043 } ;
4144 this . lastCollision = 'none' ;
45+ void this . loadTilemapPreset ( ) ;
46+ }
47+
48+ extractTileMapDocumentFromSamplePreset ( rawPreset ) {
49+ if ( ! rawPreset || typeof rawPreset !== 'object' ) {
50+ return null ;
51+ }
52+
53+ const payload = rawPreset . payload ;
54+ if ( payload && typeof payload === 'object' ) {
55+ if ( payload . tilemapDocument && typeof payload . tilemapDocument === 'object' ) {
56+ return payload . tilemapDocument ;
57+ }
58+ if ( payload . tileMapDocument && typeof payload . tileMapDocument === 'object' ) {
59+ return payload . tileMapDocument ;
60+ }
61+ if ( payload . tilemap && typeof payload . tilemap === 'object' ) {
62+ return payload . tilemap ;
63+ }
64+ if ( payload . tileMap && typeof payload . tileMap === 'object' ) {
65+ return payload . tileMap ;
66+ }
67+ if ( typeof payload . tilemapDocumentPath === 'string' && payload . tilemapDocumentPath . trim ( ) ) {
68+ return payload . tilemapDocumentPath . trim ( ) ;
69+ }
70+ if ( typeof payload . tileMapDocumentPath === 'string' && payload . tileMapDocumentPath . trim ( ) ) {
71+ return payload . tileMapDocumentPath . trim ( ) ;
72+ }
73+ }
74+ return null ;
75+ }
76+
77+ applyTilemapDocument ( documentModel ) {
78+ if ( ! documentModel || typeof documentModel !== 'object' ) {
79+ throw new Error ( 'Tilemap document is missing.' ) ;
80+ }
81+
82+ const map = documentModel . map || { } ;
83+ const tileSize = Number ( map . tileSize ) > 0 ? Number ( map . tileSize ) : 48 ;
84+ const layers = Array . isArray ( documentModel . layers ) ? documentModel . layers : [ ] ;
85+ const renderLayer = layers . find ( ( layer ) => layer && layer . kind === 'tile' ) || layers [ 0 ] || null ;
86+ const collisionLayer = layers . find ( ( layer ) => layer && layer . kind === 'collision' ) || null ;
87+
88+ if ( ! renderLayer || ! Array . isArray ( renderLayer . data ) || renderLayer . data . length === 0 ) {
89+ throw new Error ( 'Tilemap document did not include a render layer.' ) ;
90+ }
91+
92+ const rows = renderLayer . data . map ( ( row ) => Array . isArray ( row ) ? row . map ( ( value ) => Number . parseInt ( value , 10 ) || 0 ) : [ ] ) ;
93+ const tilesetEntries = Array . isArray ( documentModel . tileset ) ? documentModel . tileset : [ ] ;
94+ const palette = { } ;
95+ tilesetEntries . forEach ( ( entry ) => {
96+ const id = Number . parseInt ( entry ?. id , 10 ) ;
97+ const color = typeof entry ?. color === 'string' ? entry . color : '' ;
98+ if ( Number . isInteger ( id ) && color ) {
99+ palette [ id ] = color ;
100+ }
101+ } ) ;
102+ if ( ! palette [ 0 ] ) {
103+ palette [ 0 ] = '#1f2937' ;
104+ }
105+
106+ const definitions = { } ;
107+ if ( collisionLayer && Array . isArray ( collisionLayer . data ) ) {
108+ collisionLayer . data . forEach ( ( row , rowIndex ) => {
109+ if ( ! Array . isArray ( row ) ) {
110+ return ;
111+ }
112+ row . forEach ( ( cell , colIndex ) => {
113+ if ( Number ( cell ) === 1 ) {
114+ const tileId = Number ( rows [ rowIndex ] ?. [ colIndex ] ) || 0 ;
115+ if ( ! definitions [ tileId ] ) {
116+ definitions [ tileId ] = {
117+ solid : true ,
118+ color : palette [ tileId ] || '#6366f1' ,
119+ label : `tile-${ tileId } `
120+ } ;
121+ } else {
122+ definitions [ tileId ] . solid = true ;
123+ }
124+ }
125+ } ) ;
126+ } ) ;
127+ }
128+
129+ this . tilemap = new Tilemap ( {
130+ tileSize,
131+ tiles : rows ,
132+ palette,
133+ definitions
134+ } ) ;
135+
136+ this . player . x = this . offset . x + 60 ;
137+ this . player . y = this . offset . y + 60 ;
138+ }
139+
140+ async loadTilemapPreset ( ) {
141+ try {
142+ const presetResponse = await fetch ( TILEMAP_PRESET_PATH , { cache : 'no-store' } ) ;
143+ if ( ! presetResponse . ok ) {
144+ throw new Error ( `Preset request failed (${ presetResponse . status } ).` ) ;
145+ }
146+
147+ const samplePreset = await presetResponse . json ( ) ;
148+ const extracted = this . extractTileMapDocumentFromSamplePreset ( samplePreset ) ;
149+ let documentModel = null ;
150+
151+ if ( typeof extracted === 'string' && extracted . trim ( ) ) {
152+ const documentResponse = await fetch ( extracted . trim ( ) , { cache : 'no-store' } ) ;
153+ if ( ! documentResponse . ok ) {
154+ throw new Error ( `Tilemap document request failed (${ documentResponse . status } ).` ) ;
155+ }
156+ documentModel = await documentResponse . json ( ) ;
157+ } else if ( extracted && typeof extracted === 'object' ) {
158+ documentModel = extracted ;
159+ }
160+
161+ if ( ! documentModel ) {
162+ throw new Error ( 'Preset payload did not include a tilemap document.' ) ;
163+ }
164+
165+ this . applyTilemapDocument ( documentModel ) ;
166+ this . sampleStatus = 'Loaded tilemap preset from sample-0221-tile-map-editor.json' ;
167+ this . sampleError = '' ;
168+ } catch ( error ) {
169+ this . sampleStatus = 'Using fallback in-scene tilemap.' ;
170+ this . sampleError = error instanceof Error ? error . message : String ( error ) ;
171+ }
42172 }
43173
44174 update ( dt , engine ) {
@@ -67,9 +197,10 @@ export default class TilemapSystemScene extends Scene {
67197 drawFrame ( renderer , theme , [
68198 'Engine Sample 0221' ,
69199 'Demonstrates tilemap rendering and tile-based collision' ,
200+ 'This sample and Tilemap Studio load the same sample-0221-tile-map-editor.json source' ,
70201 'Use Arrow keys to move through the open tiles' ,
71202 `Collision: ${ this . lastCollision } ` ,
72- 'This sample provides the first map-driven gameplay foundation' ,
203+ this . sampleError ? ` ${ this . sampleStatus } ( ${ this . sampleError } )` : this . sampleStatus ,
73204 ] ) ;
74205
75206 renderTilemap ( renderer , this . tilemap , this . offset ) ;
0 commit comments