@codexo/exojs-tilemap 0.15.3 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +33 -26
- package/dist/esm/ChunkSource.d.ts +33 -0
- package/dist/esm/ChunkSource.d.ts.map +1 -0
- package/dist/esm/ChunkStreamer.d.ts +98 -0
- package/dist/esm/ChunkStreamer.d.ts.map +1 -0
- package/dist/esm/ChunkStreamer.js +201 -0
- package/dist/esm/ChunkStreamer.js.map +1 -0
- package/dist/esm/ImageLayer.d.ts +11 -3
- package/dist/esm/ImageLayer.d.ts.map +1 -0
- package/dist/esm/ImageLayer.js +71 -64
- package/dist/esm/ImageLayer.js.map +1 -1
- package/dist/esm/ImageLayerNode.d.ts +89 -0
- package/dist/esm/ImageLayerNode.d.ts.map +1 -0
- package/dist/esm/ImageLayerNode.js +205 -0
- package/dist/esm/ImageLayerNode.js.map +1 -0
- package/dist/esm/MapObject.d.ts +70 -0
- package/dist/esm/MapObject.d.ts.map +1 -0
- package/dist/esm/MapObject.js +34 -0
- package/dist/esm/MapObject.js.map +1 -0
- package/dist/esm/MapObjectSpawner.d.ts +133 -0
- package/dist/esm/MapObjectSpawner.d.ts.map +1 -0
- package/dist/esm/MapObjectSpawner.js +147 -0
- package/dist/esm/MapObjectSpawner.js.map +1 -0
- package/dist/esm/MapSpawnSession.d.ts +53 -0
- package/dist/esm/MapSpawnSession.d.ts.map +1 -0
- package/dist/esm/MapSpawnSession.js +88 -0
- package/dist/esm/MapSpawnSession.js.map +1 -0
- package/dist/esm/MapWorld.d.ts +134 -0
- package/dist/esm/MapWorld.d.ts.map +1 -0
- package/dist/esm/MapWorld.js +150 -0
- package/dist/esm/MapWorld.js.map +1 -0
- package/dist/esm/MapWorldRuntime.d.ts +182 -0
- package/dist/esm/MapWorldRuntime.d.ts.map +1 -0
- package/dist/esm/MapWorldRuntime.js +261 -0
- package/dist/esm/MapWorldRuntime.js.map +1 -0
- package/dist/esm/ObjectLayer.d.ts +93 -7
- package/dist/esm/ObjectLayer.d.ts.map +1 -0
- package/dist/esm/ObjectLayer.js +184 -167
- package/dist/esm/ObjectLayer.js.map +1 -1
- package/dist/esm/SampledChunkSource.d.ts +43 -0
- package/dist/esm/SampledChunkSource.d.ts.map +1 -0
- package/dist/esm/SampledChunkSource.js +48 -0
- package/dist/esm/SampledChunkSource.js.map +1 -0
- package/dist/esm/TileAnimator.d.ts +12 -2
- package/dist/esm/TileAnimator.d.ts.map +1 -0
- package/dist/esm/TileAnimator.js +154 -165
- package/dist/esm/TileAnimator.js.map +1 -1
- package/dist/esm/TileChunk.d.ts +30 -5
- package/dist/esm/TileChunk.d.ts.map +1 -0
- package/dist/esm/TileChunk.js +190 -188
- package/dist/esm/TileChunk.js.map +1 -1
- package/dist/esm/TileChunkNode.d.ts +18 -3
- package/dist/esm/TileChunkNode.d.ts.map +1 -0
- package/dist/esm/TileChunkNode.js +104 -85
- package/dist/esm/TileChunkNode.js.map +1 -1
- package/dist/esm/TileLayer.d.ts +104 -24
- package/dist/esm/TileLayer.d.ts.map +1 -0
- package/dist/esm/TileLayer.js +511 -469
- package/dist/esm/TileLayer.js.map +1 -1
- package/dist/esm/TileLayerNode.d.ts +52 -11
- package/dist/esm/TileLayerNode.d.ts.map +1 -0
- package/dist/esm/TileLayerNode.js +224 -166
- package/dist/esm/TileLayerNode.js.map +1 -1
- package/dist/esm/TileMap.d.ts +96 -31
- package/dist/esm/TileMap.d.ts.map +1 -0
- package/dist/esm/TileMap.js +401 -357
- package/dist/esm/TileMap.js.map +1 -1
- package/dist/esm/TileMapBand.d.ts +42 -29
- package/dist/esm/TileMapBand.d.ts.map +1 -0
- package/dist/esm/TileMapBand.js +151 -158
- package/dist/esm/TileMapBand.js.map +1 -1
- package/dist/esm/TileMapNode.d.ts +34 -18
- package/dist/esm/TileMapNode.d.ts.map +1 -0
- package/dist/esm/TileMapNode.js +122 -109
- package/dist/esm/TileMapNode.js.map +1 -1
- package/dist/esm/TileMapView.d.ts +108 -47
- package/dist/esm/TileMapView.d.ts.map +1 -0
- package/dist/esm/TileMapView.js +385 -338
- package/dist/esm/TileMapView.js.map +1 -1
- package/dist/esm/TileSet.d.ts +15 -6
- package/dist/esm/TileSet.d.ts.map +1 -0
- package/dist/esm/TileSet.js +161 -181
- package/dist/esm/TileSet.js.map +1 -1
- package/dist/esm/WangSet.d.ts +5 -4
- package/dist/esm/WangSet.d.ts.map +1 -0
- package/dist/esm/WangSet.js +70 -78
- package/dist/esm/WangSet.js.map +1 -1
- package/dist/esm/WorkerSampledChunkSource.d.ts +95 -0
- package/dist/esm/WorkerSampledChunkSource.d.ts.map +1 -0
- package/dist/esm/WorkerSampledChunkSource.js +117 -0
- package/dist/esm/WorkerSampledChunkSource.js.map +1 -0
- package/dist/esm/autoTile.d.ts +10 -5
- package/dist/esm/autoTile.d.ts.map +1 -0
- package/dist/esm/autoTile.js +164 -205
- package/dist/esm/autoTile.js.map +1 -1
- package/dist/esm/chunkGeometry.d.ts +8 -7
- package/dist/esm/chunkGeometry.d.ts.map +1 -0
- package/dist/esm/chunkGeometry.js +83 -94
- package/dist/esm/chunkGeometry.js.map +1 -1
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.d.ts.map +1 -0
- package/dist/esm/index.js +26 -15
- package/dist/esm/nodeBounds.d.ts +20 -0
- package/dist/esm/nodeBounds.d.ts.map +1 -0
- package/dist/esm/nodeBounds.js +40 -0
- package/dist/esm/nodeBounds.js.map +1 -0
- package/dist/esm/pixelSnap.d.ts +4 -3
- package/dist/esm/pixelSnap.d.ts.map +1 -0
- package/dist/esm/pixelSnap.js +18 -16
- package/dist/esm/pixelSnap.js.map +1 -1
- package/dist/esm/public.d.ts +23 -3
- package/dist/esm/public.d.ts.map +1 -0
- package/dist/esm/tileCollision.d.ts +190 -0
- package/dist/esm/tileCollision.d.ts.map +1 -0
- package/dist/esm/tileCollision.js +367 -0
- package/dist/esm/tileCollision.js.map +1 -0
- package/dist/esm/tileWord.d.ts +12 -0
- package/dist/esm/tileWord.d.ts.map +1 -0
- package/dist/esm/tileWord.js +16 -0
- package/dist/esm/tileWord.js.map +1 -0
- package/dist/esm/tilemapExtension.d.ts +4 -3
- package/dist/esm/tilemapExtension.d.ts.map +1 -0
- package/dist/esm/tilemapExtension.js +47 -47
- package/dist/esm/tilemapExtension.js.map +1 -1
- package/dist/esm/tilemapSerializers.d.ts +5 -4
- package/dist/esm/tilemapSerializers.d.ts.map +1 -0
- package/dist/esm/tilemapSerializers.js +48 -41
- package/dist/esm/tilemapSerializers.js.map +1 -1
- package/dist/esm/types.d.ts +34 -18
- package/dist/esm/types.d.ts.map +1 -0
- package/dist/esm/types.js +111 -120
- package/dist/esm/types.js.map +1 -1
- package/dist/esm/webgl2/WebGl2TileChunkRenderer.d.ts +50 -2
- package/dist/esm/webgl2/WebGl2TileChunkRenderer.d.ts.map +1 -0
- package/dist/esm/webgl2/WebGl2TileChunkRenderer.js +366 -332
- package/dist/esm/webgl2/WebGl2TileChunkRenderer.js.map +1 -1
- package/dist/esm/webgl2/shaders/tile-chunk.frag.js +6 -0
- package/dist/esm/webgl2/shaders/tile-chunk.frag.js.map +1 -0
- package/dist/esm/webgl2/shaders/tile-chunk.vert.js +6 -0
- package/dist/esm/webgl2/shaders/tile-chunk.vert.js.map +1 -0
- package/dist/esm/webgpu/WebGpuTileChunkRenderer.d.ts +70 -4
- package/dist/esm/webgpu/WebGpuTileChunkRenderer.d.ts.map +1 -0
- package/dist/esm/webgpu/WebGpuTileChunkRenderer.js +496 -383
- package/dist/esm/webgpu/WebGpuTileChunkRenderer.js.map +1 -1
- package/dist/esm/webgpu/shaders/tile-chunk.wgsl.js +6 -0
- package/dist/esm/webgpu/shaders/tile-chunk.wgsl.js.map +1 -0
- package/package.json +8 -15
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/register.d.ts +0 -1
- package/dist/esm/register.js +0 -25
- package/dist/esm/register.js.map +0 -1
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import type { ChunkSource } from './ChunkSource';
|
|
2
|
+
import type { TileLayer } from './TileLayer';
|
|
3
|
+
import type { ResolvedTile } from './types';
|
|
4
|
+
/**
|
|
5
|
+
* Options for {@link createSampledChunkSource}.
|
|
6
|
+
* @advanced
|
|
7
|
+
*/
|
|
8
|
+
export interface SampledChunkSourceOptions {
|
|
9
|
+
/**
|
|
10
|
+
* Sample a scalar value at a tile coordinate. Called once per tile within
|
|
11
|
+
* each requested chunk. Must be a pure, deterministic function of
|
|
12
|
+
* `(tx, ty)` - {@link import('./ChunkStreamer').ChunkStreamer} regenerates
|
|
13
|
+
* a chunk from scratch via this source whenever it's revisited after
|
|
14
|
+
* eviction, so a non-deterministic sampler would make previously-visited
|
|
15
|
+
* terrain silently change underneath the player.
|
|
16
|
+
*/
|
|
17
|
+
sample(tx: number, ty: number): number;
|
|
18
|
+
/**
|
|
19
|
+
* Convert a sampled value (and its tile coordinate, for position-dependent
|
|
20
|
+
* logic such as river carving or map edges) into a resolved tile, or
|
|
21
|
+
* `null` for an empty cell. Must be pure and deterministic, same
|
|
22
|
+
* requirement as {@link sample}.
|
|
23
|
+
*/
|
|
24
|
+
mapValueToTile(value: number, tx: number, ty: number): ResolvedTile | null;
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Build a {@link import('./ChunkStreamer').ChunkStreamer}-ready
|
|
28
|
+
* {@link ChunkSource} from a caller-supplied sampling function - the
|
|
29
|
+
* generic mechanism behind procedurally generated tile content (noise,
|
|
30
|
+
* a heightmap, or any other per-tile-coordinate scalar function). This
|
|
31
|
+
* module intentionally has no opinion on the sampling algorithm itself
|
|
32
|
+
* ({@link SampledChunkSourceOptions.sample}/`mapValueToTile` are both
|
|
33
|
+
* required, not defaulted) - pick or write whatever generation function
|
|
34
|
+
* fits your game.
|
|
35
|
+
*
|
|
36
|
+
* `layer` supplies the target chunk grid ({@link TileLayer.chunkWidth}/
|
|
37
|
+
* `chunkHeight`) and the tileset list tiles are packed against
|
|
38
|
+
* ({@link TileLayer.tilesets}) - the same `TileLayer` you'll construct the
|
|
39
|
+
* `ChunkStreamer` with.
|
|
40
|
+
* @advanced
|
|
41
|
+
*/
|
|
42
|
+
export declare const createSampledChunkSource: (layer: TileLayer, options: SampledChunkSourceOptions) => ChunkSource;
|
|
43
|
+
//# sourceMappingURL=SampledChunkSource.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SampledChunkSource.d.ts","sourceRoot":"","sources":["../../src/SampledChunkSource.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAgB,WAAW,EAAE,MAAM,eAAe,CAAC;AAC/D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAG5C;;;GAGG;AACH,MAAM,WAAW,yBAAyB;IACxC;;;;;;;OAOG;IACH,MAAM,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACvC;;;;;OAKG;IACH,cAAc,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,YAAY,GAAG,IAAI,CAAC;CAC5E;AAED;;;;;;;;;;;;;;;GAeG;AACH,eAAO,MAAM,wBAAwB,GAAI,OAAO,SAAS,EAAE,SAAS,yBAAyB,KAAG,WAiC/F,CAAC"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { packTile } from "./types.js";
|
|
2
|
+
|
|
3
|
+
//#region src/SampledChunkSource.ts
|
|
4
|
+
/**
|
|
5
|
+
* Build a {@link import('./ChunkStreamer').ChunkStreamer}-ready
|
|
6
|
+
* {@link ChunkSource} from a caller-supplied sampling function - the
|
|
7
|
+
* generic mechanism behind procedurally generated tile content (noise,
|
|
8
|
+
* a heightmap, or any other per-tile-coordinate scalar function). This
|
|
9
|
+
* module intentionally has no opinion on the sampling algorithm itself
|
|
10
|
+
* ({@link SampledChunkSourceOptions.sample}/`mapValueToTile` are both
|
|
11
|
+
* required, not defaulted) - pick or write whatever generation function
|
|
12
|
+
* fits your game.
|
|
13
|
+
*
|
|
14
|
+
* `layer` supplies the target chunk grid ({@link TileLayer.chunkWidth}/
|
|
15
|
+
* `chunkHeight`) and the tileset list tiles are packed against
|
|
16
|
+
* ({@link TileLayer.tilesets}) - the same `TileLayer` you'll construct the
|
|
17
|
+
* `ChunkStreamer` with.
|
|
18
|
+
* @advanced
|
|
19
|
+
*/
|
|
20
|
+
const createSampledChunkSource = (layer, options) => {
|
|
21
|
+
const sample = options.sample.bind(options);
|
|
22
|
+
const mapValueToTile = options.mapValueToTile.bind(options);
|
|
23
|
+
return { getChunk(cx, cy) {
|
|
24
|
+
const chunkWidth = layer.chunkWidth;
|
|
25
|
+
const chunkHeight = layer.chunkHeight;
|
|
26
|
+
const startTx = cx * chunkWidth;
|
|
27
|
+
const startTy = cy * chunkHeight;
|
|
28
|
+
let out = null;
|
|
29
|
+
for (let ty = startTy; ty < startTy + chunkHeight; ty++) for (let tx = startTx; tx < startTx + chunkWidth; tx++) {
|
|
30
|
+
if (layer.width !== void 0 && layer.height !== void 0 && (tx >= layer.width || ty >= layer.height)) continue;
|
|
31
|
+
const value = sample(tx, ty);
|
|
32
|
+
const resolved = mapValueToTile(value, tx, ty);
|
|
33
|
+
if (!resolved) continue;
|
|
34
|
+
out ??= new Uint32Array(chunkWidth * chunkHeight);
|
|
35
|
+
const tilesetIndex = layer.tilesets.indexOf(resolved.tileset);
|
|
36
|
+
out[(ty - startTy) * chunkWidth + (tx - startTx)] = packTile(tilesetIndex, resolved.localTileId, resolved.transform);
|
|
37
|
+
}
|
|
38
|
+
return out === null ? null : {
|
|
39
|
+
width: chunkWidth,
|
|
40
|
+
height: chunkHeight,
|
|
41
|
+
tiles: out
|
|
42
|
+
};
|
|
43
|
+
} };
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
//#endregion
|
|
47
|
+
export { createSampledChunkSource };
|
|
48
|
+
//# sourceMappingURL=SampledChunkSource.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SampledChunkSource.js","names":[],"sources":["../../src/SampledChunkSource.ts"],"sourcesContent":["import type { ChunkPayload, ChunkSource } from './ChunkSource';\nimport type { TileLayer } from './TileLayer';\nimport type { ResolvedTile } from './types';\nimport { packTile } from './types';\n\n/**\n * Options for {@link createSampledChunkSource}.\n * @advanced\n */\nexport interface SampledChunkSourceOptions {\n /**\n * Sample a scalar value at a tile coordinate. Called once per tile within\n * each requested chunk. Must be a pure, deterministic function of\n * `(tx, ty)` - {@link import('./ChunkStreamer').ChunkStreamer} regenerates\n * a chunk from scratch via this source whenever it's revisited after\n * eviction, so a non-deterministic sampler would make previously-visited\n * terrain silently change underneath the player.\n */\n sample(tx: number, ty: number): number;\n /**\n * Convert a sampled value (and its tile coordinate, for position-dependent\n * logic such as river carving or map edges) into a resolved tile, or\n * `null` for an empty cell. Must be pure and deterministic, same\n * requirement as {@link sample}.\n */\n mapValueToTile(value: number, tx: number, ty: number): ResolvedTile | null;\n}\n\n/**\n * Build a {@link import('./ChunkStreamer').ChunkStreamer}-ready\n * {@link ChunkSource} from a caller-supplied sampling function - the\n * generic mechanism behind procedurally generated tile content (noise,\n * a heightmap, or any other per-tile-coordinate scalar function). This\n * module intentionally has no opinion on the sampling algorithm itself\n * ({@link SampledChunkSourceOptions.sample}/`mapValueToTile` are both\n * required, not defaulted) - pick or write whatever generation function\n * fits your game.\n *\n * `layer` supplies the target chunk grid ({@link TileLayer.chunkWidth}/\n * `chunkHeight`) and the tileset list tiles are packed against\n * ({@link TileLayer.tilesets}) - the same `TileLayer` you'll construct the\n * `ChunkStreamer` with.\n * @advanced\n */\nexport const createSampledChunkSource = (layer: TileLayer, options: SampledChunkSourceOptions): ChunkSource => {\n const sample = options.sample.bind(options);\n const mapValueToTile = options.mapValueToTile.bind(options);\n\n return {\n getChunk(cx: number, cy: number): ChunkPayload | null {\n const chunkWidth = layer.chunkWidth;\n const chunkHeight = layer.chunkHeight;\n const startTx = cx * chunkWidth;\n const startTy = cy * chunkHeight;\n\n let out: Uint32Array | null = null;\n for (let ty = startTy; ty < startTy + chunkHeight; ty++) {\n for (let tx = startTx; tx < startTx + chunkWidth; tx++) {\n // Bounded-layer edge chunks may be smaller than a full chunk\n // (TileLayer._ensureChunk clamps them); this provider always\n // samples a full chunk rect, so clamp here instead of letting\n // _adoptChunk over-report tiles past the layer's declared bounds.\n if (layer.width !== undefined && layer.height !== undefined && (tx >= layer.width || ty >= layer.height)) continue;\n\n const value = sample(tx, ty);\n const resolved = mapValueToTile(value, tx, ty);\n if (!resolved) continue;\n\n out ??= new Uint32Array(chunkWidth * chunkHeight);\n const tilesetIndex = layer.tilesets.indexOf(resolved.tileset);\n out[(ty - startTy) * chunkWidth + (tx - startTx)] = packTile(tilesetIndex, resolved.localTileId, resolved.transform);\n }\n }\n\n return out === null ? null : { width: chunkWidth, height: chunkHeight, tiles: out };\n },\n };\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;AA4CA,MAAa,4BAA4B,OAAkB,YAAoD;CAC7G,MAAM,SAAS,QAAQ,OAAO,KAAK,OAAO;CAC1C,MAAM,iBAAiB,QAAQ,eAAe,KAAK,OAAO;CAE1D,OAAO,EACL,SAAS,IAAY,IAAiC;EACpD,MAAM,aAAa,MAAM;EACzB,MAAM,cAAc,MAAM;EAC1B,MAAM,UAAU,KAAK;EACrB,MAAM,UAAU,KAAK;EAErB,IAAI,MAA0B;EAC9B,KAAK,IAAI,KAAK,SAAS,KAAK,UAAU,aAAa,MACjD,KAAK,IAAI,KAAK,SAAS,KAAK,UAAU,YAAY,MAAM;GAKtD,IAAI,MAAM,UAAU,UAAa,MAAM,WAAW,WAAc,MAAM,MAAM,SAAS,MAAM,MAAM,SAAS;GAE1G,MAAM,QAAQ,OAAO,IAAI,EAAE;GAC3B,MAAM,WAAW,eAAe,OAAO,IAAI,EAAE;GAC7C,IAAI,CAAC,UAAU;GAEf,QAAQ,IAAI,YAAY,aAAa,WAAW;GAChD,MAAM,eAAe,MAAM,SAAS,QAAQ,SAAS,OAAO;GAC5D,KAAK,KAAK,WAAW,cAAc,KAAK,YAAY,SAAS,cAAc,SAAS,aAAa,SAAS,SAAS;EACrH;EAGF,OAAO,QAAQ,OAAO,OAAO;GAAE,OAAO;GAAY,QAAQ;GAAa,OAAO;EAAI;CACpF,EACF;AACF"}
|
|
@@ -5,12 +5,21 @@ import type { TileLayer } from './TileLayer';
|
|
|
5
5
|
* On construction it scans the given layer(s) once and registers every cell
|
|
6
6
|
* whose tile carries an `animation` (see {@link import('./types').TileDefinition}).
|
|
7
7
|
* Each {@link update} advances a shared clock and rewrites **only** the
|
|
8
|
-
* registered animated cells, and **only** when a cell crosses a frame boundary
|
|
8
|
+
* registered animated cells, and **only** when a cell crosses a frame boundary -
|
|
9
9
|
* static tiles are never touched. Because a tile rewrite goes through
|
|
10
10
|
* `layer.setTileAt`, only the chunks that actually contain animated cells rebuild
|
|
11
11
|
* their geometry, and only on the (infrequent) frames where a boundary is
|
|
12
12
|
* crossed. The large static body of the map never rebuilds.
|
|
13
13
|
*
|
|
14
|
+
* An unbounded {@link import('./TileLayer').TileLayer} (see
|
|
15
|
+
* {@link import('./TileLayer').TileLayer.bounded}) is skipped entirely by
|
|
16
|
+
* the initial scan and reports zero animated cells for that layer, rather
|
|
17
|
+
* than sweeping every ever-loaded chunk. Streaming/procedural chunk
|
|
18
|
+
* providers that need animated tiles must drive per-chunk `TileAnimator`
|
|
19
|
+
* instances themselves (scanning only the newly-adopted chunk's tile
|
|
20
|
+
* range) - a whole-layer `TileAnimator` is not currently wired to react to
|
|
21
|
+
* chunk load/unload.
|
|
22
|
+
*
|
|
14
23
|
* Tick it from your update loop, like `TweenSequencer`:
|
|
15
24
|
*
|
|
16
25
|
* ```ts
|
|
@@ -18,7 +27,7 @@ import type { TileLayer } from './TileLayer';
|
|
|
18
27
|
* scene.systems.add({ update: (t) => animator.update(t.deltaSeconds) });
|
|
19
28
|
* ```
|
|
20
29
|
*
|
|
21
|
-
* The animator references
|
|
30
|
+
* The animator references - but never owns - the layers and their tilesets;
|
|
22
31
|
* {@link destroy} only drops its own cell registry.
|
|
23
32
|
*
|
|
24
33
|
* @advanced
|
|
@@ -60,3 +69,4 @@ export declare class TileAnimator {
|
|
|
60
69
|
/** Scan all layers for cells whose tile carries a (multi-frame) animation. */
|
|
61
70
|
private _scan;
|
|
62
71
|
}
|
|
72
|
+
//# sourceMappingURL=TileAnimator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TileAnimator.d.ts","sourceRoot":"","sources":["../../src/TileAnimator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAmB7C;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAuB;IAC/C,OAAO,CAAC,MAAM,CAAsB;IACpC,OAAO,CAAC,UAAU,CAAK;IAEvB;;;OAGG;gBACgB,MAAM,EAAE,SAAS,GAAG,SAAS,SAAS,EAAE;IAK3D,uEAAuE;IACvE,IAAW,iBAAiB,IAAI,MAAM,CAErC;IAED,6EAA6E;IAC7E,IAAW,SAAS,IAAI,MAAM,CAE7B;IAED;;;;;;OAMG;IACI,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,IAAI;IA0BzC;;;OAGG;IACI,KAAK,IAAI,IAAI;IAgBpB;;;;OAIG;IACI,MAAM,IAAI,IAAI;IAKrB,sEAAsE;IAC/D,OAAO,IAAI,IAAI;IAKtB,8EAA8E;IAC9E,OAAO,CAAC,KAAK;CAqDd"}
|
package/dist/esm/TileAnimator.js
CHANGED
|
@@ -1,169 +1,158 @@
|
|
|
1
|
+
//#region src/TileAnimator.ts
|
|
1
2
|
/**
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
frames,
|
|
144
|
-
cumulative,
|
|
145
|
-
totalMs: total,
|
|
146
|
-
currentFrame: -1,
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
this._cells = cells;
|
|
152
|
-
}
|
|
153
|
-
}
|
|
3
|
+
* Drives per-tile animations on one or more {@link TileLayer}s, RPG-Maker style.
|
|
4
|
+
*
|
|
5
|
+
* On construction it scans the given layer(s) once and registers every cell
|
|
6
|
+
* whose tile carries an `animation` (see {@link import('./types').TileDefinition}).
|
|
7
|
+
* Each {@link update} advances a shared clock and rewrites **only** the
|
|
8
|
+
* registered animated cells, and **only** when a cell crosses a frame boundary -
|
|
9
|
+
* static tiles are never touched. Because a tile rewrite goes through
|
|
10
|
+
* `layer.setTileAt`, only the chunks that actually contain animated cells rebuild
|
|
11
|
+
* their geometry, and only on the (infrequent) frames where a boundary is
|
|
12
|
+
* crossed. The large static body of the map never rebuilds.
|
|
13
|
+
*
|
|
14
|
+
* An unbounded {@link import('./TileLayer').TileLayer} (see
|
|
15
|
+
* {@link import('./TileLayer').TileLayer.bounded}) is skipped entirely by
|
|
16
|
+
* the initial scan and reports zero animated cells for that layer, rather
|
|
17
|
+
* than sweeping every ever-loaded chunk. Streaming/procedural chunk
|
|
18
|
+
* providers that need animated tiles must drive per-chunk `TileAnimator`
|
|
19
|
+
* instances themselves (scanning only the newly-adopted chunk's tile
|
|
20
|
+
* range) - a whole-layer `TileAnimator` is not currently wired to react to
|
|
21
|
+
* chunk load/unload.
|
|
22
|
+
*
|
|
23
|
+
* Tick it from your update loop, like `TweenSequencer`:
|
|
24
|
+
*
|
|
25
|
+
* ```ts
|
|
26
|
+
* const animator = new TileAnimator(map.layers);
|
|
27
|
+
* scene.systems.add({ update: (t) => animator.update(t.deltaSeconds) });
|
|
28
|
+
* ```
|
|
29
|
+
*
|
|
30
|
+
* The animator references - but never owns - the layers and their tilesets;
|
|
31
|
+
* {@link destroy} only drops its own cell registry.
|
|
32
|
+
*
|
|
33
|
+
* @advanced
|
|
34
|
+
*/
|
|
35
|
+
var TileAnimator = class {
|
|
36
|
+
_layers;
|
|
37
|
+
_cells = [];
|
|
38
|
+
_elapsedMs = 0;
|
|
39
|
+
/**
|
|
40
|
+
* @param layers One layer, or an array of layers (e.g. `map.layers`), to scan
|
|
41
|
+
* for animated tiles.
|
|
42
|
+
*/
|
|
43
|
+
constructor(layers) {
|
|
44
|
+
this._layers = Array.isArray(layers) ? layers : [layers];
|
|
45
|
+
this._scan();
|
|
46
|
+
}
|
|
47
|
+
/** Number of animated cells currently registered across all layers. */
|
|
48
|
+
get animatedCellCount() {
|
|
49
|
+
return this._cells.length;
|
|
50
|
+
}
|
|
51
|
+
/** Total elapsed animation time in milliseconds since construction/reset. */
|
|
52
|
+
get elapsedMs() {
|
|
53
|
+
return this._elapsedMs;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Advance all registered animations by `deltaSeconds` and write the current
|
|
57
|
+
* frame into any cell that crossed a frame boundary. Cells that did not change
|
|
58
|
+
* frame are not touched, so their chunks do not rebuild.
|
|
59
|
+
*
|
|
60
|
+
* @param deltaSeconds Elapsed wall-clock time since the last call, in seconds.
|
|
61
|
+
*/
|
|
62
|
+
update(deltaSeconds) {
|
|
63
|
+
if (!Number.isFinite(deltaSeconds) || deltaSeconds <= 0 || this._cells.length === 0) return;
|
|
64
|
+
this._elapsedMs += deltaSeconds * 1e3;
|
|
65
|
+
for (const cell of this._cells) {
|
|
66
|
+
const t = this._elapsedMs % cell.totalMs;
|
|
67
|
+
const frameIndex = frameIndexAt(cell.cumulative, t);
|
|
68
|
+
if (frameIndex === cell.currentFrame) continue;
|
|
69
|
+
cell.currentFrame = frameIndex;
|
|
70
|
+
const frame = cell.frames[frameIndex];
|
|
71
|
+
if (frame === void 0) continue;
|
|
72
|
+
cell.layer.setTileAt(cell.tx, cell.ty, {
|
|
73
|
+
tileset: cell.tileset,
|
|
74
|
+
localTileId: frame.localTileId,
|
|
75
|
+
transform: cell.transform
|
|
76
|
+
});
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Restore every animated cell to its first frame and reset the clock.
|
|
81
|
+
* Useful before serialising or pausing.
|
|
82
|
+
*/
|
|
83
|
+
reset() {
|
|
84
|
+
this._elapsedMs = 0;
|
|
85
|
+
for (const cell of this._cells) {
|
|
86
|
+
const frame = cell.frames[0];
|
|
87
|
+
if (frame === void 0) continue;
|
|
88
|
+
cell.currentFrame = 0;
|
|
89
|
+
cell.layer.setTileAt(cell.tx, cell.ty, {
|
|
90
|
+
tileset: cell.tileset,
|
|
91
|
+
localTileId: frame.localTileId,
|
|
92
|
+
transform: cell.transform
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Re-scan the layers for animated cells. Call after structural edits that add
|
|
98
|
+
* or remove animated tiles. Resets all currently-tracked cells to frame 0
|
|
99
|
+
* first so the rescan starts from a clean, deterministic state.
|
|
100
|
+
*/
|
|
101
|
+
rescan() {
|
|
102
|
+
this.reset();
|
|
103
|
+
this._scan();
|
|
104
|
+
}
|
|
105
|
+
/** Drop the cell registry. Does not modify the layers or tilesets. */
|
|
106
|
+
destroy() {
|
|
107
|
+
this._cells = [];
|
|
108
|
+
this._elapsedMs = 0;
|
|
109
|
+
}
|
|
110
|
+
/** Scan all layers for cells whose tile carries a (multi-frame) animation. */
|
|
111
|
+
_scan() {
|
|
112
|
+
const cells = [];
|
|
113
|
+
for (const layer of this._layers) {
|
|
114
|
+
if (layer.width === void 0 || layer.height === void 0) continue;
|
|
115
|
+
for (let ty = 0; ty < layer.height; ty++) for (let tx = 0; tx < layer.width; tx++) {
|
|
116
|
+
const tile = layer.getTileAt(tx, ty);
|
|
117
|
+
if (!tile) continue;
|
|
118
|
+
const frames = tile.tileset.getTileDefinition(tile.localTileId)?.animation;
|
|
119
|
+
if (!frames || frames.length < 2) continue;
|
|
120
|
+
if (frames.some((f) => f.localTileId < 0 || f.localTileId >= tile.tileset.tileCount)) continue;
|
|
121
|
+
const cumulative = [];
|
|
122
|
+
let total = 0;
|
|
123
|
+
for (const frame of frames) {
|
|
124
|
+
total += Math.max(0, frame.duration);
|
|
125
|
+
cumulative.push(total);
|
|
126
|
+
}
|
|
127
|
+
if (total <= 0) continue;
|
|
128
|
+
cells.push({
|
|
129
|
+
layer,
|
|
130
|
+
tx,
|
|
131
|
+
ty,
|
|
132
|
+
tileset: tile.tileset,
|
|
133
|
+
transform: tile.transform,
|
|
134
|
+
frames,
|
|
135
|
+
cumulative,
|
|
136
|
+
totalMs: total,
|
|
137
|
+
currentFrame: -1
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
this._cells = cells;
|
|
142
|
+
}
|
|
143
|
+
};
|
|
154
144
|
/**
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
return cumulative.length - 1;
|
|
166
|
-
}
|
|
145
|
+
* Find the frame index whose cumulative window contains time `t` (0 ≤ t < total).
|
|
146
|
+
* `cumulative[i]` is the end time of frame `i`; the last entry equals the total.
|
|
147
|
+
*/
|
|
148
|
+
const frameIndexAt = (cumulative, t) => {
|
|
149
|
+
for (let i = 0; i < cumulative.length; i++) {
|
|
150
|
+
const end = cumulative[i];
|
|
151
|
+
if (end !== void 0 && t < end) return i;
|
|
152
|
+
}
|
|
153
|
+
return cumulative.length - 1;
|
|
154
|
+
};
|
|
167
155
|
|
|
156
|
+
//#endregion
|
|
168
157
|
export { TileAnimator };
|
|
169
|
-
//# sourceMappingURL=TileAnimator.js.map
|
|
158
|
+
//# sourceMappingURL=TileAnimator.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"TileAnimator.js","sources":["
|
|
1
|
+
{"version":3,"file":"TileAnimator.js","names":[],"sources":["../../src/TileAnimator.ts"],"sourcesContent":["import type { TileLayer } from './TileLayer';\nimport type { TileSet } from './TileSet';\nimport type { TileAnimationFrame, TileTransform } from './types';\n\n/** Internal per-cell animation record. */\ninterface AnimatedCell {\n readonly layer: TileLayer;\n readonly tx: number;\n readonly ty: number;\n readonly tileset: TileSet;\n readonly transform: TileTransform;\n readonly frames: readonly TileAnimationFrame[];\n /** Cumulative end-time (ms) of each frame, so `cumulative.at(-1) === totalMs`. */\n readonly cumulative: readonly number[];\n readonly totalMs: number;\n /** Index of the frame currently written into the layer (-1 = none yet). */\n currentFrame: number;\n}\n\n/**\n * Drives per-tile animations on one or more {@link TileLayer}s, RPG-Maker style.\n *\n * On construction it scans the given layer(s) once and registers every cell\n * whose tile carries an `animation` (see {@link import('./types').TileDefinition}).\n * Each {@link update} advances a shared clock and rewrites **only** the\n * registered animated cells, and **only** when a cell crosses a frame boundary -\n * static tiles are never touched. Because a tile rewrite goes through\n * `layer.setTileAt`, only the chunks that actually contain animated cells rebuild\n * their geometry, and only on the (infrequent) frames where a boundary is\n * crossed. The large static body of the map never rebuilds.\n *\n * An unbounded {@link import('./TileLayer').TileLayer} (see\n * {@link import('./TileLayer').TileLayer.bounded}) is skipped entirely by\n * the initial scan and reports zero animated cells for that layer, rather\n * than sweeping every ever-loaded chunk. Streaming/procedural chunk\n * providers that need animated tiles must drive per-chunk `TileAnimator`\n * instances themselves (scanning only the newly-adopted chunk's tile\n * range) - a whole-layer `TileAnimator` is not currently wired to react to\n * chunk load/unload.\n *\n * Tick it from your update loop, like `TweenSequencer`:\n *\n * ```ts\n * const animator = new TileAnimator(map.layers);\n * scene.systems.add({ update: (t) => animator.update(t.deltaSeconds) });\n * ```\n *\n * The animator references - but never owns - the layers and their tilesets;\n * {@link destroy} only drops its own cell registry.\n *\n * @advanced\n */\nexport class TileAnimator {\n private readonly _layers: readonly TileLayer[];\n private _cells: AnimatedCell[] = [];\n private _elapsedMs = 0;\n\n /**\n * @param layers One layer, or an array of layers (e.g. `map.layers`), to scan\n * for animated tiles.\n */\n public constructor(layers: TileLayer | readonly TileLayer[]) {\n this._layers = Array.isArray(layers) ? layers : [layers as TileLayer];\n this._scan();\n }\n\n /** Number of animated cells currently registered across all layers. */\n public get animatedCellCount(): number {\n return this._cells.length;\n }\n\n /** Total elapsed animation time in milliseconds since construction/reset. */\n public get elapsedMs(): number {\n return this._elapsedMs;\n }\n\n /**\n * Advance all registered animations by `deltaSeconds` and write the current\n * frame into any cell that crossed a frame boundary. Cells that did not change\n * frame are not touched, so their chunks do not rebuild.\n *\n * @param deltaSeconds Elapsed wall-clock time since the last call, in seconds.\n */\n public update(deltaSeconds: number): void {\n if (!Number.isFinite(deltaSeconds) || deltaSeconds <= 0 || this._cells.length === 0) {\n return;\n }\n\n this._elapsedMs += deltaSeconds * 1000;\n\n for (const cell of this._cells) {\n const t = this._elapsedMs % cell.totalMs;\n const frameIndex = frameIndexAt(cell.cumulative, t);\n if (frameIndex === cell.currentFrame) {\n continue;\n }\n cell.currentFrame = frameIndex;\n const frame = cell.frames[frameIndex];\n if (frame === undefined) {\n continue;\n }\n cell.layer.setTileAt(cell.tx, cell.ty, {\n tileset: cell.tileset,\n localTileId: frame.localTileId,\n transform: cell.transform,\n });\n }\n }\n\n /**\n * Restore every animated cell to its first frame and reset the clock.\n * Useful before serialising or pausing.\n */\n public reset(): void {\n this._elapsedMs = 0;\n for (const cell of this._cells) {\n const frame = cell.frames[0];\n if (frame === undefined) {\n continue;\n }\n cell.currentFrame = 0;\n cell.layer.setTileAt(cell.tx, cell.ty, {\n tileset: cell.tileset,\n localTileId: frame.localTileId,\n transform: cell.transform,\n });\n }\n }\n\n /**\n * Re-scan the layers for animated cells. Call after structural edits that add\n * or remove animated tiles. Resets all currently-tracked cells to frame 0\n * first so the rescan starts from a clean, deterministic state.\n */\n public rescan(): void {\n this.reset();\n this._scan();\n }\n\n /** Drop the cell registry. Does not modify the layers or tilesets. */\n public destroy(): void {\n this._cells = [];\n this._elapsedMs = 0;\n }\n\n /** Scan all layers for cells whose tile carries a (multi-frame) animation. */\n private _scan(): void {\n const cells: AnimatedCell[] = [];\n\n for (const layer of this._layers) {\n if (layer.width === undefined || layer.height === undefined) {\n continue; // unbounded layers are not scanned in v1 — see class doc comment.\n }\n for (let ty = 0; ty < layer.height; ty++) {\n for (let tx = 0; tx < layer.width; tx++) {\n const tile = layer.getTileAt(tx, ty);\n if (!tile) {\n continue;\n }\n\n const def = tile.tileset.getTileDefinition(tile.localTileId);\n const frames = def?.animation;\n if (!frames || frames.length < 2) {\n continue;\n }\n\n // Skip animations referencing out-of-range frames so update() never\n // throws from setTileAt; such data is malformed and silently ignored.\n if (frames.some(f => f.localTileId < 0 || f.localTileId >= tile.tileset.tileCount)) {\n continue;\n }\n\n const cumulative: number[] = [];\n let total = 0;\n for (const frame of frames) {\n total += Math.max(0, frame.duration);\n cumulative.push(total);\n }\n if (total <= 0) {\n continue;\n }\n\n cells.push({\n layer,\n tx,\n ty,\n tileset: tile.tileset,\n transform: tile.transform,\n frames,\n cumulative,\n totalMs: total,\n currentFrame: -1,\n });\n }\n }\n }\n\n this._cells = cells;\n }\n}\n\n/**\n * Find the frame index whose cumulative window contains time `t` (0 ≤ t < total).\n * `cumulative[i]` is the end time of frame `i`; the last entry equals the total.\n */\nconst frameIndexAt = (cumulative: readonly number[], t: number): number => {\n for (let i = 0; i < cumulative.length; i++) {\n const end = cumulative[i];\n if (end !== undefined && t < end) {\n return i;\n }\n }\n return cumulative.length - 1;\n};\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoDA,IAAa,eAAb,MAA0B;CACxB,AAAiB;CACjB,AAAQ,SAAyB,CAAC;CAClC,AAAQ,aAAa;;;;;CAMrB,AAAO,YAAY,QAA0C;EAC3D,KAAK,UAAU,MAAM,QAAQ,MAAM,IAAI,SAAS,CAAC,MAAmB;EACpE,KAAK,MAAM;CACb;;CAGA,IAAW,oBAA4B;EACrC,OAAO,KAAK,OAAO;CACrB;;CAGA,IAAW,YAAoB;EAC7B,OAAO,KAAK;CACd;;;;;;;;CASA,AAAO,OAAO,cAA4B;EACxC,IAAI,CAAC,OAAO,SAAS,YAAY,KAAK,gBAAgB,KAAK,KAAK,OAAO,WAAW,GAChF;EAGF,KAAK,cAAc,eAAe;EAElC,KAAK,MAAM,QAAQ,KAAK,QAAQ;GAC9B,MAAM,IAAI,KAAK,aAAa,KAAK;GACjC,MAAM,aAAa,aAAa,KAAK,YAAY,CAAC;GAClD,IAAI,eAAe,KAAK,cACtB;GAEF,KAAK,eAAe;GACpB,MAAM,QAAQ,KAAK,OAAO;GAC1B,IAAI,UAAU,QACZ;GAEF,KAAK,MAAM,UAAU,KAAK,IAAI,KAAK,IAAI;IACrC,SAAS,KAAK;IACd,aAAa,MAAM;IACnB,WAAW,KAAK;GAClB,CAAC;EACH;CACF;;;;;CAMA,AAAO,QAAc;EACnB,KAAK,aAAa;EAClB,KAAK,MAAM,QAAQ,KAAK,QAAQ;GAC9B,MAAM,QAAQ,KAAK,OAAO;GAC1B,IAAI,UAAU,QACZ;GAEF,KAAK,eAAe;GACpB,KAAK,MAAM,UAAU,KAAK,IAAI,KAAK,IAAI;IACrC,SAAS,KAAK;IACd,aAAa,MAAM;IACnB,WAAW,KAAK;GAClB,CAAC;EACH;CACF;;;;;;CAOA,AAAO,SAAe;EACpB,KAAK,MAAM;EACX,KAAK,MAAM;CACb;;CAGA,AAAO,UAAgB;EACrB,KAAK,SAAS,CAAC;EACf,KAAK,aAAa;CACpB;;CAGA,AAAQ,QAAc;EACpB,MAAM,QAAwB,CAAC;EAE/B,KAAK,MAAM,SAAS,KAAK,SAAS;GAChC,IAAI,MAAM,UAAU,UAAa,MAAM,WAAW,QAChD;GAEF,KAAK,IAAI,KAAK,GAAG,KAAK,MAAM,QAAQ,MAClC,KAAK,IAAI,KAAK,GAAG,KAAK,MAAM,OAAO,MAAM;IACvC,MAAM,OAAO,MAAM,UAAU,IAAI,EAAE;IACnC,IAAI,CAAC,MACH;IAIF,MAAM,SADM,KAAK,QAAQ,kBAAkB,KAAK,WAC/B,CAAC,EAAE;IACpB,IAAI,CAAC,UAAU,OAAO,SAAS,GAC7B;IAKF,IAAI,OAAO,MAAK,MAAK,EAAE,cAAc,KAAK,EAAE,eAAe,KAAK,QAAQ,SAAS,GAC/E;IAGF,MAAM,aAAuB,CAAC;IAC9B,IAAI,QAAQ;IACZ,KAAK,MAAM,SAAS,QAAQ;KAC1B,SAAS,KAAK,IAAI,GAAG,MAAM,QAAQ;KACnC,WAAW,KAAK,KAAK;IACvB;IACA,IAAI,SAAS,GACX;IAGF,MAAM,KAAK;KACT;KACA;KACA;KACA,SAAS,KAAK;KACd,WAAW,KAAK;KAChB;KACA;KACA,SAAS;KACT,cAAc;IAChB,CAAC;GACH;EAEJ;EAEA,KAAK,SAAS;CAChB;AACF;;;;;AAMA,MAAM,gBAAgB,YAA+B,MAAsB;CACzE,KAAK,IAAI,IAAI,GAAG,IAAI,WAAW,QAAQ,KAAK;EAC1C,MAAM,MAAM,WAAW;EACvB,IAAI,QAAQ,UAAa,IAAI,KAC3B,OAAO;CAEX;CACA,OAAO,WAAW,SAAS;AAC7B"}
|
package/dist/esm/TileChunk.d.ts
CHANGED
|
@@ -42,7 +42,7 @@ export interface ReadonlyTileChunk {
|
|
|
42
42
|
* laid out row-major. Each cell is a packed tile word (0 = empty).
|
|
43
43
|
* Chunk coordinates are signed to support future infinite maps.
|
|
44
44
|
*
|
|
45
|
-
* The backing array is **private**
|
|
45
|
+
* The backing array is **private** - external code cannot mutate storage
|
|
46
46
|
* directly. All mutation must flow through {@link TileLayer} public APIs,
|
|
47
47
|
* which call the package-internal `_setRawAt` method.
|
|
48
48
|
*
|
|
@@ -60,12 +60,21 @@ export declare class TileChunk implements ReadonlyTileChunk {
|
|
|
60
60
|
readonly width: number;
|
|
61
61
|
/** Height of this chunk in tiles. */
|
|
62
62
|
readonly height: number;
|
|
63
|
-
/** Packed tile storage (row-major). Private
|
|
63
|
+
/** Packed tile storage (row-major). Private - never exposed directly. */
|
|
64
64
|
private readonly _tiles;
|
|
65
65
|
/** Whether every cell in this chunk is empty (0). Lazy-computed. */
|
|
66
66
|
private _empty;
|
|
67
|
-
/** Monotonic revision counter
|
|
67
|
+
/** Monotonic revision counter - incremented on every mutation. */
|
|
68
68
|
private _revision;
|
|
69
|
+
/**
|
|
70
|
+
* Render-node-owned callbacks notified whenever `_revision` advances.
|
|
71
|
+
* `TileChunkNode.pages` caches geometry against `revision`, but that cache
|
|
72
|
+
* is only consulted from `render()` - a call the engine skips entirely for
|
|
73
|
+
* a content-clean subtree under a `RetainedContainer`. Without
|
|
74
|
+
* this push, an in-place tile edit after capture would replay stale cached
|
|
75
|
+
* geometry forever. Package-internal; not part of {@link ReadonlyTileChunk}.
|
|
76
|
+
*/
|
|
77
|
+
private _dirtyListeners;
|
|
69
78
|
/**
|
|
70
79
|
* @param cx Signed chunk X coordinate (must be finite safe integer).
|
|
71
80
|
* @param cy Signed chunk Y coordinate (must be finite safe integer).
|
|
@@ -91,7 +100,7 @@ export declare class TileChunk implements ReadonlyTileChunk {
|
|
|
91
100
|
cloneTiles(): Uint32Array;
|
|
92
101
|
/**
|
|
93
102
|
* Package-internal access to the underlying tile storage.
|
|
94
|
-
* Returns the actual mutable `Uint32Array`
|
|
103
|
+
* Returns the actual mutable `Uint32Array` - DO NOT USE publicly.
|
|
95
104
|
*
|
|
96
105
|
* Provided for the future tilemap renderer (same package) so it can
|
|
97
106
|
* read chunk data efficiently without a full `cloneTiles()` copy per frame.
|
|
@@ -102,7 +111,7 @@ export declare class TileChunk implements ReadonlyTileChunk {
|
|
|
102
111
|
_getRawStorage(): Uint32Array;
|
|
103
112
|
/**
|
|
104
113
|
* Validate a packed tile value before storing.
|
|
105
|
-
* Accepts any finite integer
|
|
114
|
+
* Accepts any finite integer - `Uint32Array` stores via unsigned 32-bit
|
|
106
115
|
* truncation (`ToUint32`). Negative values produced by JavaScript's
|
|
107
116
|
* signed bitwise ops (e.g. when the transform bits set bit 31) are valid.
|
|
108
117
|
* @throws If the value is NaN, Infinity, or non-integer.
|
|
@@ -133,4 +142,20 @@ export declare class TileChunk implements ReadonlyTileChunk {
|
|
|
133
142
|
* @internal
|
|
134
143
|
*/
|
|
135
144
|
_clear(): void;
|
|
145
|
+
/**
|
|
146
|
+
* Register a callback invoked synchronously whenever this chunk's revision
|
|
147
|
+
* advances. Multiple listeners are supported (a chunk may back more than one
|
|
148
|
+
* `TileChunkNode` - e.g. two `TileLayerNode`s over the same `TileLayer`).
|
|
149
|
+
* Package-internal: called by `TileChunkNode` to push mutations onto the
|
|
150
|
+
* scene-node content-revision chain (see the `_dirtyListeners` field).
|
|
151
|
+
* @internal
|
|
152
|
+
*/
|
|
153
|
+
_addDirtyListener(listener: () => void): void;
|
|
154
|
+
/**
|
|
155
|
+
* Unregister a listener added via {@link _addDirtyListener} (node destroy).
|
|
156
|
+
* @internal
|
|
157
|
+
*/
|
|
158
|
+
_removeDirtyListener(listener: () => void): void;
|
|
159
|
+
private _notifyDirty;
|
|
136
160
|
}
|
|
161
|
+
//# sourceMappingURL=TileChunk.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TileChunk.d.ts","sourceRoot":"","sources":["../../src/TileChunk.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAG1C;;;;;;;GAOG;AACH,MAAM,WAAW,iBAAiB;IAChC,iCAAiC;IACjC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,iCAAiC;IACjC,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,oCAAoC;IACpC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,qCAAqC;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,8CAA8C;IAC9C,QAAQ,CAAC,KAAK,EAAE,OAAO,CAAC;IACxB;;;OAGG;IACH,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAE1B;;;;OAIG;IACH,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,UAAU,CAAC;IAE7C;;;OAGG;IACH,UAAU,IAAI,WAAW,CAAC;CAC3B;AAED;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,SAAU,YAAW,iBAAiB;IACjD,iCAAiC;IACjC,SAAgB,EAAE,EAAE,MAAM,CAAC;IAC3B,iCAAiC;IACjC,SAAgB,EAAE,EAAE,MAAM,CAAC;IAE3B,oCAAoC;IACpC,SAAgB,KAAK,EAAE,MAAM,CAAC;IAC9B,qCAAqC;IACrC,SAAgB,MAAM,EAAE,MAAM,CAAC;IAE/B,yEAAyE;IACzE,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IAErC,oEAAoE;IACpE,OAAO,CAAC,MAAM,CAAwB;IAEtC,kEAAkE;IAClE,OAAO,CAAC,SAAS,CAAK;IAEtB;;;;;;;OAOG;IACH,OAAO,CAAC,eAAe,CAAgC;IAEvD;;;;;;OAMG;gBACgB,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,WAAW;IA0C9F,2DAA2D;IAC3D,OAAO,CAAC,MAAM;IAId;;;OAGG;IACH,OAAO,CAAC,mBAAmB;IAa3B,kBAAkB;IACX,QAAQ,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,GAAG,UAAU;IAKnD,kBAAkB;IAClB,IAAW,KAAK,IAAI,OAAO,CAK1B;IAED,kBAAkB;IAClB,IAAW,QAAQ,IAAI,MAAM,CAE5B;IAED,kBAAkB;IACX,UAAU,IAAI,WAAW;IAMhC;;;;;;;;;OASG;IACI,cAAc,IAAI,WAAW;IAIpC;;;;;;;OAOG;IACH,OAAO,CAAC,eAAe;IAMvB;;;;;;OAMG;IACI,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,EAAE,UAAU,GAAG,OAAO;IAarE;;;;;;OAMG;IACI,UAAU,IAAI,IAAI;IAMzB;;;;;;OAMG;IACI,MAAM,IAAI,IAAI;IASrB;;;;;;;OAOG;IACI,iBAAiB,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI;IAIpD;;;OAGG;IACI,oBAAoB,CAAC,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI;IAIvD,OAAO,CAAC,YAAY;CAMrB"}
|