@al8b/map 0.1.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 +24 -0
- package/dist/core/tile-map.d.mts +36 -0
- package/dist/core/tile-map.d.ts +36 -0
- package/dist/core/tile-map.js +361 -0
- package/dist/core/tile-map.js.map +1 -0
- package/dist/core/tile-map.mjs +335 -0
- package/dist/core/tile-map.mjs.map +1 -0
- package/dist/data/loader.d.mts +10 -0
- package/dist/data/loader.d.ts +10 -0
- package/dist/data/loader.js +52 -0
- package/dist/data/loader.js.map +1 -0
- package/dist/data/loader.mjs +28 -0
- package/dist/data/loader.mjs.map +1 -0
- package/dist/data/types.d.mts +29 -0
- package/dist/data/types.d.ts +29 -0
- package/dist/data/types.js +19 -0
- package/dist/data/types.js.map +1 -0
- package/dist/data/types.mjs +1 -0
- package/dist/data/types.mjs.map +1 -0
- package/dist/drawing/renderer.d.mts +14 -0
- package/dist/drawing/renderer.d.ts +14 -0
- package/dist/drawing/renderer.js +108 -0
- package/dist/drawing/renderer.js.map +1 -0
- package/dist/drawing/renderer.mjs +82 -0
- package/dist/drawing/renderer.mjs.map +1 -0
- package/dist/index.d.mts +3 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +363 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +335 -0
- package/dist/index.mjs.map +1 -0
- package/dist/shared/references.d.mts +4 -0
- package/dist/shared/references.d.ts +4 -0
- package/dist/shared/references.js +35 -0
- package/dist/shared/references.js.map +1 -0
- package/dist/shared/references.mjs +11 -0
- package/dist/shared/references.mjs.map +1 -0
- package/package.json +35 -0
package/README.md
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# @al8b/map
|
|
2
|
+
|
|
3
|
+
Tile map data structure and renderer integration for L8B. It handles serialized map payloads, sprite references, cached canvas output, and animated tile rendering.
|
|
4
|
+
|
|
5
|
+
## Public API
|
|
6
|
+
|
|
7
|
+
- `TileMap`
|
|
8
|
+
- `LoadMap`
|
|
9
|
+
- `UpdateMap`
|
|
10
|
+
- `SaveMap`
|
|
11
|
+
- Type: `MapData`
|
|
12
|
+
|
|
13
|
+
## Notes
|
|
14
|
+
|
|
15
|
+
- Depends on `@al8b/sprites` for sprite-backed tile rendering.
|
|
16
|
+
- `TileMap` is browser-oriented and can fetch map assets via `XMLHttpRequest`.
|
|
17
|
+
|
|
18
|
+
## Scripts
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
bun run build
|
|
22
|
+
bun run test
|
|
23
|
+
bun run clean
|
|
24
|
+
```
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Sprite } from '@al8b/sprites';
|
|
2
|
+
import { SpriteDictionary } from '../data/types.mjs';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* TileMap - Tile-based map implementation with sprite rendering support.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
declare class TileMap {
|
|
9
|
+
width: number;
|
|
10
|
+
height: number;
|
|
11
|
+
block_width: number;
|
|
12
|
+
block_height: number;
|
|
13
|
+
sprites: SpriteDictionary;
|
|
14
|
+
map: (string | null)[];
|
|
15
|
+
ready: boolean;
|
|
16
|
+
needs_update: boolean;
|
|
17
|
+
name: string;
|
|
18
|
+
private parsedMap;
|
|
19
|
+
private readonly renderState;
|
|
20
|
+
constructor(width: number, height: number, block_width: number, block_height: number, sprites?: Record<string, Sprite>);
|
|
21
|
+
clear(): void;
|
|
22
|
+
set(x: number, y: number, ref: string | null): void;
|
|
23
|
+
get(x: number, y: number): string | number | null;
|
|
24
|
+
getCanvas(): HTMLCanvasElement;
|
|
25
|
+
draw(context: CanvasRenderingContext2D, x: number, y: number, w: number, h: number): void;
|
|
26
|
+
update(): void;
|
|
27
|
+
loadFile(url: string, loaded?: () => void): void;
|
|
28
|
+
load(data: string, sprites: Record<string, Sprite>): void;
|
|
29
|
+
clone(): TileMap;
|
|
30
|
+
copyFrom(map: TileMap): TileMap;
|
|
31
|
+
}
|
|
32
|
+
declare function LoadMap(url: string, sprites?: Record<string, Sprite>, loaded?: () => void): TileMap;
|
|
33
|
+
declare function UpdateMap(map: TileMap, data: string, sprites?: Record<string, Sprite>): TileMap;
|
|
34
|
+
declare function SaveMap(map: TileMap): string;
|
|
35
|
+
|
|
36
|
+
export { LoadMap, SaveMap, TileMap, UpdateMap };
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Sprite } from '@al8b/sprites';
|
|
2
|
+
import { SpriteDictionary } from '../data/types.js';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* TileMap - Tile-based map implementation with sprite rendering support.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
declare class TileMap {
|
|
9
|
+
width: number;
|
|
10
|
+
height: number;
|
|
11
|
+
block_width: number;
|
|
12
|
+
block_height: number;
|
|
13
|
+
sprites: SpriteDictionary;
|
|
14
|
+
map: (string | null)[];
|
|
15
|
+
ready: boolean;
|
|
16
|
+
needs_update: boolean;
|
|
17
|
+
name: string;
|
|
18
|
+
private parsedMap;
|
|
19
|
+
private readonly renderState;
|
|
20
|
+
constructor(width: number, height: number, block_width: number, block_height: number, sprites?: Record<string, Sprite>);
|
|
21
|
+
clear(): void;
|
|
22
|
+
set(x: number, y: number, ref: string | null): void;
|
|
23
|
+
get(x: number, y: number): string | number | null;
|
|
24
|
+
getCanvas(): HTMLCanvasElement;
|
|
25
|
+
draw(context: CanvasRenderingContext2D, x: number, y: number, w: number, h: number): void;
|
|
26
|
+
update(): void;
|
|
27
|
+
loadFile(url: string, loaded?: () => void): void;
|
|
28
|
+
load(data: string, sprites: Record<string, Sprite>): void;
|
|
29
|
+
clone(): TileMap;
|
|
30
|
+
copyFrom(map: TileMap): TileMap;
|
|
31
|
+
}
|
|
32
|
+
declare function LoadMap(url: string, sprites?: Record<string, Sprite>, loaded?: () => void): TileMap;
|
|
33
|
+
declare function UpdateMap(map: TileMap, data: string, sprites?: Record<string, Sprite>): TileMap;
|
|
34
|
+
declare function SaveMap(map: TileMap): string;
|
|
35
|
+
|
|
36
|
+
export { LoadMap, SaveMap, TileMap, UpdateMap };
|
|
@@ -0,0 +1,361 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
var __copyProps = (to, from, except, desc) => {
|
|
12
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
13
|
+
for (let key of __getOwnPropNames(from))
|
|
14
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
15
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
16
|
+
}
|
|
17
|
+
return to;
|
|
18
|
+
};
|
|
19
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
20
|
+
|
|
21
|
+
// src/core/tile-map.ts
|
|
22
|
+
var tile_map_exports = {};
|
|
23
|
+
__export(tile_map_exports, {
|
|
24
|
+
LoadMap: () => LoadMap,
|
|
25
|
+
SaveMap: () => SaveMap,
|
|
26
|
+
TileMap: () => TileMap,
|
|
27
|
+
UpdateMap: () => UpdateMap
|
|
28
|
+
});
|
|
29
|
+
module.exports = __toCommonJS(tile_map_exports);
|
|
30
|
+
var import_diagnostics2 = require("@al8b/diagnostics");
|
|
31
|
+
|
|
32
|
+
// src/drawing/renderer.ts
|
|
33
|
+
var import_diagnostics = require("@al8b/diagnostics");
|
|
34
|
+
var ensureCanvas = /* @__PURE__ */ __name((state, width, height, blockWidth, blockHeight) => {
|
|
35
|
+
if (!state.canvas) {
|
|
36
|
+
state.canvas = document.createElement("canvas");
|
|
37
|
+
}
|
|
38
|
+
const expectedWidth = width * blockWidth;
|
|
39
|
+
const expectedHeight = height * blockHeight;
|
|
40
|
+
if (state.canvas.width !== expectedWidth || state.canvas.height !== expectedHeight) {
|
|
41
|
+
state.canvas.width = expectedWidth;
|
|
42
|
+
state.canvas.height = expectedHeight;
|
|
43
|
+
}
|
|
44
|
+
const ctx = state.canvas.getContext("2d");
|
|
45
|
+
if (!ctx) {
|
|
46
|
+
const diagnostic = (0, import_diagnostics.createDiagnostic)(import_diagnostics.APIErrorCode.E7031);
|
|
47
|
+
const formatted = (0, import_diagnostics.formatForBrowser)(diagnostic);
|
|
48
|
+
throw new Error(formatted);
|
|
49
|
+
}
|
|
50
|
+
ctx.clearRect(0, 0, state.canvas.width, state.canvas.height);
|
|
51
|
+
state.animated = [];
|
|
52
|
+
return ctx;
|
|
53
|
+
}, "ensureCanvas");
|
|
54
|
+
var drawTile = /* @__PURE__ */ __name((ctx, sprite, blockWidth, blockHeight, gridX, gridY, parsed) => {
|
|
55
|
+
const canvas = sprite.frames[0].canvas;
|
|
56
|
+
if (!canvas || canvas.width === 0 || canvas.height === 0) {
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
if (parsed.subX != null) {
|
|
60
|
+
const tx = parsed.subX * blockWidth;
|
|
61
|
+
const ty = (parsed.subY ?? 0) * blockHeight;
|
|
62
|
+
ctx.drawImage(canvas, tx, ty, blockWidth, blockHeight, blockWidth * gridX, blockHeight * gridY, blockWidth, blockHeight);
|
|
63
|
+
} else {
|
|
64
|
+
ctx.drawImage(canvas, blockWidth * gridX, blockHeight * gridY);
|
|
65
|
+
}
|
|
66
|
+
return true;
|
|
67
|
+
}, "drawTile");
|
|
68
|
+
var queueAnimatedTile = /* @__PURE__ */ __name((state, sprite, blockWidth, blockHeight, gridX, gridY, parsed) => {
|
|
69
|
+
const tile = {
|
|
70
|
+
x: blockWidth * gridX,
|
|
71
|
+
y: blockHeight * gridY,
|
|
72
|
+
w: blockWidth,
|
|
73
|
+
h: blockHeight,
|
|
74
|
+
sprite
|
|
75
|
+
};
|
|
76
|
+
if (parsed.subX != null) {
|
|
77
|
+
tile.tx = parsed.subX * blockWidth;
|
|
78
|
+
tile.ty = (parsed.subY ?? 0) * blockHeight;
|
|
79
|
+
}
|
|
80
|
+
state.animated.push(tile);
|
|
81
|
+
}, "queueAnimatedTile");
|
|
82
|
+
var renderAnimatedTiles = /* @__PURE__ */ __name((state, blockWidth, blockHeight) => {
|
|
83
|
+
const time = performance.now();
|
|
84
|
+
if (!state.buffer || state.buffer.width !== blockWidth * (state.canvas.width / blockWidth) || state.buffer.height !== blockHeight * (state.canvas.height / blockHeight)) {
|
|
85
|
+
state.buffer = document.createElement("canvas");
|
|
86
|
+
state.buffer.width = state.canvas.width;
|
|
87
|
+
state.buffer.height = state.canvas.height;
|
|
88
|
+
}
|
|
89
|
+
const bufferCtx = state.buffer.getContext("2d");
|
|
90
|
+
bufferCtx.clearRect(0, 0, state.buffer.width, state.buffer.height);
|
|
91
|
+
bufferCtx.drawImage(state.canvas, 0, 0);
|
|
92
|
+
for (const tile of state.animated) {
|
|
93
|
+
const len = tile.sprite.frames.length;
|
|
94
|
+
const frame = tile.sprite.frames[Math.floor(time / 1e3 * tile.sprite.fps) % len]?.canvas;
|
|
95
|
+
if (!frame) continue;
|
|
96
|
+
if (tile.tx != null && tile.ty != null) {
|
|
97
|
+
bufferCtx.drawImage(frame, tile.tx, tile.ty, blockWidth, blockHeight, tile.x, tile.y, blockWidth, blockHeight);
|
|
98
|
+
} else {
|
|
99
|
+
bufferCtx.drawImage(frame, tile.x, tile.y, blockWidth, blockHeight);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return state.buffer;
|
|
103
|
+
}, "renderAnimatedTiles");
|
|
104
|
+
|
|
105
|
+
// src/shared/references.ts
|
|
106
|
+
var normalizeRefForStorage = /* @__PURE__ */ __name((ref) => ref.replace(/\//g, "-"), "normalizeRefForStorage");
|
|
107
|
+
var normalizeRefForUsage = /* @__PURE__ */ __name((ref) => ref.replace(/-/g, "/"), "normalizeRefForUsage");
|
|
108
|
+
|
|
109
|
+
// src/core/tile-map.ts
|
|
110
|
+
function parseTileRef(entry) {
|
|
111
|
+
const colonIdx = entry.indexOf(":");
|
|
112
|
+
if (colonIdx === -1) {
|
|
113
|
+
return {
|
|
114
|
+
spriteName: entry
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
const spriteName = entry.substring(0, colonIdx);
|
|
118
|
+
const coords = entry.substring(colonIdx + 1);
|
|
119
|
+
const commaIdx = coords.indexOf(",");
|
|
120
|
+
if (commaIdx === -1) {
|
|
121
|
+
return {
|
|
122
|
+
spriteName,
|
|
123
|
+
subX: Number.parseInt(coords, 10)
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
return {
|
|
127
|
+
spriteName,
|
|
128
|
+
subX: Number.parseInt(coords.substring(0, commaIdx), 10),
|
|
129
|
+
subY: Number.parseInt(coords.substring(commaIdx + 1), 10)
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
__name(parseTileRef, "parseTileRef");
|
|
133
|
+
var TileMap = class _TileMap {
|
|
134
|
+
static {
|
|
135
|
+
__name(this, "TileMap");
|
|
136
|
+
}
|
|
137
|
+
width;
|
|
138
|
+
height;
|
|
139
|
+
block_width;
|
|
140
|
+
block_height;
|
|
141
|
+
sprites;
|
|
142
|
+
map = [];
|
|
143
|
+
ready = true;
|
|
144
|
+
needs_update = false;
|
|
145
|
+
name = "";
|
|
146
|
+
parsedMap = [];
|
|
147
|
+
renderState = {
|
|
148
|
+
canvas: null,
|
|
149
|
+
buffer: null,
|
|
150
|
+
animated: []
|
|
151
|
+
};
|
|
152
|
+
constructor(width, height, block_width, block_height, sprites) {
|
|
153
|
+
if (width <= 0 || height <= 0 || !isFinite(width) || !isFinite(height)) {
|
|
154
|
+
const diagnostic = (0, import_diagnostics2.createDiagnostic)(import_diagnostics2.APIErrorCode.E7034, {
|
|
155
|
+
data: {
|
|
156
|
+
width,
|
|
157
|
+
height
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
const formatted = (0, import_diagnostics2.formatForBrowser)(diagnostic);
|
|
161
|
+
throw new Error(formatted);
|
|
162
|
+
}
|
|
163
|
+
this.width = width;
|
|
164
|
+
this.height = height;
|
|
165
|
+
this.block_width = block_width;
|
|
166
|
+
this.block_height = block_height;
|
|
167
|
+
this.sprites = sprites ?? {};
|
|
168
|
+
this.clear();
|
|
169
|
+
}
|
|
170
|
+
clear() {
|
|
171
|
+
for (let j = 0; j < this.height; j++) {
|
|
172
|
+
for (let i = 0; i < this.width; i++) {
|
|
173
|
+
const idx = i + j * this.width;
|
|
174
|
+
this.map[idx] = null;
|
|
175
|
+
this.parsedMap[idx] = null;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
set(x, y, ref) {
|
|
180
|
+
if (x < 0 || y < 0 || x >= this.width || y >= this.height || !isFinite(x) || !isFinite(y)) {
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
let normalized = ref;
|
|
184
|
+
if (typeof normalized === "string") {
|
|
185
|
+
normalized = normalizeRefForStorage(normalized);
|
|
186
|
+
}
|
|
187
|
+
const idx = x + y * this.width;
|
|
188
|
+
this.map[idx] = normalized;
|
|
189
|
+
this.parsedMap[idx] = normalized ? parseTileRef(normalized) : null;
|
|
190
|
+
this.needs_update = true;
|
|
191
|
+
}
|
|
192
|
+
get(x, y) {
|
|
193
|
+
if (x < 0 || y < 0 || x >= this.width || y >= this.height || !isFinite(x) || !isFinite(y)) {
|
|
194
|
+
return 0;
|
|
195
|
+
}
|
|
196
|
+
let cell = this.map[x + y * this.width];
|
|
197
|
+
if (typeof cell === "string") {
|
|
198
|
+
cell = normalizeRefForUsage(cell);
|
|
199
|
+
}
|
|
200
|
+
return cell || 0;
|
|
201
|
+
}
|
|
202
|
+
getCanvas() {
|
|
203
|
+
if (this.renderState.canvas == null || this.needs_update) {
|
|
204
|
+
this.update();
|
|
205
|
+
}
|
|
206
|
+
return this.renderState.canvas;
|
|
207
|
+
}
|
|
208
|
+
draw(context, x, y, w, h) {
|
|
209
|
+
if (this.renderState.animated.length > 0) {
|
|
210
|
+
const buffer = renderAnimatedTiles(this.renderState, this.block_width, this.block_height);
|
|
211
|
+
context.drawImage(buffer, x, y, w, h);
|
|
212
|
+
} else {
|
|
213
|
+
context.drawImage(this.getCanvas(), x, y, w, h);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
update() {
|
|
217
|
+
this.needs_update = false;
|
|
218
|
+
const context = ensureCanvas(this.renderState, this.width, this.height, this.block_width, this.block_height);
|
|
219
|
+
for (let j = 0; j < this.height; j++) {
|
|
220
|
+
for (let i = 0; i < this.width; i++) {
|
|
221
|
+
const index = i + (this.height - 1 - j) * this.width;
|
|
222
|
+
const parsed = this.parsedMap[index];
|
|
223
|
+
if (!parsed) continue;
|
|
224
|
+
const sprite = this.sprites[parsed.spriteName] || this.sprites[normalizeRefForUsage(parsed.spriteName)];
|
|
225
|
+
if (!sprite || !sprite.frames[0]) continue;
|
|
226
|
+
if (sprite.frames.length > 1) {
|
|
227
|
+
queueAnimatedTile(this.renderState, sprite, this.block_width, this.block_height, i, j, parsed);
|
|
228
|
+
} else {
|
|
229
|
+
drawTile(context, sprite, this.block_width, this.block_height, i, j, parsed);
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
loadFile(url, loaded) {
|
|
235
|
+
const req = new XMLHttpRequest();
|
|
236
|
+
req.onreadystatechange = () => {
|
|
237
|
+
if (req.readyState === XMLHttpRequest.DONE && req.status === 200) {
|
|
238
|
+
this.load(req.responseText, this.sprites);
|
|
239
|
+
this.update();
|
|
240
|
+
loaded?.();
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
req.open("GET", url);
|
|
244
|
+
req.send();
|
|
245
|
+
}
|
|
246
|
+
load(data, sprites) {
|
|
247
|
+
const parsed = JSON.parse(data);
|
|
248
|
+
this.width = parsed.width;
|
|
249
|
+
this.height = parsed.height;
|
|
250
|
+
this.block_width = parsed.block_width;
|
|
251
|
+
this.block_height = parsed.block_height;
|
|
252
|
+
this.sprites = sprites ?? this.sprites;
|
|
253
|
+
for (let j = 0; j < parsed.height; j++) {
|
|
254
|
+
for (let i = 0; i < parsed.width; i++) {
|
|
255
|
+
const idx = i + j * parsed.width;
|
|
256
|
+
const value = parsed.data[idx];
|
|
257
|
+
if (value > 0) {
|
|
258
|
+
const ref = parsed.sprites[value];
|
|
259
|
+
this.map[idx] = ref;
|
|
260
|
+
this.parsedMap[idx] = parseTileRef(ref);
|
|
261
|
+
} else {
|
|
262
|
+
this.map[idx] = null;
|
|
263
|
+
this.parsedMap[idx] = null;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
this.needs_update = true;
|
|
268
|
+
}
|
|
269
|
+
clone() {
|
|
270
|
+
const duplicate = new _TileMap(this.width, this.height, this.block_width, this.block_height, this.sprites);
|
|
271
|
+
for (let j = 0; j < this.height; j++) {
|
|
272
|
+
for (let i = 0; i < this.width; i++) {
|
|
273
|
+
const idx = i + j * this.width;
|
|
274
|
+
duplicate.map[idx] = this.map[idx];
|
|
275
|
+
duplicate.parsedMap[idx] = this.parsedMap[idx];
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
duplicate.needs_update = true;
|
|
279
|
+
return duplicate;
|
|
280
|
+
}
|
|
281
|
+
copyFrom(map) {
|
|
282
|
+
this.width = map.width;
|
|
283
|
+
this.height = map.height;
|
|
284
|
+
this.block_width = map.block_width;
|
|
285
|
+
this.block_height = map.block_height;
|
|
286
|
+
for (let j = 0; j < this.height; j++) {
|
|
287
|
+
for (let i = 0; i < this.width; i++) {
|
|
288
|
+
const idx = i + j * this.width;
|
|
289
|
+
this.map[idx] = map.map[idx];
|
|
290
|
+
this.parsedMap[idx] = map.parsedMap[idx];
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
this.update();
|
|
294
|
+
return this;
|
|
295
|
+
}
|
|
296
|
+
};
|
|
297
|
+
function LoadMap(url, sprites, loaded) {
|
|
298
|
+
const map = new TileMap(1, 1, 1, 1, sprites);
|
|
299
|
+
map.ready = false;
|
|
300
|
+
const req = new XMLHttpRequest();
|
|
301
|
+
req.onreadystatechange = () => {
|
|
302
|
+
if (req.readyState === XMLHttpRequest.DONE) {
|
|
303
|
+
map.ready = true;
|
|
304
|
+
if (req.status === 200) {
|
|
305
|
+
UpdateMap(map, req.responseText, sprites);
|
|
306
|
+
}
|
|
307
|
+
map.needs_update = true;
|
|
308
|
+
loaded?.();
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
req.open("GET", url);
|
|
312
|
+
req.send();
|
|
313
|
+
return map;
|
|
314
|
+
}
|
|
315
|
+
__name(LoadMap, "LoadMap");
|
|
316
|
+
function UpdateMap(map, data, sprites) {
|
|
317
|
+
map.load(data, sprites ?? map.sprites);
|
|
318
|
+
return map;
|
|
319
|
+
}
|
|
320
|
+
__name(UpdateMap, "UpdateMap");
|
|
321
|
+
function SaveMap(map) {
|
|
322
|
+
let index = 1;
|
|
323
|
+
const list = [
|
|
324
|
+
0
|
|
325
|
+
];
|
|
326
|
+
const table = {};
|
|
327
|
+
for (let j = 0; j < map.height; j++) {
|
|
328
|
+
for (let i = 0; i < map.width; i++) {
|
|
329
|
+
const entry = map.map[i + j * map.width];
|
|
330
|
+
if (entry && entry.length > 0 && table[entry] == null) {
|
|
331
|
+
list.push(entry);
|
|
332
|
+
table[entry] = index++;
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
const serialized = [];
|
|
337
|
+
for (let j = 0; j < map.height; j++) {
|
|
338
|
+
for (let i = 0; i < map.width; i++) {
|
|
339
|
+
const entry = map.map[i + j * map.width];
|
|
340
|
+
serialized[i + j * map.width] = entry && entry.length > 0 ? table[entry] : 0;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
const payload = {
|
|
344
|
+
width: map.width,
|
|
345
|
+
height: map.height,
|
|
346
|
+
block_width: map.block_width,
|
|
347
|
+
block_height: map.block_height,
|
|
348
|
+
sprites: list,
|
|
349
|
+
data: serialized
|
|
350
|
+
};
|
|
351
|
+
return JSON.stringify(payload);
|
|
352
|
+
}
|
|
353
|
+
__name(SaveMap, "SaveMap");
|
|
354
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
355
|
+
0 && (module.exports = {
|
|
356
|
+
LoadMap,
|
|
357
|
+
SaveMap,
|
|
358
|
+
TileMap,
|
|
359
|
+
UpdateMap
|
|
360
|
+
});
|
|
361
|
+
//# sourceMappingURL=tile-map.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/core/tile-map.ts","../../src/drawing/renderer.ts","../../src/shared/references.ts"],"sourcesContent":["/**\n * TileMap - Tile-based map implementation with sprite rendering support.\n */\n\nimport { APIErrorCode, createDiagnostic, formatForBrowser } from \"@al8b/diagnostics\";\nimport type { Sprite } from \"@al8b/sprites\";\nimport type { MapData, ParsedTile, SpriteDictionary } from \"../data/types\";\nimport { drawTile, ensureCanvas, queueAnimatedTile, type RenderState, renderAnimatedTiles } from \"../drawing/renderer\";\nimport { normalizeRefForStorage, normalizeRefForUsage } from \"../shared/references\";\n\n/**\n * Parse a tile reference string into a cached ParsedTile object.\n * Input format: \"spriteName\" or \"spriteName:subX,subY\"\n */\nfunction parseTileRef(entry: string): ParsedTile {\n\tconst colonIdx = entry.indexOf(\":\");\n\tif (colonIdx === -1) {\n\t\treturn { spriteName: entry };\n\t}\n\tconst spriteName = entry.substring(0, colonIdx);\n\tconst coords = entry.substring(colonIdx + 1);\n\tconst commaIdx = coords.indexOf(\",\");\n\tif (commaIdx === -1) {\n\t\treturn { spriteName, subX: Number.parseInt(coords, 10) };\n\t}\n\treturn {\n\t\tspriteName,\n\t\tsubX: Number.parseInt(coords.substring(0, commaIdx), 10),\n\t\tsubY: Number.parseInt(coords.substring(commaIdx + 1), 10),\n\t};\n}\n\nexport class TileMap {\n\tpublic width: number;\n\tpublic height: number;\n\tpublic block_width: number;\n\tpublic block_height: number;\n\tpublic sprites: SpriteDictionary;\n\tpublic map: (string | null)[] = [];\n\tpublic ready = true;\n\tpublic needs_update = false;\n\tpublic name = \"\";\n\tprivate parsedMap: (ParsedTile | null)[] = [];\n\tprivate readonly renderState: RenderState = {\n\t\tcanvas: null,\n\t\tbuffer: null,\n\t\tanimated: [],\n\t};\n\n\tconstructor(\n\t\twidth: number,\n\t\theight: number,\n\t\tblock_width: number,\n\t\tblock_height: number,\n\t\tsprites?: Record<string, Sprite>,\n\t) {\n\t\t// Validate map dimensions to ensure positive, finite values\n\t\tif (width <= 0 || height <= 0 || !isFinite(width) || !isFinite(height)) {\n\t\t\tconst diagnostic = createDiagnostic(APIErrorCode.E7034, {\n\t\t\t\tdata: {\n\t\t\t\t\twidth,\n\t\t\t\t\theight,\n\t\t\t\t},\n\t\t\t});\n\t\t\tconst formatted = formatForBrowser(diagnostic);\n\t\t\tthrow new Error(formatted);\n\t\t}\n\n\t\tthis.width = width;\n\t\tthis.height = height;\n\t\tthis.block_width = block_width;\n\t\tthis.block_height = block_height;\n\t\tthis.sprites = sprites ?? {};\n\t\tthis.clear();\n\t}\n\n\tclear(): void {\n\t\tfor (let j = 0; j < this.height; j++) {\n\t\t\tfor (let i = 0; i < this.width; i++) {\n\t\t\t\tconst idx = i + j * this.width;\n\t\t\t\tthis.map[idx] = null;\n\t\t\t\tthis.parsedMap[idx] = null;\n\t\t\t}\n\t\t}\n\t}\n\n\tset(x: number, y: number, ref: string | null): void {\n\t\t// Validate tile coordinates are within map bounds\n\t\tif (x < 0 || y < 0 || x >= this.width || y >= this.height || !isFinite(x) || !isFinite(y)) {\n\t\t\t// Silent fail: TileMap lacks runtime reference for error reporting\n\t\t\t// Out-of-bounds access is ignored to prevent crashes during development\n\t\t\treturn;\n\t\t}\n\n\t\tlet normalized = ref;\n\t\tif (typeof normalized === \"string\") {\n\t\t\tnormalized = normalizeRefForStorage(normalized);\n\t\t}\n\t\tconst idx = x + y * this.width;\n\t\tthis.map[idx] = normalized;\n\t\tthis.parsedMap[idx] = normalized ? parseTileRef(normalized) : null;\n\t\tthis.needs_update = true;\n\t}\n\n\tget(x: number, y: number): string | number | null {\n\t\t// Validate tile coordinates are within map bounds\n\t\tif (x < 0 || y < 0 || x >= this.width || y >= this.height || !isFinite(x) || !isFinite(y)) {\n\t\t\t// Silent fail: TileMap lacks runtime reference for error reporting\n\t\t\t// Returns 0 for out-of-bounds access to maintain backward compatibility\n\t\t\treturn 0;\n\t\t}\n\t\tlet cell = this.map[x + y * this.width];\n\t\tif (typeof cell === \"string\") {\n\t\t\tcell = normalizeRefForUsage(cell);\n\t\t}\n\t\treturn cell || 0;\n\t}\n\n\tgetCanvas(): HTMLCanvasElement {\n\t\tif (this.renderState.canvas == null || this.needs_update) {\n\t\t\tthis.update();\n\t\t}\n\t\treturn this.renderState.canvas!;\n\t}\n\n\tdraw(context: CanvasRenderingContext2D, x: number, y: number, w: number, h: number): void {\n\t\tif (this.renderState.animated.length > 0) {\n\t\t\tconst buffer = renderAnimatedTiles(this.renderState, this.block_width, this.block_height);\n\t\t\tcontext.drawImage(buffer, x, y, w, h);\n\t\t} else {\n\t\t\tcontext.drawImage(this.getCanvas(), x, y, w, h);\n\t\t}\n\t}\n\n\tupdate(): void {\n\t\tthis.needs_update = false;\n\t\tconst context = ensureCanvas(this.renderState, this.width, this.height, this.block_width, this.block_height);\n\n\t\tfor (let j = 0; j < this.height; j++) {\n\t\t\tfor (let i = 0; i < this.width; i++) {\n\t\t\t\tconst index = i + (this.height - 1 - j) * this.width;\n\t\t\t\tconst parsed = this.parsedMap[index];\n\t\t\t\tif (!parsed) continue;\n\n\t\t\t\tconst sprite =\n\t\t\t\t\tthis.sprites[parsed.spriteName] || this.sprites[normalizeRefForUsage(parsed.spriteName)];\n\t\t\t\tif (!sprite || !sprite.frames[0]) continue;\n\n\t\t\t\tif (sprite.frames.length > 1) {\n\t\t\t\t\tqueueAnimatedTile(this.renderState, sprite, this.block_width, this.block_height, i, j, parsed);\n\t\t\t\t} else {\n\t\t\t\t\tdrawTile(context, sprite, this.block_width, this.block_height, i, j, parsed);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\n\tloadFile(url: string, loaded?: () => void): void {\n\t\tconst req = new XMLHttpRequest();\n\t\treq.onreadystatechange = () => {\n\t\t\tif (req.readyState === XMLHttpRequest.DONE && req.status === 200) {\n\t\t\t\tthis.load(req.responseText, this.sprites);\n\t\t\t\tthis.update();\n\t\t\t\tloaded?.();\n\t\t\t}\n\t\t};\n\t\treq.open(\"GET\", url);\n\t\treq.send();\n\t}\n\n\tload(data: string, sprites: Record<string, Sprite>): void {\n\t\tconst parsed: MapData = JSON.parse(data);\n\t\tthis.width = parsed.width;\n\t\tthis.height = parsed.height;\n\t\tthis.block_width = parsed.block_width;\n\t\tthis.block_height = parsed.block_height;\n\t\tthis.sprites = sprites ?? this.sprites;\n\n\t\tfor (let j = 0; j < parsed.height; j++) {\n\t\t\tfor (let i = 0; i < parsed.width; i++) {\n\t\t\t\tconst idx = i + j * parsed.width;\n\t\t\t\tconst value = parsed.data[idx];\n\t\t\t\tif (value > 0) {\n\t\t\t\t\tconst ref = parsed.sprites[value] as string;\n\t\t\t\t\tthis.map[idx] = ref;\n\t\t\t\t\tthis.parsedMap[idx] = parseTileRef(ref);\n\t\t\t\t} else {\n\t\t\t\t\tthis.map[idx] = null;\n\t\t\t\t\tthis.parsedMap[idx] = null;\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\tthis.needs_update = true;\n\t}\n\n\tclone(): TileMap {\n\t\tconst duplicate = new TileMap(this.width, this.height, this.block_width, this.block_height, this.sprites);\n\t\tfor (let j = 0; j < this.height; j++) {\n\t\t\tfor (let i = 0; i < this.width; i++) {\n\t\t\t\tconst idx = i + j * this.width;\n\t\t\t\tduplicate.map[idx] = this.map[idx];\n\t\t\t\tduplicate.parsedMap[idx] = this.parsedMap[idx];\n\t\t\t}\n\t\t}\n\t\tduplicate.needs_update = true;\n\t\treturn duplicate;\n\t}\n\n\tcopyFrom(map: TileMap): TileMap {\n\t\tthis.width = map.width;\n\t\tthis.height = map.height;\n\t\tthis.block_width = map.block_width;\n\t\tthis.block_height = map.block_height;\n\t\tfor (let j = 0; j < this.height; j++) {\n\t\t\tfor (let i = 0; i < this.width; i++) {\n\t\t\t\tconst idx = i + j * this.width;\n\t\t\t\tthis.map[idx] = map.map[idx];\n\t\t\t\tthis.parsedMap[idx] = map.parsedMap[idx];\n\t\t\t}\n\t\t}\n\t\tthis.update();\n\t\treturn this;\n\t}\n}\n\nexport function LoadMap(url: string, sprites?: Record<string, Sprite>, loaded?: () => void): TileMap {\n\tconst map = new TileMap(1, 1, 1, 1, sprites);\n\tmap.ready = false;\n\n\tconst req = new XMLHttpRequest();\n\treq.onreadystatechange = () => {\n\t\tif (req.readyState === XMLHttpRequest.DONE) {\n\t\t\tmap.ready = true;\n\t\t\tif (req.status === 200) {\n\t\t\t\tUpdateMap(map, req.responseText, sprites);\n\t\t\t}\n\t\t\tmap.needs_update = true;\n\t\t\tloaded?.();\n\t\t}\n\t};\n\treq.open(\"GET\", url);\n\treq.send();\n\treturn map;\n}\n\nexport function UpdateMap(map: TileMap, data: string, sprites?: Record<string, Sprite>): TileMap {\n\tmap.load(data, sprites ?? map.sprites);\n\treturn map;\n}\n\nexport function SaveMap(map: TileMap): string {\n\tlet index = 1;\n\tconst list: Array<string | number> = [0];\n\tconst table: Record<string, number> = {};\n\n\tfor (let j = 0; j < map.height; j++) {\n\t\tfor (let i = 0; i < map.width; i++) {\n\t\t\tconst entry = map.map[i + j * map.width];\n\t\t\tif (entry && entry.length > 0 && table[entry] == null) {\n\t\t\t\tlist.push(entry);\n\t\t\t\ttable[entry] = index++;\n\t\t\t}\n\t\t}\n\t}\n\n\tconst serialized: number[] = [];\n\tfor (let j = 0; j < map.height; j++) {\n\t\tfor (let i = 0; i < map.width; i++) {\n\t\t\tconst entry = map.map[i + j * map.width];\n\t\t\tserialized[i + j * map.width] = entry && entry.length > 0 ? table[entry] : 0;\n\t\t}\n\t}\n\n\tconst payload: MapData = {\n\t\twidth: map.width,\n\t\theight: map.height,\n\t\tblock_width: map.block_width,\n\t\tblock_height: map.block_height,\n\t\tsprites: list,\n\t\tdata: serialized,\n\t};\n\n\treturn JSON.stringify(payload);\n}\n","import { APIErrorCode, createDiagnostic, formatForBrowser } from \"@al8b/diagnostics\";\nimport type { Sprite } from \"@al8b/sprites\";\nimport type { AnimatedTile, ParsedTile } from \"../data/types\";\n\nexport interface RenderState {\n\tcanvas: HTMLCanvasElement | null;\n\tbuffer: HTMLCanvasElement | null;\n\tanimated: AnimatedTile[];\n}\n\nexport const ensureCanvas = (\n\tstate: RenderState,\n\twidth: number,\n\theight: number,\n\tblockWidth: number,\n\tblockHeight: number,\n): CanvasRenderingContext2D => {\n\tif (!state.canvas) {\n\t\tstate.canvas = document.createElement(\"canvas\");\n\t}\n\tconst expectedWidth = width * blockWidth;\n\tconst expectedHeight = height * blockHeight;\n\tif (state.canvas.width !== expectedWidth || state.canvas.height !== expectedHeight) {\n\t\tstate.canvas.width = expectedWidth;\n\t\tstate.canvas.height = expectedHeight;\n\t}\n\tconst ctx = state.canvas.getContext(\"2d\");\n\tif (!ctx) {\n\t\tconst diagnostic = createDiagnostic(APIErrorCode.E7031);\n\t\tconst formatted = formatForBrowser(diagnostic);\n\t\tthrow new Error(formatted);\n\t}\n\tctx.clearRect(0, 0, state.canvas.width, state.canvas.height);\n\tstate.animated = [];\n\treturn ctx;\n};\n\nexport const drawTile = (\n\tctx: CanvasRenderingContext2D,\n\tsprite: Sprite,\n\tblockWidth: number,\n\tblockHeight: number,\n\tgridX: number,\n\tgridY: number,\n\tparsed: ParsedTile,\n): boolean => {\n\tconst canvas = sprite.frames[0].canvas;\n\tif (!canvas || canvas.width === 0 || canvas.height === 0) {\n\t\treturn false;\n\t}\n\tif (parsed.subX != null) {\n\t\tconst tx = parsed.subX * blockWidth;\n\t\tconst ty = (parsed.subY ?? 0) * blockHeight;\n\t\tctx.drawImage(\n\t\t\tcanvas,\n\t\t\ttx,\n\t\t\tty,\n\t\t\tblockWidth,\n\t\t\tblockHeight,\n\t\t\tblockWidth * gridX,\n\t\t\tblockHeight * gridY,\n\t\t\tblockWidth,\n\t\t\tblockHeight,\n\t\t);\n\t} else {\n\t\tctx.drawImage(canvas, blockWidth * gridX, blockHeight * gridY);\n\t}\n\treturn true;\n};\n\nexport const queueAnimatedTile = (\n\tstate: RenderState,\n\tsprite: Sprite,\n\tblockWidth: number,\n\tblockHeight: number,\n\tgridX: number,\n\tgridY: number,\n\tparsed: ParsedTile,\n): void => {\n\tconst tile: AnimatedTile = {\n\t\tx: blockWidth * gridX,\n\t\ty: blockHeight * gridY,\n\t\tw: blockWidth,\n\t\th: blockHeight,\n\t\tsprite,\n\t};\n\tif (parsed.subX != null) {\n\t\ttile.tx = parsed.subX * blockWidth;\n\t\ttile.ty = (parsed.subY ?? 0) * blockHeight;\n\t}\n\tstate.animated.push(tile);\n};\n\nexport const renderAnimatedTiles = (state: RenderState, blockWidth: number, blockHeight: number): HTMLCanvasElement => {\n\tconst time = performance.now();\n\tif (\n\t\t!state.buffer ||\n\t\tstate.buffer.width !== blockWidth * (state.canvas!.width / blockWidth) ||\n\t\tstate.buffer.height !== blockHeight * (state.canvas!.height / blockHeight)\n\t) {\n\t\tstate.buffer = document.createElement(\"canvas\");\n\t\tstate.buffer.width = state.canvas!.width;\n\t\tstate.buffer.height = state.canvas!.height;\n\t}\n\tconst bufferCtx = state.buffer.getContext(\"2d\")!;\n\tbufferCtx.clearRect(0, 0, state.buffer.width, state.buffer.height);\n\tbufferCtx.drawImage(state.canvas!, 0, 0);\n\tfor (const tile of state.animated) {\n\t\tconst len = tile.sprite.frames.length;\n\t\tconst frame = tile.sprite.frames[Math.floor((time / 1000) * tile.sprite.fps) % len]?.canvas;\n\t\tif (!frame) continue;\n\t\tif (tile.tx != null && tile.ty != null) {\n\t\t\tbufferCtx.drawImage(frame, tile.tx, tile.ty, blockWidth, blockHeight, tile.x, tile.y, blockWidth, blockHeight);\n\t\t} else {\n\t\t\tbufferCtx.drawImage(frame, tile.x, tile.y, blockWidth, blockHeight);\n\t\t}\n\t}\n\treturn state.buffer;\n};\n","// Convert forward slashes to dashes for safe storage in map data format\nexport const normalizeRefForStorage = (ref: string): string => ref.replace(/\\//g, \"-\");\n// Convert dashes back to forward slashes for sprite reference lookup\nexport const normalizeRefForUsage = (ref: string): string => ref.replace(/-/g, \"/\");\n"],"mappings":"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","names":["import_diagnostics","ensureCanvas","state","width","height","blockWidth","blockHeight","canvas","document","createElement","expectedWidth","expectedHeight","ctx","getContext","diagnostic","createDiagnostic","APIErrorCode","E7031","formatted","formatForBrowser","Error","clearRect","animated","drawTile","sprite","gridX","gridY","parsed","frames","subX","tx","ty","subY","drawImage","queueAnimatedTile","tile","x","y","w","h","push","renderAnimatedTiles","time","performance","now","buffer","bufferCtx","len","length","frame","Math","floor","fps","normalizeRefForStorage","ref","replace","normalizeRefForUsage","parseTileRef","entry","colonIdx","indexOf","spriteName","substring","coords","commaIdx","subX","Number","parseInt","subY","TileMap","width","height","block_width","block_height","sprites","map","ready","needs_update","name","parsedMap","renderState","canvas","buffer","animated","isFinite","diagnostic","createDiagnostic","APIErrorCode","E7034","data","formatted","formatForBrowser","Error","clear","j","i","idx","set","x","y","ref","normalized","normalizeRefForStorage","get","cell","normalizeRefForUsage","getCanvas","update","draw","context","w","h","length","renderAnimatedTiles","drawImage","ensureCanvas","index","parsed","sprite","frames","queueAnimatedTile","drawTile","loadFile","url","loaded","req","XMLHttpRequest","onreadystatechange","readyState","DONE","status","load","responseText","open","send","JSON","parse","value","clone","duplicate","copyFrom","LoadMap","UpdateMap","SaveMap","list","table","push","serialized","payload","stringify"]}
|