@rpgjs/tiledmap 5.0.0-alpha.9 → 5.0.0-beta.2
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 +19 -0
- package/dist/client/index.js +3 -2
- package/dist/client/index2.js +7 -1
- package/dist/client/index3.js +586 -17
- package/dist/client/index4.js +4 -1
- package/dist/client/index5.js +50 -0
- package/dist/physics.d.ts +7 -0
- package/dist/server/index.js +1 -1
- package/dist/server/index2.js +6 -84
- package/dist/server/index3.js +7 -296
- package/dist/server/index4.js +72 -0
- package/dist/server.d.ts +0 -53
- package/package.json +11 -11
- package/src/client.ts +9 -3
- package/src/index.ts +5 -1
- package/src/physics.spec.ts +90 -0
- package/src/physics.ts +98 -0
- package/src/server.ts +6 -152
- package/src/tiled.ce +5 -1
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { MapClass } from "./index3.js";
|
|
2
|
+
const TILED_HITBOX_ID_PREFIX = "__tiled_collision__:";
|
|
3
|
+
function prepareTiledPhysicsData(mapData, map) {
|
|
4
|
+
if (!mapData?.parsedMap) {
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
const tiledMap = new MapClass(mapData.parsedMap);
|
|
8
|
+
map.tiled = tiledMap;
|
|
9
|
+
const tiledHitboxes = collectBlockedTileHitboxes(tiledMap);
|
|
10
|
+
mapData.hitboxes = mergeTiledHitboxes(mapData.hitboxes, tiledHitboxes);
|
|
11
|
+
mapData.width = tiledMap.widthPx;
|
|
12
|
+
mapData.height = tiledMap.heightPx;
|
|
13
|
+
}
|
|
14
|
+
function collectBlockedTileHitboxes(tiledMap) {
|
|
15
|
+
const hitboxes = [];
|
|
16
|
+
const mapWidth = tiledMap.width;
|
|
17
|
+
const mapHeight = tiledMap.height;
|
|
18
|
+
const tileWidth = tiledMap.tilewidth;
|
|
19
|
+
const tileHeight = tiledMap.tileheight;
|
|
20
|
+
for (let y = 0; y < mapHeight; y++) {
|
|
21
|
+
for (let x = 0; x < mapWidth; x++) {
|
|
22
|
+
const tileInfo = tiledMap.getTileByPosition(x * tileWidth, y * tileHeight, [0, 0], {
|
|
23
|
+
populateTiles: true
|
|
24
|
+
});
|
|
25
|
+
if (tileInfo.hasCollision) {
|
|
26
|
+
hitboxes.push({
|
|
27
|
+
id: createTiledHitboxId(x, y),
|
|
28
|
+
x: x * tileWidth,
|
|
29
|
+
y: y * tileHeight,
|
|
30
|
+
width: tileWidth,
|
|
31
|
+
height: tileHeight
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return hitboxes;
|
|
37
|
+
}
|
|
38
|
+
function mergeTiledHitboxes(existingHitboxes, tiledHitboxes) {
|
|
39
|
+
const preservedHitboxes = Array.isArray(existingHitboxes) ? existingHitboxes.filter((hitbox) => !isGeneratedTiledHitbox(hitbox)) : [];
|
|
40
|
+
return [...preservedHitboxes, ...tiledHitboxes];
|
|
41
|
+
}
|
|
42
|
+
function isGeneratedTiledHitbox(hitbox) {
|
|
43
|
+
return typeof hitbox?.id === "string" && hitbox.id.startsWith(TILED_HITBOX_ID_PREFIX);
|
|
44
|
+
}
|
|
45
|
+
function createTiledHitboxId(x, y) {
|
|
46
|
+
return `${TILED_HITBOX_ID_PREFIX}${x},${y}`;
|
|
47
|
+
}
|
|
48
|
+
export {
|
|
49
|
+
prepareTiledPhysicsData
|
|
50
|
+
};
|
package/dist/server/index.js
CHANGED
package/dist/server/index2.js
CHANGED
|
@@ -1,92 +1,14 @@
|
|
|
1
|
-
import { MapClass } from "./index3.js";
|
|
2
1
|
import { defineModule } from "@rpgjs/common";
|
|
2
|
+
import { prepareTiledPhysicsData, applyTiledPointEvents } from "./index4.js";
|
|
3
3
|
const server = defineModule({
|
|
4
4
|
map: {
|
|
5
|
-
/**
|
|
6
|
-
* Hook called before map update
|
|
7
|
-
*
|
|
8
|
-
* @description Parses Tiled data and creates collision hitboxes
|
|
9
|
-
* automatically by iterating through all tiles on the map.
|
|
10
|
-
*
|
|
11
|
-
* This method:
|
|
12
|
-
* 1. Parses TMX data with TiledParser
|
|
13
|
-
* 2. Creates a MapClass instance with parsed data
|
|
14
|
-
* 3. Attaches the Tiled instance to the RpgMap
|
|
15
|
-
* 4. Scans all tiles to detect collisions
|
|
16
|
-
* 5. Automatically creates hitboxes for each collision tile
|
|
17
|
-
*
|
|
18
|
-
* @param mapData - Map data containing TMX information
|
|
19
|
-
* @param map - RpgMap instance to extend
|
|
20
|
-
* @returns The modified map instance with tiled property
|
|
21
|
-
*
|
|
22
|
-
* @example
|
|
23
|
-
* ```ts
|
|
24
|
-
* // Created hitboxes will have this structure:
|
|
25
|
-
* {
|
|
26
|
-
* id: 'collision_x_y', // Unique identifier
|
|
27
|
-
* x: x * tileWidth, // X position in pixels
|
|
28
|
-
* y: y * tileHeight, // Y position in pixels
|
|
29
|
-
* width: tileWidth, // Tile width
|
|
30
|
-
* height: tileHeight, // Tile height
|
|
31
|
-
* properties: {
|
|
32
|
-
* type: 'collision', // Hitbox type
|
|
33
|
-
* tileX: x, // X position in tiles
|
|
34
|
-
* tileY: y, // Y position in tiles
|
|
35
|
-
* tileIndex: tileIndex // Tile index
|
|
36
|
-
* }
|
|
37
|
-
* }
|
|
38
|
-
* ```
|
|
39
|
-
*/
|
|
40
5
|
onBeforeUpdate(mapData, map) {
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
mapData.hitboxes = mapData.hitboxes || [];
|
|
44
|
-
mapData.width = tiledMap.widthPx;
|
|
45
|
-
mapData.height = tiledMap.heightPx;
|
|
46
|
-
const mapWidth = tiledMap.width;
|
|
47
|
-
const mapHeight = tiledMap.height;
|
|
48
|
-
const tileWidth = tiledMap.tilewidth;
|
|
49
|
-
const tileHeight = tiledMap.tileheight;
|
|
50
|
-
for (let y = 0; y < mapHeight; y++) {
|
|
51
|
-
for (let x = 0; x < mapWidth; x++) {
|
|
52
|
-
const pixelX = x * tileWidth;
|
|
53
|
-
const pixelY = y * tileHeight;
|
|
54
|
-
const tileInfo = tiledMap.getTileByPosition(pixelX, pixelY, [0, 0], {
|
|
55
|
-
populateTiles: true
|
|
56
|
-
});
|
|
57
|
-
if (tileInfo.hasCollision) {
|
|
58
|
-
const hitbox = {
|
|
59
|
-
id: `collision_${x}_${y}`,
|
|
60
|
-
x: pixelX,
|
|
61
|
-
y: pixelY,
|
|
62
|
-
width: tileWidth,
|
|
63
|
-
height: tileHeight,
|
|
64
|
-
properties: {
|
|
65
|
-
type: "collision",
|
|
66
|
-
tileX: x,
|
|
67
|
-
tileY: y,
|
|
68
|
-
tileIndex: tileInfo.tileIndex
|
|
69
|
-
}
|
|
70
|
-
};
|
|
71
|
-
mapData.hitboxes.push(hitbox);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
for (let obj of mapData.parsedMap.objects) {
|
|
76
|
-
if (obj.point) {
|
|
77
|
-
mapData.events = mapData.events.map((e) => {
|
|
78
|
-
if (e.name === obj.name) {
|
|
79
|
-
return {
|
|
80
|
-
event: e,
|
|
81
|
-
x: obj.x,
|
|
82
|
-
y: obj.y
|
|
83
|
-
};
|
|
84
|
-
}
|
|
85
|
-
return e;
|
|
86
|
-
}).filter((e) => e !== null);
|
|
87
|
-
}
|
|
88
|
-
}
|
|
6
|
+
prepareTiledPhysicsData(mapData, map);
|
|
7
|
+
applyTiledPointEvents(mapData);
|
|
89
8
|
return map;
|
|
9
|
+
},
|
|
10
|
+
onPhysicsInit(map, context) {
|
|
11
|
+
prepareTiledPhysicsData(context?.mapData, map);
|
|
90
12
|
}
|
|
91
13
|
}
|
|
92
14
|
});
|
package/dist/server/index3.js
CHANGED
|
@@ -5,9 +5,6 @@ var TiledLayerType = /* @__PURE__ */ ((TiledLayerType2) => {
|
|
|
5
5
|
TiledLayerType2["Group"] = "group";
|
|
6
6
|
return TiledLayerType2;
|
|
7
7
|
})(TiledLayerType || {});
|
|
8
|
-
function joinPath(...segments) {
|
|
9
|
-
return segments.filter((segment) => segment && segment.length > 0).join("/").replace(/\/+/g, "/");
|
|
10
|
-
}
|
|
11
8
|
function getAugmentedNamespace(n) {
|
|
12
9
|
if (Object.prototype.hasOwnProperty.call(n, "__esModule")) return n;
|
|
13
10
|
var f = n.default;
|
|
@@ -142,7 +139,6 @@ function requireBase64Js() {
|
|
|
142
139
|
return base64Js;
|
|
143
140
|
}
|
|
144
141
|
var ieee754 = {};
|
|
145
|
-
/*! ieee754. BSD-3-Clause License. Feross Aboukhadijeh <https://feross.org/opensource> */
|
|
146
142
|
var hasRequiredIeee754;
|
|
147
143
|
function requireIeee754() {
|
|
148
144
|
if (hasRequiredIeee754) return ieee754;
|
|
@@ -226,12 +222,6 @@ function requireIeee754() {
|
|
|
226
222
|
};
|
|
227
223
|
return ieee754;
|
|
228
224
|
}
|
|
229
|
-
/*!
|
|
230
|
-
* The buffer module from node.js, for the browser.
|
|
231
|
-
*
|
|
232
|
-
* @author Feross Aboukhadijeh <https://feross.org>
|
|
233
|
-
* @license MIT
|
|
234
|
-
*/
|
|
235
225
|
var hasRequiredBuffer;
|
|
236
226
|
function requireBuffer() {
|
|
237
227
|
if (hasRequiredBuffer) return buffer;
|
|
@@ -1803,7 +1793,7 @@ function requireBuffer() {
|
|
|
1803
1793
|
function numberIsNaN(obj) {
|
|
1804
1794
|
return obj !== obj;
|
|
1805
1795
|
}
|
|
1806
|
-
const hexSliceLookupTable = function() {
|
|
1796
|
+
const hexSliceLookupTable = (function() {
|
|
1807
1797
|
const alphabet = "0123456789abcdef";
|
|
1808
1798
|
const table = new Array(256);
|
|
1809
1799
|
for (let i = 0; i < 16; ++i) {
|
|
@@ -1813,7 +1803,7 @@ function requireBuffer() {
|
|
|
1813
1803
|
}
|
|
1814
1804
|
}
|
|
1815
1805
|
return table;
|
|
1816
|
-
}();
|
|
1806
|
+
})();
|
|
1817
1807
|
function defineBigIntMethod(fn) {
|
|
1818
1808
|
return typeof BigInt === "undefined" ? BufferBigIntNotDefined : fn;
|
|
1819
1809
|
}
|
|
@@ -1823,7 +1813,6 @@ function requireBuffer() {
|
|
|
1823
1813
|
})(buffer);
|
|
1824
1814
|
return buffer;
|
|
1825
1815
|
}
|
|
1826
|
-
/*! safe-buffer. MIT License. Feross Aboukhadijeh <https://feross.org/opensource> */
|
|
1827
1816
|
var hasRequiredSafeBuffer;
|
|
1828
1817
|
function requireSafeBuffer() {
|
|
1829
1818
|
if (hasRequiredSafeBuffer) return safeBuffer.exports;
|
|
@@ -3531,7 +3520,6 @@ function requireSax() {
|
|
|
3531
3520
|
}
|
|
3532
3521
|
return parser;
|
|
3533
3522
|
}
|
|
3534
|
-
/*! http://mths.be/fromcodepoint v0.1.0 by @mathias */
|
|
3535
3523
|
if (!String.fromCodePoint) {
|
|
3536
3524
|
(function() {
|
|
3537
3525
|
var stringFromCharCode = String.fromCharCode;
|
|
@@ -4376,288 +4364,12 @@ function requireLib() {
|
|
|
4376
4364
|
};
|
|
4377
4365
|
return lib;
|
|
4378
4366
|
}
|
|
4379
|
-
|
|
4380
|
-
|
|
4381
|
-
const _TiledParser = class _TiledParser {
|
|
4382
|
-
constructor(xml, filePath = "", basePath = "") {
|
|
4383
|
-
this.xml = xml;
|
|
4384
|
-
this.filePath = filePath;
|
|
4385
|
-
this.basePath = basePath;
|
|
4386
|
-
this.layers = /* @__PURE__ */ new Map();
|
|
4387
|
-
this.transform = (obj) => {
|
|
4388
|
-
var _a, _b;
|
|
4389
|
-
if (!obj) return;
|
|
4390
|
-
const attr = obj.attributes || obj._attributes;
|
|
4391
|
-
if (!attr) return obj;
|
|
4392
|
-
let newObj = {
|
|
4393
|
-
...obj,
|
|
4394
|
-
...attr,
|
|
4395
|
-
..._TiledParser.propToNumber(attr, [
|
|
4396
|
-
"version",
|
|
4397
|
-
"width",
|
|
4398
|
-
"height",
|
|
4399
|
-
"tilewidth",
|
|
4400
|
-
"tileheight",
|
|
4401
|
-
"nextlayerid",
|
|
4402
|
-
"nextobjectid",
|
|
4403
|
-
"hexsidelength",
|
|
4404
|
-
"opacity",
|
|
4405
|
-
"x",
|
|
4406
|
-
"y",
|
|
4407
|
-
"offsetx",
|
|
4408
|
-
"offsety",
|
|
4409
|
-
"startx",
|
|
4410
|
-
"starty",
|
|
4411
|
-
"id",
|
|
4412
|
-
"firstgid",
|
|
4413
|
-
"imageheight",
|
|
4414
|
-
"imagewidth",
|
|
4415
|
-
"margin",
|
|
4416
|
-
"columns",
|
|
4417
|
-
"rows",
|
|
4418
|
-
"tilecount",
|
|
4419
|
-
"rotation",
|
|
4420
|
-
"gid",
|
|
4421
|
-
"tileid",
|
|
4422
|
-
"duration",
|
|
4423
|
-
"parallaxx",
|
|
4424
|
-
"parallaxy",
|
|
4425
|
-
"repeatx",
|
|
4426
|
-
"repeaty",
|
|
4427
|
-
"pixelsize"
|
|
4428
|
-
]),
|
|
4429
|
-
..._TiledParser.propToBool(attr, [
|
|
4430
|
-
"visible",
|
|
4431
|
-
"infinite",
|
|
4432
|
-
"locked",
|
|
4433
|
-
"bold",
|
|
4434
|
-
"italic",
|
|
4435
|
-
"kerning",
|
|
4436
|
-
"strikeout",
|
|
4437
|
-
"underline",
|
|
4438
|
-
"wrap"
|
|
4439
|
-
])
|
|
4440
|
-
};
|
|
4441
|
-
if (newObj.properties) {
|
|
4442
|
-
const properties = _TiledParser.toArray(newObj.properties.property);
|
|
4443
|
-
const propObj = {};
|
|
4444
|
-
for (let prop of properties) {
|
|
4445
|
-
const attr2 = prop._attributes;
|
|
4446
|
-
if (!attr2) continue;
|
|
4447
|
-
let val;
|
|
4448
|
-
switch (attr2.type) {
|
|
4449
|
-
case "file":
|
|
4450
|
-
val = this.getImagePath(attr2.value);
|
|
4451
|
-
break;
|
|
4452
|
-
case "object":
|
|
4453
|
-
case "float":
|
|
4454
|
-
case "int":
|
|
4455
|
-
val = +attr2.value;
|
|
4456
|
-
break;
|
|
4457
|
-
case "bool":
|
|
4458
|
-
val = attr2.value == "true" ? true : false;
|
|
4459
|
-
break;
|
|
4460
|
-
case "class":
|
|
4461
|
-
val = {
|
|
4462
|
-
...((_a = this.transform(prop)) == null ? void 0 : _a.properties) ?? {},
|
|
4463
|
-
_classname: attr2.propertytype
|
|
4464
|
-
};
|
|
4465
|
-
break;
|
|
4466
|
-
default:
|
|
4467
|
-
val = attr2.value;
|
|
4468
|
-
}
|
|
4469
|
-
propObj[attr2.name] = val;
|
|
4470
|
-
}
|
|
4471
|
-
newObj.properties = propObj;
|
|
4472
|
-
}
|
|
4473
|
-
if (newObj.polygon) {
|
|
4474
|
-
newObj.polygon = this.transform(newObj.polygon);
|
|
4475
|
-
}
|
|
4476
|
-
if (newObj.polyline) {
|
|
4477
|
-
newObj.polyline = this.transform(newObj.polyline);
|
|
4478
|
-
}
|
|
4479
|
-
if (newObj.points) {
|
|
4480
|
-
newObj = newObj.points.split(" ").map((point) => {
|
|
4481
|
-
const pos = point.split(",");
|
|
4482
|
-
return { x: +pos[0], y: +pos[1] };
|
|
4483
|
-
});
|
|
4484
|
-
}
|
|
4485
|
-
if (newObj.point) {
|
|
4486
|
-
newObj.point = true;
|
|
4487
|
-
}
|
|
4488
|
-
if (newObj.ellipse) {
|
|
4489
|
-
newObj.ellipse = true;
|
|
4490
|
-
}
|
|
4491
|
-
if (newObj.text) {
|
|
4492
|
-
newObj.text = {
|
|
4493
|
-
text: newObj.text._text,
|
|
4494
|
-
...this.transform(newObj.text)
|
|
4495
|
-
};
|
|
4496
|
-
delete newObj.text._text;
|
|
4497
|
-
}
|
|
4498
|
-
if (newObj.image) {
|
|
4499
|
-
newObj.image = this.transform(newObj.image);
|
|
4500
|
-
}
|
|
4501
|
-
if (newObj.source) {
|
|
4502
|
-
if (!this.isTilesetSource(newObj)) {
|
|
4503
|
-
newObj.source = this.getImagePath(newObj.source);
|
|
4504
|
-
}
|
|
4505
|
-
}
|
|
4506
|
-
const objectgroup = newObj.object || ((_b = newObj.objectgroup) == null ? void 0 : _b.object);
|
|
4507
|
-
if (objectgroup) {
|
|
4508
|
-
newObj.objects = _TiledParser.toArray(objectgroup).map((object) => {
|
|
4509
|
-
return this.transform(object);
|
|
4510
|
-
});
|
|
4511
|
-
}
|
|
4512
|
-
delete newObj._attributes;
|
|
4513
|
-
delete newObj.attributes;
|
|
4514
|
-
delete newObj.object;
|
|
4515
|
-
delete newObj.objectgroup;
|
|
4516
|
-
return newObj;
|
|
4517
|
-
};
|
|
4518
|
-
}
|
|
4519
|
-
static toArray(prop) {
|
|
4520
|
-
if (!prop) return [];
|
|
4521
|
-
if (!Array.isArray(prop)) return [prop];
|
|
4522
|
-
return prop;
|
|
4523
|
-
}
|
|
4524
|
-
getImagePath(image) {
|
|
4525
|
-
if (this.filePath.startsWith("http")) return new URL(image, this.filePath).href;
|
|
4526
|
-
return joinPath(this.basePath, image);
|
|
4527
|
-
}
|
|
4528
|
-
/**
|
|
4529
|
-
* Check if the object is a tileset source reference
|
|
4530
|
-
* Tileset sources should not have their paths transformed with getImagePath
|
|
4531
|
-
*/
|
|
4532
|
-
isTilesetSource(obj) {
|
|
4533
|
-
return obj.firstgid !== void 0 || obj.tilewidth !== void 0 || obj.tileheight !== void 0 || obj.tilecount !== void 0 || obj.columns !== void 0;
|
|
4534
|
-
}
|
|
4535
|
-
static unpackTileBytes(buffer2, size) {
|
|
4536
|
-
const expectedCount = size * 4;
|
|
4537
|
-
if (buffer2.length !== expectedCount) {
|
|
4538
|
-
throw new Error("Expected " + expectedCount + " bytes of tile data; received " + buffer2.length);
|
|
4539
|
-
}
|
|
4540
|
-
let tileIndex = 0;
|
|
4541
|
-
const array = [];
|
|
4542
|
-
for (let i = 0; i < expectedCount; i += 4) {
|
|
4543
|
-
array[tileIndex] = buffer2.readUInt32LE(i);
|
|
4544
|
-
tileIndex++;
|
|
4545
|
-
}
|
|
4546
|
-
return array;
|
|
4547
|
-
}
|
|
4548
|
-
static decode(obj, size) {
|
|
4549
|
-
const { encoding, data } = obj;
|
|
4550
|
-
if (encoding == "base64") {
|
|
4551
|
-
return _TiledParser.unpackTileBytes(bufferExports.Buffer.from(data.trim(), "base64"), size);
|
|
4552
|
-
} else if (encoding == "csv") {
|
|
4553
|
-
return data.trim().split(",").map((x) => +x);
|
|
4554
|
-
}
|
|
4555
|
-
return data;
|
|
4556
|
-
}
|
|
4557
|
-
parseMap() {
|
|
4558
|
-
const json = libExports.xml2js(this.xml, { compact: true });
|
|
4559
|
-
const jsonNoCompact = libExports.xml2js(this.xml);
|
|
4560
|
-
const tileset = json.map.tileset;
|
|
4561
|
-
json.map.group;
|
|
4562
|
-
const recursiveObjectGroup = (obj) => {
|
|
4563
|
-
const { objectgroup, group: group2, layer, imagelayer } = obj;
|
|
4564
|
-
const setLayer = (type) => {
|
|
4565
|
-
if (!type) return;
|
|
4566
|
-
_TiledParser.toArray(type).forEach((val) => {
|
|
4567
|
-
if (this.layers.has(+val._attributes.id)) {
|
|
4568
|
-
throw new Error(`Tiled Parser Error: Layer with id ${val._attributes.id} already exists`);
|
|
4569
|
-
}
|
|
4570
|
-
this.layers.set(+val._attributes.id, val);
|
|
4571
|
-
});
|
|
4572
|
-
};
|
|
4573
|
-
setLayer(objectgroup);
|
|
4574
|
-
setLayer(layer);
|
|
4575
|
-
setLayer(group2);
|
|
4576
|
-
setLayer(imagelayer);
|
|
4577
|
-
if (group2) {
|
|
4578
|
-
recursiveObjectGroup(group2);
|
|
4579
|
-
}
|
|
4580
|
-
};
|
|
4581
|
-
recursiveObjectGroup(json.map);
|
|
4582
|
-
const recursiveLayer = (elements, array = []) => {
|
|
4583
|
-
var _a;
|
|
4584
|
-
if (!elements) return array;
|
|
4585
|
-
for (let element of elements) {
|
|
4586
|
-
const { name } = element;
|
|
4587
|
-
if (!["layer", "group", "imagelayer", "objectgroup"].includes(name)) continue;
|
|
4588
|
-
const data = (_a = element.elements) == null ? void 0 : _a.find((el) => el.name == "data");
|
|
4589
|
-
element.layer = this.layers.get(+element.attributes.id);
|
|
4590
|
-
const obj = {
|
|
4591
|
-
...this.transform(data) ?? {},
|
|
4592
|
-
...this.transform(element),
|
|
4593
|
-
...this.transform(element.layer),
|
|
4594
|
-
layers: recursiveLayer(element.elements),
|
|
4595
|
-
data: data ? data.elements[0].text : void 0,
|
|
4596
|
-
type: name == "layer" ? "tilelayer" : name
|
|
4597
|
-
};
|
|
4598
|
-
delete obj.elements;
|
|
4599
|
-
delete obj.layer;
|
|
4600
|
-
if (obj.data) obj.data = _TiledParser.decode(obj, obj.width * obj.height);
|
|
4601
|
-
array.push(obj);
|
|
4602
|
-
}
|
|
4603
|
-
return array;
|
|
4604
|
-
};
|
|
4605
|
-
const layers = recursiveLayer(jsonNoCompact.elements[0].elements);
|
|
4606
|
-
const tilesets = _TiledParser.toArray(tileset).map((tileset2) => {
|
|
4607
|
-
const obj = this.transform(tileset2);
|
|
4608
|
-
return obj;
|
|
4609
|
-
});
|
|
4610
|
-
const ret = {
|
|
4611
|
-
...this.transform(json.map),
|
|
4612
|
-
layers,
|
|
4613
|
-
tilesets
|
|
4614
|
-
};
|
|
4615
|
-
delete ret.layer;
|
|
4616
|
-
delete ret.tileset;
|
|
4617
|
-
delete ret.group;
|
|
4618
|
-
delete ret.imagelayer;
|
|
4619
|
-
return ret;
|
|
4620
|
-
}
|
|
4621
|
-
parseTileset() {
|
|
4622
|
-
const json = libExports.xml2js(this.xml, { compact: true });
|
|
4623
|
-
const { tileset } = json;
|
|
4624
|
-
const ret = {
|
|
4625
|
-
...this.transform(tileset),
|
|
4626
|
-
image: this.transform(tileset.image),
|
|
4627
|
-
tiles: _TiledParser.toArray(tileset.tile).map((tile) => {
|
|
4628
|
-
const ret2 = this.transform(tile);
|
|
4629
|
-
if (tile.animation) {
|
|
4630
|
-
ret2.animations = _TiledParser.toArray(tile.animation.frame).map(this.transform);
|
|
4631
|
-
}
|
|
4632
|
-
delete ret2.animation;
|
|
4633
|
-
return ret2;
|
|
4634
|
-
})
|
|
4635
|
-
};
|
|
4636
|
-
delete ret.tile;
|
|
4637
|
-
return ret;
|
|
4638
|
-
}
|
|
4639
|
-
};
|
|
4640
|
-
_TiledParser.propToNumber = (obj, props) => {
|
|
4641
|
-
for (let key of props) {
|
|
4642
|
-
if (obj[key] !== void 0) {
|
|
4643
|
-
obj[key] = +obj[key];
|
|
4644
|
-
}
|
|
4645
|
-
}
|
|
4646
|
-
return obj;
|
|
4647
|
-
};
|
|
4648
|
-
_TiledParser.propToBool = (obj, props) => {
|
|
4649
|
-
for (let key of props) {
|
|
4650
|
-
if (obj[key] !== void 0) {
|
|
4651
|
-
obj[key] = obj[key] == "true" || obj[key] == "1";
|
|
4652
|
-
}
|
|
4653
|
-
}
|
|
4654
|
-
return obj;
|
|
4655
|
-
};
|
|
4656
|
-
let TiledParser = _TiledParser;
|
|
4367
|
+
requireLib();
|
|
4368
|
+
requireBuffer();
|
|
4657
4369
|
class TiledProperties {
|
|
4658
4370
|
constructor(data) {
|
|
4659
4371
|
this.properties = {};
|
|
4660
|
-
this.properties =
|
|
4372
|
+
this.properties = data?.properties ?? {};
|
|
4661
4373
|
}
|
|
4662
4374
|
getProperty(name, defaultValue) {
|
|
4663
4375
|
const val = this.properties[name];
|
|
@@ -4684,7 +4396,7 @@ class TileGid extends TiledProperties {
|
|
|
4684
4396
|
constructor(obj) {
|
|
4685
4397
|
super(obj);
|
|
4686
4398
|
this.obj = obj;
|
|
4687
|
-
this._gid = obj
|
|
4399
|
+
this._gid = obj?.gid;
|
|
4688
4400
|
}
|
|
4689
4401
|
static getRealGid(gid) {
|
|
4690
4402
|
return gid & 268435455;
|
|
@@ -4725,7 +4437,7 @@ class TiledObjectClass extends TileGid {
|
|
|
4725
4437
|
super(object);
|
|
4726
4438
|
this.layerName = "";
|
|
4727
4439
|
Object.assign(this, object);
|
|
4728
|
-
if (object
|
|
4440
|
+
if (object?.gid) {
|
|
4729
4441
|
this.y -= this.height;
|
|
4730
4442
|
}
|
|
4731
4443
|
}
|
|
@@ -5226,7 +4938,6 @@ export {
|
|
|
5226
4938
|
Tile,
|
|
5227
4939
|
TiledLayerType,
|
|
5228
4940
|
TiledObjectClass,
|
|
5229
|
-
TiledParser,
|
|
5230
4941
|
TiledProperties,
|
|
5231
4942
|
Tileset
|
|
5232
4943
|
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
import { MapClass } from "./index3.js";
|
|
2
|
+
const TILED_HITBOX_ID_PREFIX = "__tiled_collision__:";
|
|
3
|
+
function prepareTiledPhysicsData(mapData, map) {
|
|
4
|
+
if (!mapData?.parsedMap) {
|
|
5
|
+
return;
|
|
6
|
+
}
|
|
7
|
+
const tiledMap = new MapClass(mapData.parsedMap);
|
|
8
|
+
map.tiled = tiledMap;
|
|
9
|
+
const tiledHitboxes = collectBlockedTileHitboxes(tiledMap);
|
|
10
|
+
mapData.hitboxes = mergeTiledHitboxes(mapData.hitboxes, tiledHitboxes);
|
|
11
|
+
mapData.width = tiledMap.widthPx;
|
|
12
|
+
mapData.height = tiledMap.heightPx;
|
|
13
|
+
}
|
|
14
|
+
function applyTiledPointEvents(mapData) {
|
|
15
|
+
const objects = mapData?.parsedMap?.objects;
|
|
16
|
+
if (!Array.isArray(objects) || !Array.isArray(mapData?.events)) {
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
for (const obj of objects) {
|
|
20
|
+
if (!obj?.point) {
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
mapData.events = mapData.events.map((eventEntry) => {
|
|
24
|
+
if (eventEntry?.name === obj.name) {
|
|
25
|
+
return {
|
|
26
|
+
event: eventEntry,
|
|
27
|
+
x: obj.x,
|
|
28
|
+
y: obj.y
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
return eventEntry;
|
|
32
|
+
}).filter((eventEntry) => eventEntry !== null);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
function collectBlockedTileHitboxes(tiledMap) {
|
|
36
|
+
const hitboxes = [];
|
|
37
|
+
const mapWidth = tiledMap.width;
|
|
38
|
+
const mapHeight = tiledMap.height;
|
|
39
|
+
const tileWidth = tiledMap.tilewidth;
|
|
40
|
+
const tileHeight = tiledMap.tileheight;
|
|
41
|
+
for (let y = 0; y < mapHeight; y++) {
|
|
42
|
+
for (let x = 0; x < mapWidth; x++) {
|
|
43
|
+
const tileInfo = tiledMap.getTileByPosition(x * tileWidth, y * tileHeight, [0, 0], {
|
|
44
|
+
populateTiles: true
|
|
45
|
+
});
|
|
46
|
+
if (tileInfo.hasCollision) {
|
|
47
|
+
hitboxes.push({
|
|
48
|
+
id: createTiledHitboxId(x, y),
|
|
49
|
+
x: x * tileWidth,
|
|
50
|
+
y: y * tileHeight,
|
|
51
|
+
width: tileWidth,
|
|
52
|
+
height: tileHeight
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
return hitboxes;
|
|
58
|
+
}
|
|
59
|
+
function mergeTiledHitboxes(existingHitboxes, tiledHitboxes) {
|
|
60
|
+
const preservedHitboxes = Array.isArray(existingHitboxes) ? existingHitboxes.filter((hitbox) => !isGeneratedTiledHitbox(hitbox)) : [];
|
|
61
|
+
return [...preservedHitboxes, ...tiledHitboxes];
|
|
62
|
+
}
|
|
63
|
+
function isGeneratedTiledHitbox(hitbox) {
|
|
64
|
+
return typeof hitbox?.id === "string" && hitbox.id.startsWith(TILED_HITBOX_ID_PREFIX);
|
|
65
|
+
}
|
|
66
|
+
function createTiledHitboxId(x, y) {
|
|
67
|
+
return `${TILED_HITBOX_ID_PREFIX}${x},${y}`;
|
|
68
|
+
}
|
|
69
|
+
export {
|
|
70
|
+
applyTiledPointEvents,
|
|
71
|
+
prepareTiledPhysicsData
|
|
72
|
+
};
|
package/dist/server.d.ts
CHANGED
|
@@ -5,61 +5,8 @@ declare module "@rpgjs/server" {
|
|
|
5
5
|
tiled?: MapClass;
|
|
6
6
|
}
|
|
7
7
|
}
|
|
8
|
-
/**
|
|
9
|
-
* Interface for an RpgMap extended with Tiled functionality
|
|
10
|
-
*
|
|
11
|
-
* @description This interface combines RpgMap with MapClass to enable
|
|
12
|
-
* the use of Tiled methods on RPG maps
|
|
13
|
-
*/
|
|
14
8
|
export interface RpgTiledMap extends RpgMap {
|
|
15
9
|
tiled: MapClass;
|
|
16
10
|
}
|
|
17
|
-
/**
|
|
18
|
-
* Tiled Module for RPGJS
|
|
19
|
-
*
|
|
20
|
-
* @description This module extends RPGJS maps with Tiled functionality,
|
|
21
|
-
* allowing TMX map parsing and automatic hitbox creation
|
|
22
|
-
* based on collisions defined in Tiled
|
|
23
|
-
*
|
|
24
|
-
* ## Features
|
|
25
|
-
*
|
|
26
|
-
* - **Automatic parsing**: Parses TMX files from Tiled Map Editor
|
|
27
|
-
* - **Collision detection**: Scans all tiles to detect collisions
|
|
28
|
-
* - **Hitbox creation**: Automatically generates hitboxes for each collision tile
|
|
29
|
-
* - **RpgMap extension**: Adds the `tiled` property to all RpgMap instances
|
|
30
|
-
*
|
|
31
|
-
* ## Usage
|
|
32
|
-
*
|
|
33
|
-
* Once this module is activated, you can use Tiled methods on your maps:
|
|
34
|
-
*
|
|
35
|
-
* @example
|
|
36
|
-
* ```ts
|
|
37
|
-
* // In a map class
|
|
38
|
-
* class MyMap extends RpgMap {
|
|
39
|
-
* onLoad() {
|
|
40
|
-
* // Access Tiled functionality
|
|
41
|
-
* const tiles = this.tiled.getTileByPosition(100, 100);
|
|
42
|
-
*
|
|
43
|
-
* if (tiles.hasCollision) {
|
|
44
|
-
* console.log('This position has a collision');
|
|
45
|
-
* }
|
|
46
|
-
*
|
|
47
|
-
* // Iterate through all tiles by index
|
|
48
|
-
* for (let i = 0; i < this.tiled.width * this.tiled.height; i++) {
|
|
49
|
-
* const tileInfo = this.tiled.getTileByIndex(i);
|
|
50
|
-
* if (tileInfo.hasCollision) {
|
|
51
|
-
* console.log(`Tile ${i} has collision`);
|
|
52
|
-
* }
|
|
53
|
-
* }
|
|
54
|
-
*
|
|
55
|
-
* // Get information about a specific layer
|
|
56
|
-
* const layer = this.tiled.getLayerByName('Collision');
|
|
57
|
-
* if (layer) {
|
|
58
|
-
* console.log('Collision layer found:', layer);
|
|
59
|
-
* }
|
|
60
|
-
* }
|
|
61
|
-
* }
|
|
62
|
-
* ```
|
|
63
|
-
*/
|
|
64
11
|
declare const _default: any;
|
|
65
12
|
export default _default;
|