@codexo/exojs-tilemap 0.13.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/LICENSE +21 -0
- package/README.md +187 -0
- package/dist/esm/TileChunk.d.ts +136 -0
- package/dist/esm/TileChunk.js +192 -0
- package/dist/esm/TileChunk.js.map +1 -0
- package/dist/esm/TileChunkNode.d.ts +59 -0
- package/dist/esm/TileChunkNode.js +89 -0
- package/dist/esm/TileChunkNode.js.map +1 -0
- package/dist/esm/TileLayer.d.ts +229 -0
- package/dist/esm/TileLayer.js +450 -0
- package/dist/esm/TileLayer.js.map +1 -0
- package/dist/esm/TileLayerNode.d.ts +81 -0
- package/dist/esm/TileLayerNode.js +142 -0
- package/dist/esm/TileLayerNode.js.map +1 -0
- package/dist/esm/TileMap.d.ts +178 -0
- package/dist/esm/TileMap.js +262 -0
- package/dist/esm/TileMap.js.map +1 -0
- package/dist/esm/TileMapBand.d.ts +97 -0
- package/dist/esm/TileMapBand.js +161 -0
- package/dist/esm/TileMapBand.js.map +1 -0
- package/dist/esm/TileMapNode.d.ts +71 -0
- package/dist/esm/TileMapNode.js +113 -0
- package/dist/esm/TileMapNode.js.map +1 -0
- package/dist/esm/TileMapView.d.ts +182 -0
- package/dist/esm/TileMapView.js +342 -0
- package/dist/esm/TileMapView.js.map +1 -0
- package/dist/esm/TileSet.d.ts +99 -0
- package/dist/esm/TileSet.js +157 -0
- package/dist/esm/TileSet.js.map +1 -0
- package/dist/esm/chunkGeometry.d.ts +71 -0
- package/dist/esm/chunkGeometry.js +98 -0
- package/dist/esm/chunkGeometry.js.map +1 -0
- package/dist/esm/index.d.ts +1 -0
- package/dist/esm/index.js +10 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/pixelSnap.d.ts +12 -0
- package/dist/esm/pixelSnap.js +19 -0
- package/dist/esm/pixelSnap.js.map +1 -0
- package/dist/esm/public.d.ts +18 -0
- package/dist/esm/register.d.ts +1 -0
- package/dist/esm/register.js +20 -0
- package/dist/esm/register.js.map +1 -0
- package/dist/esm/tilemapExtension.d.ts +18 -0
- package/dist/esm/tilemapExtension.js +52 -0
- package/dist/esm/tilemapExtension.js.map +1 -0
- package/dist/esm/types.d.ts +139 -0
- package/dist/esm/types.js +121 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/esm/webgl2/WebGl2TileChunkRenderer.d.ts +39 -0
- package/dist/esm/webgl2/WebGl2TileChunkRenderer.js +339 -0
- package/dist/esm/webgl2/WebGl2TileChunkRenderer.js.map +1 -0
- package/dist/esm/webgpu/WebGpuTileChunkRenderer.d.ts +42 -0
- package/dist/esm/webgpu/WebGpuTileChunkRenderer.js +390 -0
- package/dist/esm/webgpu/WebGpuTileChunkRenderer.js.map +1 -0
- package/package.json +48 -0
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
import { Container } from '@codexo/exojs';
|
|
2
|
+
import { assertPixelSnapMode } from './pixelSnap.js';
|
|
3
|
+
import { TileChunkNode } from './TileChunkNode.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A scene node that renders one generic {@link TileLayer} as a
|
|
7
|
+
* {@link Container} of per-chunk {@link TileChunkNode} drawables.
|
|
8
|
+
*
|
|
9
|
+
* Each non-empty loaded chunk becomes one child positioned at its pixel
|
|
10
|
+
* origin, so the engine's existing per-node culling drops individual chunks and
|
|
11
|
+
* the render-plan optimiser batches them by tileset texture. The layer's pixel
|
|
12
|
+
* `offset` is applied to this node's transform; `visible` and `opacity` are
|
|
13
|
+
* read live from the runtime layer on every frame (no rebuild required).
|
|
14
|
+
*
|
|
15
|
+
* The node references — but never owns — the {@link TileLayer}: destroying it
|
|
16
|
+
* frees its chunk nodes and their cached geometry but leaves the layer, map,
|
|
17
|
+
* and Loader-owned textures intact.
|
|
18
|
+
*
|
|
19
|
+
* Structural changes to the layer (tiles written into previously-empty chunks)
|
|
20
|
+
* are reflected only after {@link TileLayerNode.refresh}; in-place edits to
|
|
21
|
+
* existing chunks are picked up automatically via chunk revisions.
|
|
22
|
+
*
|
|
23
|
+
* @advanced
|
|
24
|
+
*/
|
|
25
|
+
class TileLayerNode extends Container {
|
|
26
|
+
_layer;
|
|
27
|
+
_cullChunks;
|
|
28
|
+
_chunkNodes = [];
|
|
29
|
+
_syncedOpacity = -1;
|
|
30
|
+
_pixelSnapMode = 'none';
|
|
31
|
+
constructor(layer, options) {
|
|
32
|
+
super();
|
|
33
|
+
this._layer = layer;
|
|
34
|
+
this._cullChunks = options?.cullable ?? true;
|
|
35
|
+
this.setPosition(layer.offsetX, layer.offsetY);
|
|
36
|
+
this._buildChunkNodes();
|
|
37
|
+
}
|
|
38
|
+
/** The runtime layer this node renders. */
|
|
39
|
+
get layer() {
|
|
40
|
+
return this._layer;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Render-only pixel-snap mode applied to every chunk node in this layer (and
|
|
44
|
+
* to chunks rebuilt later by {@link refresh}). Each chunk's rendered origin is
|
|
45
|
+
* snapped to the active render target's device-pixel grid; because chunk
|
|
46
|
+
* origins are integer multiples of the integer tile pitch from the same layer
|
|
47
|
+
* origin, the whole grid stays exact and adjacent chunks cannot drift apart.
|
|
48
|
+
*
|
|
49
|
+
* Purely visual: tile data, the layer offset, chunk content revisions, and
|
|
50
|
+
* culling bounds are never changed. `'geometry'` and `'position'` both resolve
|
|
51
|
+
* to coherent origin snapping for tile chunks (chunk quads are already on the
|
|
52
|
+
* integer pixel grid by construction). Setting the current value is a no-op;
|
|
53
|
+
* an invalid value throws and leaves the prior mode unchanged.
|
|
54
|
+
*
|
|
55
|
+
* @default 'none'
|
|
56
|
+
* @stable
|
|
57
|
+
*/
|
|
58
|
+
get pixelSnapMode() {
|
|
59
|
+
return this._pixelSnapMode;
|
|
60
|
+
}
|
|
61
|
+
set pixelSnapMode(mode) {
|
|
62
|
+
if (mode === this._pixelSnapMode) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
assertPixelSnapMode(mode);
|
|
66
|
+
this._pixelSnapMode = mode;
|
|
67
|
+
for (const chunk of this._chunkNodes) {
|
|
68
|
+
chunk.pixelSnapMode = mode;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Rebuild the chunk-node children from the layer's current loaded chunks.
|
|
73
|
+
* Call after structural mutation that creates or empties chunks. In-place
|
|
74
|
+
* tile edits to existing chunks do not need a refresh.
|
|
75
|
+
*/
|
|
76
|
+
refresh() {
|
|
77
|
+
const previous = [...this._chunkNodes];
|
|
78
|
+
this.removeChildren();
|
|
79
|
+
this._chunkNodes.length = 0;
|
|
80
|
+
for (const child of previous) {
|
|
81
|
+
child.destroy();
|
|
82
|
+
}
|
|
83
|
+
this._syncedOpacity = -1;
|
|
84
|
+
this._buildChunkNodes();
|
|
85
|
+
return this;
|
|
86
|
+
}
|
|
87
|
+
/** The chunk render nodes owned by this layer node, in build order. @internal */
|
|
88
|
+
get chunkNodes() {
|
|
89
|
+
return this._chunkNodes;
|
|
90
|
+
}
|
|
91
|
+
getLocalBounds() {
|
|
92
|
+
const bounds = super.getLocalBounds();
|
|
93
|
+
bounds.set(0, 0, this._layer.pixelWidth, this._layer.pixelHeight);
|
|
94
|
+
return bounds;
|
|
95
|
+
}
|
|
96
|
+
/** @internal */
|
|
97
|
+
_collectContent(builder) {
|
|
98
|
+
if (!this._layer.visible) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
this._syncOpacity();
|
|
102
|
+
super._collectContent(builder);
|
|
103
|
+
}
|
|
104
|
+
destroy() {
|
|
105
|
+
const children = [...this._chunkNodes];
|
|
106
|
+
this._chunkNodes.length = 0;
|
|
107
|
+
super.destroy();
|
|
108
|
+
for (const child of children) {
|
|
109
|
+
child.destroy();
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
_buildChunkNodes() {
|
|
113
|
+
const layer = this._layer;
|
|
114
|
+
for (const chunk of layer.loadedChunks()) {
|
|
115
|
+
if (chunk.empty) {
|
|
116
|
+
continue;
|
|
117
|
+
}
|
|
118
|
+
const node = new TileChunkNode(chunk, layer.tilesets, layer.tileWidth, layer.tileHeight, layer.chunkWidth, layer.chunkHeight);
|
|
119
|
+
node.cullable = this._cullChunks;
|
|
120
|
+
if (this._pixelSnapMode !== 'none') {
|
|
121
|
+
node.pixelSnapMode = this._pixelSnapMode;
|
|
122
|
+
}
|
|
123
|
+
this._chunkNodes.push(node);
|
|
124
|
+
this.addChild(node);
|
|
125
|
+
}
|
|
126
|
+
this._syncOpacity();
|
|
127
|
+
}
|
|
128
|
+
/** Propagate the layer's live opacity onto the chunk tints if it changed. */
|
|
129
|
+
_syncOpacity() {
|
|
130
|
+
const opacity = this._layer.opacity;
|
|
131
|
+
if (opacity === this._syncedOpacity) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
for (const child of this._chunkNodes) {
|
|
135
|
+
child.tint.a = opacity;
|
|
136
|
+
}
|
|
137
|
+
this._syncedOpacity = opacity;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
export { TileLayerNode };
|
|
142
|
+
//# sourceMappingURL=TileLayerNode.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TileLayerNode.js","sources":["../../../src/TileLayerNode.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import { type TileLayer } from './TileLayer';
|
|
2
|
+
import type { TileMapViewOptions } from './TileMapView';
|
|
3
|
+
import { TileMapView } from './TileMapView';
|
|
4
|
+
import { type TileSet } from './TileSet';
|
|
5
|
+
import type { ResolvedTile, TileProperties } from './types';
|
|
6
|
+
/**
|
|
7
|
+
* Options for constructing a {@link TileMap}.
|
|
8
|
+
* @advanced
|
|
9
|
+
*/
|
|
10
|
+
export interface TileMapOptions {
|
|
11
|
+
/** Map name (for debugging). */
|
|
12
|
+
readonly name?: string;
|
|
13
|
+
/** Map width in tiles. */
|
|
14
|
+
readonly width: number;
|
|
15
|
+
/** Map height in tiles. */
|
|
16
|
+
readonly height: number;
|
|
17
|
+
/** Width of each tile in pixels. */
|
|
18
|
+
readonly tileWidth: number;
|
|
19
|
+
/** Height of each tile in pixels. */
|
|
20
|
+
readonly tileHeight: number;
|
|
21
|
+
/** Tilesets available to this map. */
|
|
22
|
+
readonly tilesets?: readonly TileSet[];
|
|
23
|
+
/** Layers (constructed externally and owned by the map after construction). */
|
|
24
|
+
readonly layers?: readonly TileLayer[];
|
|
25
|
+
/** Chunk width for layers (default 32). */
|
|
26
|
+
readonly chunkWidth?: number;
|
|
27
|
+
/** Chunk height for layers (default 32). */
|
|
28
|
+
readonly chunkHeight?: number;
|
|
29
|
+
/** Map-level properties (copied and frozen). */
|
|
30
|
+
readonly properties?: TileProperties;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* A generic, format-independent tile map.
|
|
34
|
+
*
|
|
35
|
+
* Owns a finite grid of {@link TileLayer}s and a shared set of {@link TileSet}s.
|
|
36
|
+
* Tile data is stored in compact chunked arrays — no per-tile heap objects.
|
|
37
|
+
*
|
|
38
|
+
* The map does NOT own tileset textures (those are Loader-owned) and does
|
|
39
|
+
* NOT own SceneNode children (the future TileMapNode will own those).
|
|
40
|
+
*
|
|
41
|
+
* Multiple tilesets are supported: each cell stores a packed tileset index
|
|
42
|
+
* and local tile ID, so different tilesets may have different tile dimensions.
|
|
43
|
+
*
|
|
44
|
+
* @advanced
|
|
45
|
+
*/
|
|
46
|
+
export declare class TileMap {
|
|
47
|
+
/** Map name (debug). */
|
|
48
|
+
readonly name: string;
|
|
49
|
+
/** Map width in tiles. */
|
|
50
|
+
readonly width: number;
|
|
51
|
+
/** Map height in tiles. */
|
|
52
|
+
readonly height: number;
|
|
53
|
+
/** Tile width in pixels. */
|
|
54
|
+
readonly tileWidth: number;
|
|
55
|
+
/** Tile height in pixels. */
|
|
56
|
+
readonly tileHeight: number;
|
|
57
|
+
/** Pixel width. */
|
|
58
|
+
get pixelWidth(): number;
|
|
59
|
+
/** Pixel height. */
|
|
60
|
+
get pixelHeight(): number;
|
|
61
|
+
/** Default chunk width for layers. */
|
|
62
|
+
readonly chunkWidth: number;
|
|
63
|
+
/** Default chunk height for layers. */
|
|
64
|
+
readonly chunkHeight: number;
|
|
65
|
+
/** Map-level properties (immutable). */
|
|
66
|
+
readonly properties: TileProperties;
|
|
67
|
+
private readonly _tilesets;
|
|
68
|
+
private readonly _layers;
|
|
69
|
+
private readonly _layerById;
|
|
70
|
+
private _revision;
|
|
71
|
+
private _destroyed;
|
|
72
|
+
/**
|
|
73
|
+
* @throws When dimensions or other options are invalid.
|
|
74
|
+
*/
|
|
75
|
+
constructor(options: TileMapOptions);
|
|
76
|
+
/** Immutable list of tilesets available to this map. */
|
|
77
|
+
get tilesets(): readonly TileSet[];
|
|
78
|
+
/**
|
|
79
|
+
* Add a tileset. Tilesets must have unique names.
|
|
80
|
+
* @throws If a tileset with the same name already exists, or the map is destroyed.
|
|
81
|
+
*/
|
|
82
|
+
addTileset(tileset: TileSet): void;
|
|
83
|
+
/**
|
|
84
|
+
* Get a tileset by name, or undefined.
|
|
85
|
+
*/
|
|
86
|
+
getTileset(name: string): TileSet | undefined;
|
|
87
|
+
/** Immutable snapshot of layers (ordered). */
|
|
88
|
+
get layers(): readonly TileLayer[];
|
|
89
|
+
private _addLayer;
|
|
90
|
+
/**
|
|
91
|
+
* Add a layer after construction.
|
|
92
|
+
* @throws If a layer with the same ID already exists.
|
|
93
|
+
*/
|
|
94
|
+
addLayer(layer: TileLayer): void;
|
|
95
|
+
/**
|
|
96
|
+
* Get a layer by ID.
|
|
97
|
+
*/
|
|
98
|
+
getLayerById(id: number): TileLayer | undefined;
|
|
99
|
+
/**
|
|
100
|
+
* Get a layer by name. Returns the first match in insertion order.
|
|
101
|
+
*/
|
|
102
|
+
getLayerByName(name: string): TileLayer | undefined;
|
|
103
|
+
/**
|
|
104
|
+
* Get a tile layer by name. Convenience alias for {@link getLayerByName}.
|
|
105
|
+
*/
|
|
106
|
+
getTileLayer(name: string): TileLayer | undefined;
|
|
107
|
+
/**
|
|
108
|
+
* Remove a layer by ID. The layer is destroyed.
|
|
109
|
+
* @returns true if the layer was found and removed.
|
|
110
|
+
*/
|
|
111
|
+
removeLayer(id: number): boolean;
|
|
112
|
+
/**
|
|
113
|
+
* Create a new {@link TileMapView} that groups this map's layers into
|
|
114
|
+
* independently placeable band / layer scene nodes for interleaving
|
|
115
|
+
* application actors between tile layers.
|
|
116
|
+
*
|
|
117
|
+
* Each call returns a fresh, independent view — the map does **not** cache a
|
|
118
|
+
* single global view, so multiple coexisting views of the same map are
|
|
119
|
+
* allowed. The view references this map but never owns it: destroying the
|
|
120
|
+
* view frees only its generated layer/band nodes — never the map, its layers,
|
|
121
|
+
* tileset textures, or any application actors.
|
|
122
|
+
*
|
|
123
|
+
* @advanced
|
|
124
|
+
*/
|
|
125
|
+
createView(options?: TileMapViewOptions): TileMapView;
|
|
126
|
+
/**
|
|
127
|
+
* Get a resolved tile from a given layer at tile coordinates.
|
|
128
|
+
* Convenience for `map.getLayerById(id)?.getTileAt(tx, ty)`.
|
|
129
|
+
* Returns null for an empty cell, out-of-bounds, or missing layer.
|
|
130
|
+
*/
|
|
131
|
+
getTileAt(layerId: number, tx: number, ty: number): ResolvedTile | null;
|
|
132
|
+
/**
|
|
133
|
+
* Set a tile on a given layer at tile coordinates.
|
|
134
|
+
* Convenience for `map.getLayerById(id)?.setTileAt(tx, ty, tile)`.
|
|
135
|
+
* @throws If the layer does not exist, coordinates are out of bounds,
|
|
136
|
+
* or the tile reference is invalid.
|
|
137
|
+
*/
|
|
138
|
+
setTileAt(layerId: number, tx: number, ty: number, tile: ResolvedTile): void;
|
|
139
|
+
/**
|
|
140
|
+
* Clear a tile on a given layer at tile coordinates.
|
|
141
|
+
* Convenience for `map.getLayerById(id)?.clearTileAt(tx, ty)`.
|
|
142
|
+
* @throws If the layer does not exist or coordinates are out of bounds.
|
|
143
|
+
*/
|
|
144
|
+
clearTileAt(layerId: number, tx: number, ty: number): void;
|
|
145
|
+
/**
|
|
146
|
+
* Convert a tile coordinate to the pixel position of its top-left corner
|
|
147
|
+
* in map-local space (ignoring layer offsets).
|
|
148
|
+
*/
|
|
149
|
+
tileToPixel(tx: number, ty: number): {
|
|
150
|
+
x: number;
|
|
151
|
+
y: number;
|
|
152
|
+
};
|
|
153
|
+
/**
|
|
154
|
+
* Convert a pixel position in map-local space to the tile coordinate
|
|
155
|
+
* that contains it. Uses `floor`. May return coordinates outside map bounds.
|
|
156
|
+
*/
|
|
157
|
+
pixelToTile(px: number, py: number): {
|
|
158
|
+
tx: number;
|
|
159
|
+
ty: number;
|
|
160
|
+
};
|
|
161
|
+
/**
|
|
162
|
+
* Monotonic map revision counter. Increments on structural changes only
|
|
163
|
+
* (add/remove layer, add tileset). Cell mutations are tracked per-chunk
|
|
164
|
+
* and per-layer; the renderer reads chunk-level revisions directly.
|
|
165
|
+
* @advanced
|
|
166
|
+
*/
|
|
167
|
+
get revision(): number;
|
|
168
|
+
/** Whether the map has been destroyed. */
|
|
169
|
+
get destroyed(): boolean;
|
|
170
|
+
private _checkDestroyed;
|
|
171
|
+
/**
|
|
172
|
+
* Destroy the map and all owned layers and chunk storage.
|
|
173
|
+
*
|
|
174
|
+
* Is idempotent. Does NOT destroy tileset textures (Loader-owned) or
|
|
175
|
+
* any SceneNodes (those do not exist yet in this slice).
|
|
176
|
+
*/
|
|
177
|
+
destroy(): void;
|
|
178
|
+
}
|
|
@@ -0,0 +1,262 @@
|
|
|
1
|
+
import { validatePositiveInteger } from './types.js';
|
|
2
|
+
import { TileMapView } from './TileMapView.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* A generic, format-independent tile map.
|
|
6
|
+
*
|
|
7
|
+
* Owns a finite grid of {@link TileLayer}s and a shared set of {@link TileSet}s.
|
|
8
|
+
* Tile data is stored in compact chunked arrays — no per-tile heap objects.
|
|
9
|
+
*
|
|
10
|
+
* The map does NOT own tileset textures (those are Loader-owned) and does
|
|
11
|
+
* NOT own SceneNode children (the future TileMapNode will own those).
|
|
12
|
+
*
|
|
13
|
+
* Multiple tilesets are supported: each cell stores a packed tileset index
|
|
14
|
+
* and local tile ID, so different tilesets may have different tile dimensions.
|
|
15
|
+
*
|
|
16
|
+
* @advanced
|
|
17
|
+
*/
|
|
18
|
+
class TileMap {
|
|
19
|
+
/** Map name (debug). */
|
|
20
|
+
name;
|
|
21
|
+
/** Map width in tiles. */
|
|
22
|
+
width;
|
|
23
|
+
/** Map height in tiles. */
|
|
24
|
+
height;
|
|
25
|
+
/** Tile width in pixels. */
|
|
26
|
+
tileWidth;
|
|
27
|
+
/** Tile height in pixels. */
|
|
28
|
+
tileHeight;
|
|
29
|
+
/** Pixel width. */
|
|
30
|
+
get pixelWidth() { return this.width * this.tileWidth; }
|
|
31
|
+
/** Pixel height. */
|
|
32
|
+
get pixelHeight() { return this.height * this.tileHeight; }
|
|
33
|
+
/** Default chunk width for layers. */
|
|
34
|
+
chunkWidth;
|
|
35
|
+
/** Default chunk height for layers. */
|
|
36
|
+
chunkHeight;
|
|
37
|
+
/** Map-level properties (immutable). */
|
|
38
|
+
properties;
|
|
39
|
+
_tilesets;
|
|
40
|
+
_layers = [];
|
|
41
|
+
_layerById = new Map();
|
|
42
|
+
_revision = 0;
|
|
43
|
+
_destroyed = false;
|
|
44
|
+
/**
|
|
45
|
+
* @throws When dimensions or other options are invalid.
|
|
46
|
+
*/
|
|
47
|
+
constructor(options) {
|
|
48
|
+
validatePositiveInteger(options.width, 'map.width');
|
|
49
|
+
validatePositiveInteger(options.height, 'map.height');
|
|
50
|
+
validatePositiveInteger(options.tileWidth, 'map.tileWidth');
|
|
51
|
+
validatePositiveInteger(options.tileHeight, 'map.tileHeight');
|
|
52
|
+
const chunkWidth = options.chunkWidth ?? 32;
|
|
53
|
+
const chunkHeight = options.chunkHeight ?? 32;
|
|
54
|
+
validatePositiveInteger(chunkWidth, 'chunkWidth');
|
|
55
|
+
validatePositiveInteger(chunkHeight, 'chunkHeight');
|
|
56
|
+
this.name = options.name ?? 'TileMap';
|
|
57
|
+
this.width = options.width;
|
|
58
|
+
this.height = options.height;
|
|
59
|
+
this.tileWidth = options.tileWidth;
|
|
60
|
+
this.tileHeight = options.tileHeight;
|
|
61
|
+
this.chunkWidth = chunkWidth;
|
|
62
|
+
this.chunkHeight = chunkHeight;
|
|
63
|
+
this._tilesets = options.tilesets ? [...options.tilesets] : [];
|
|
64
|
+
this.properties = options.properties
|
|
65
|
+
? Object.freeze({ ...options.properties })
|
|
66
|
+
: Object.freeze({});
|
|
67
|
+
if (options.layers) {
|
|
68
|
+
for (const layer of options.layers) {
|
|
69
|
+
this._addLayer(layer);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
// ── Tilesets ──────────────────────────────────────────────────────────
|
|
74
|
+
/** Immutable list of tilesets available to this map. */
|
|
75
|
+
get tilesets() {
|
|
76
|
+
return this._tilesets;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Add a tileset. Tilesets must have unique names.
|
|
80
|
+
* @throws If a tileset with the same name already exists, or the map is destroyed.
|
|
81
|
+
*/
|
|
82
|
+
addTileset(tileset) {
|
|
83
|
+
this._checkDestroyed();
|
|
84
|
+
if (this._tilesets.some(ts => ts.name === tileset.name)) {
|
|
85
|
+
throw new Error(`Tileset "${tileset.name}" already exists in map "${this.name}".`);
|
|
86
|
+
}
|
|
87
|
+
this._tilesets.push(tileset);
|
|
88
|
+
this._revision++;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Get a tileset by name, or undefined.
|
|
92
|
+
*/
|
|
93
|
+
getTileset(name) {
|
|
94
|
+
return this._tilesets.find(ts => ts.name === name);
|
|
95
|
+
}
|
|
96
|
+
// ── Layers ────────────────────────────────────────────────────────────
|
|
97
|
+
/** Immutable snapshot of layers (ordered). */
|
|
98
|
+
get layers() {
|
|
99
|
+
return this._layers;
|
|
100
|
+
}
|
|
101
|
+
_addLayer(layer) {
|
|
102
|
+
if (this._layerById.has(layer.id)) {
|
|
103
|
+
throw new Error(`Layer ID ${layer.id} already exists in map "${this.name}".`);
|
|
104
|
+
}
|
|
105
|
+
this._layerById.set(layer.id, layer);
|
|
106
|
+
this._layers.push(layer);
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Add a layer after construction.
|
|
110
|
+
* @throws If a layer with the same ID already exists.
|
|
111
|
+
*/
|
|
112
|
+
addLayer(layer) {
|
|
113
|
+
this._checkDestroyed();
|
|
114
|
+
this._addLayer(layer);
|
|
115
|
+
this._revision++;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Get a layer by ID.
|
|
119
|
+
*/
|
|
120
|
+
getLayerById(id) {
|
|
121
|
+
return this._layerById.get(id);
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Get a layer by name. Returns the first match in insertion order.
|
|
125
|
+
*/
|
|
126
|
+
getLayerByName(name) {
|
|
127
|
+
return this._layers.find(l => l.name === name);
|
|
128
|
+
}
|
|
129
|
+
/**
|
|
130
|
+
* Get a tile layer by name. Convenience alias for {@link getLayerByName}.
|
|
131
|
+
*/
|
|
132
|
+
getTileLayer(name) {
|
|
133
|
+
return this.getLayerByName(name);
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Remove a layer by ID. The layer is destroyed.
|
|
137
|
+
* @returns true if the layer was found and removed.
|
|
138
|
+
*/
|
|
139
|
+
removeLayer(id) {
|
|
140
|
+
this._checkDestroyed();
|
|
141
|
+
const layer = this._layerById.get(id);
|
|
142
|
+
if (!layer)
|
|
143
|
+
return false;
|
|
144
|
+
this._layers.splice(this._layers.indexOf(layer), 1);
|
|
145
|
+
this._layerById.delete(id);
|
|
146
|
+
layer.destroy();
|
|
147
|
+
this._revision++;
|
|
148
|
+
return true;
|
|
149
|
+
}
|
|
150
|
+
// ── Scene composition ─────────────────────────────────────────────────
|
|
151
|
+
/**
|
|
152
|
+
* Create a new {@link TileMapView} that groups this map's layers into
|
|
153
|
+
* independently placeable band / layer scene nodes for interleaving
|
|
154
|
+
* application actors between tile layers.
|
|
155
|
+
*
|
|
156
|
+
* Each call returns a fresh, independent view — the map does **not** cache a
|
|
157
|
+
* single global view, so multiple coexisting views of the same map are
|
|
158
|
+
* allowed. The view references this map but never owns it: destroying the
|
|
159
|
+
* view frees only its generated layer/band nodes — never the map, its layers,
|
|
160
|
+
* tileset textures, or any application actors.
|
|
161
|
+
*
|
|
162
|
+
* @advanced
|
|
163
|
+
*/
|
|
164
|
+
createView(options) {
|
|
165
|
+
return new TileMapView(this, options);
|
|
166
|
+
}
|
|
167
|
+
// ── Queries ───────────────────────────────────────────────────────────
|
|
168
|
+
/**
|
|
169
|
+
* Get a resolved tile from a given layer at tile coordinates.
|
|
170
|
+
* Convenience for `map.getLayerById(id)?.getTileAt(tx, ty)`.
|
|
171
|
+
* Returns null for an empty cell, out-of-bounds, or missing layer.
|
|
172
|
+
*/
|
|
173
|
+
getTileAt(layerId, tx, ty) {
|
|
174
|
+
const layer = this._layerById.get(layerId);
|
|
175
|
+
if (!layer)
|
|
176
|
+
return null;
|
|
177
|
+
return layer.getTileAt(tx, ty);
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Set a tile on a given layer at tile coordinates.
|
|
181
|
+
* Convenience for `map.getLayerById(id)?.setTileAt(tx, ty, tile)`.
|
|
182
|
+
* @throws If the layer does not exist, coordinates are out of bounds,
|
|
183
|
+
* or the tile reference is invalid.
|
|
184
|
+
*/
|
|
185
|
+
setTileAt(layerId, tx, ty, tile) {
|
|
186
|
+
const layer = this._layerById.get(layerId);
|
|
187
|
+
if (!layer)
|
|
188
|
+
throw new Error(`Layer ${layerId} not found in map "${this.name}".`);
|
|
189
|
+
layer.setTileAt(tx, ty, tile);
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* Clear a tile on a given layer at tile coordinates.
|
|
193
|
+
* Convenience for `map.getLayerById(id)?.clearTileAt(tx, ty)`.
|
|
194
|
+
* @throws If the layer does not exist or coordinates are out of bounds.
|
|
195
|
+
*/
|
|
196
|
+
clearTileAt(layerId, tx, ty) {
|
|
197
|
+
const layer = this._layerById.get(layerId);
|
|
198
|
+
if (!layer)
|
|
199
|
+
throw new Error(`Layer ${layerId} not found in map "${this.name}".`);
|
|
200
|
+
layer.clearTileAt(tx, ty);
|
|
201
|
+
}
|
|
202
|
+
// ── Coordinate conversion (base layer) ────────────────────────────────
|
|
203
|
+
/**
|
|
204
|
+
* Convert a tile coordinate to the pixel position of its top-left corner
|
|
205
|
+
* in map-local space (ignoring layer offsets).
|
|
206
|
+
*/
|
|
207
|
+
tileToPixel(tx, ty) {
|
|
208
|
+
return {
|
|
209
|
+
x: tx * this.tileWidth,
|
|
210
|
+
y: ty * this.tileHeight,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* Convert a pixel position in map-local space to the tile coordinate
|
|
215
|
+
* that contains it. Uses `floor`. May return coordinates outside map bounds.
|
|
216
|
+
*/
|
|
217
|
+
pixelToTile(px, py) {
|
|
218
|
+
return {
|
|
219
|
+
tx: Math.floor(px / this.tileWidth),
|
|
220
|
+
ty: Math.floor(py / this.tileHeight),
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
// ── Revision / lifecycle ──────────────────────────────────────────────
|
|
224
|
+
/**
|
|
225
|
+
* Monotonic map revision counter. Increments on structural changes only
|
|
226
|
+
* (add/remove layer, add tileset). Cell mutations are tracked per-chunk
|
|
227
|
+
* and per-layer; the renderer reads chunk-level revisions directly.
|
|
228
|
+
* @advanced
|
|
229
|
+
*/
|
|
230
|
+
get revision() {
|
|
231
|
+
return this._revision;
|
|
232
|
+
}
|
|
233
|
+
/** Whether the map has been destroyed. */
|
|
234
|
+
get destroyed() {
|
|
235
|
+
return this._destroyed;
|
|
236
|
+
}
|
|
237
|
+
_checkDestroyed() {
|
|
238
|
+
if (this._destroyed) {
|
|
239
|
+
throw new Error(`TileMap "${this.name}" has been destroyed.`);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
/**
|
|
243
|
+
* Destroy the map and all owned layers and chunk storage.
|
|
244
|
+
*
|
|
245
|
+
* Is idempotent. Does NOT destroy tileset textures (Loader-owned) or
|
|
246
|
+
* any SceneNodes (those do not exist yet in this slice).
|
|
247
|
+
*/
|
|
248
|
+
destroy() {
|
|
249
|
+
if (this._destroyed)
|
|
250
|
+
return;
|
|
251
|
+
this._destroyed = true;
|
|
252
|
+
for (const layer of this._layers) {
|
|
253
|
+
layer.destroy();
|
|
254
|
+
}
|
|
255
|
+
this._layers.length = 0;
|
|
256
|
+
this._layerById.clear();
|
|
257
|
+
this._tilesets.length = 0;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
export { TileMap };
|
|
262
|
+
//# sourceMappingURL=TileMap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"TileMap.js","sources":["../../../src/TileMap.ts"],"sourcesContent":[null],"names":[],"mappings":"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"}
|