@rpgjs/tiledmap 5.0.0-beta.7 → 5.0.0-beta.8
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/CHANGELOG.md +15 -0
- package/dist/client/index3.js +24 -0
- package/dist/server/index3.js +40 -2
- package/package.json +5 -5
- package/src/physics.spec.ts +156 -1
- package/src/physics.ts +73 -2
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# @rpgjs/tiledmap
|
|
2
|
+
|
|
3
|
+
## 5.0.0-beta.8
|
|
4
|
+
|
|
5
|
+
### Major Changes
|
|
6
|
+
|
|
7
|
+
- 35e7fa4: beta.8
|
|
8
|
+
|
|
9
|
+
### Patch Changes
|
|
10
|
+
|
|
11
|
+
- Updated dependencies [35e7fa4]
|
|
12
|
+
- @rpgjs/client@5.0.0-beta.8
|
|
13
|
+
- @rpgjs/common@5.0.0-beta.8
|
|
14
|
+
- @rpgjs/server@5.0.0-beta.8
|
|
15
|
+
- @rpgjs/vite@5.0.0-beta.8
|
package/dist/client/index3.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { MapClass } from "./index2.js";
|
|
2
2
|
//#region src/physics.ts
|
|
3
3
|
var TILED_HITBOX_ID_PREFIX = "__tiled_collision__:";
|
|
4
|
+
var START_POSITION_NAME = "start";
|
|
4
5
|
function prepareTiledPhysicsData(mapData, map) {
|
|
5
6
|
if (!mapData?.parsedMap) return;
|
|
6
7
|
const tiledMap = new MapClass(mapData.parsedMap);
|
|
@@ -9,6 +10,29 @@ function prepareTiledPhysicsData(mapData, map) {
|
|
|
9
10
|
mapData.hitboxes = mergeTiledHitboxes(mapData.hitboxes, tiledHitboxes);
|
|
10
11
|
mapData.width = tiledMap.widthPx;
|
|
11
12
|
mapData.height = tiledMap.heightPx;
|
|
13
|
+
mapData.positions = mergeTiledPositions(mapData.positions, collectTiledPointPositions(mapData.parsedMap.objects));
|
|
14
|
+
}
|
|
15
|
+
function collectTiledPointPositions(objects) {
|
|
16
|
+
if (!Array.isArray(objects)) return {};
|
|
17
|
+
const positions = {};
|
|
18
|
+
for (const obj of objects) {
|
|
19
|
+
if (!obj?.point || typeof obj.x !== "number" || typeof obj.y !== "number") continue;
|
|
20
|
+
if (typeof obj.name === "string" && obj.name.length > 0) positions[obj.name] = {
|
|
21
|
+
x: obj.x,
|
|
22
|
+
y: obj.y
|
|
23
|
+
};
|
|
24
|
+
if (!positions[START_POSITION_NAME] && (obj.class === START_POSITION_NAME || obj.type === START_POSITION_NAME)) positions[START_POSITION_NAME] = {
|
|
25
|
+
x: obj.x,
|
|
26
|
+
y: obj.y
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
return positions;
|
|
30
|
+
}
|
|
31
|
+
function mergeTiledPositions(existingPositions, tiledPositions) {
|
|
32
|
+
return {
|
|
33
|
+
...existingPositions && typeof existingPositions === "object" ? existingPositions : {},
|
|
34
|
+
...tiledPositions
|
|
35
|
+
};
|
|
12
36
|
}
|
|
13
37
|
function collectBlockedTileHitboxes(tiledMap) {
|
|
14
38
|
const hitboxes = [];
|
package/dist/server/index3.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { MapClass } from "./index2.js";
|
|
2
2
|
//#region src/physics.ts
|
|
3
3
|
var TILED_HITBOX_ID_PREFIX = "__tiled_collision__:";
|
|
4
|
+
var START_POSITION_NAME = "start";
|
|
4
5
|
function prepareTiledPhysicsData(mapData, map) {
|
|
5
6
|
if (!mapData?.parsedMap) return;
|
|
6
7
|
const tiledMap = new MapClass(mapData.parsedMap);
|
|
@@ -9,6 +10,7 @@ function prepareTiledPhysicsData(mapData, map) {
|
|
|
9
10
|
mapData.hitboxes = mergeTiledHitboxes(mapData.hitboxes, tiledHitboxes);
|
|
10
11
|
mapData.width = tiledMap.widthPx;
|
|
11
12
|
mapData.height = tiledMap.heightPx;
|
|
13
|
+
mapData.positions = mergeTiledPositions(mapData.positions, collectTiledPointPositions(mapData.parsedMap.objects));
|
|
12
14
|
}
|
|
13
15
|
function applyTiledPointEvents(mapData) {
|
|
14
16
|
const objects = mapData?.parsedMap?.objects;
|
|
@@ -16,8 +18,8 @@ function applyTiledPointEvents(mapData) {
|
|
|
16
18
|
for (const obj of objects) {
|
|
17
19
|
if (!obj?.point) continue;
|
|
18
20
|
mapData.events = mapData.events.map((eventEntry) => {
|
|
19
|
-
if (eventEntry?.
|
|
20
|
-
event: eventEntry,
|
|
21
|
+
if (obj.name && eventEntry?.x === void 0 && eventEntry?.y === void 0 && getEventName(eventEntry) === obj.name) return {
|
|
22
|
+
...eventEntry && typeof eventEntry === "object" && "event" in eventEntry ? eventEntry : { event: eventEntry },
|
|
21
23
|
x: obj.x,
|
|
22
24
|
y: obj.y
|
|
23
25
|
};
|
|
@@ -25,6 +27,42 @@ function applyTiledPointEvents(mapData) {
|
|
|
25
27
|
}).filter((eventEntry) => eventEntry !== null);
|
|
26
28
|
}
|
|
27
29
|
}
|
|
30
|
+
function collectTiledPointPositions(objects) {
|
|
31
|
+
if (!Array.isArray(objects)) return {};
|
|
32
|
+
const positions = {};
|
|
33
|
+
for (const obj of objects) {
|
|
34
|
+
if (!obj?.point || typeof obj.x !== "number" || typeof obj.y !== "number") continue;
|
|
35
|
+
if (typeof obj.name === "string" && obj.name.length > 0) positions[obj.name] = {
|
|
36
|
+
x: obj.x,
|
|
37
|
+
y: obj.y
|
|
38
|
+
};
|
|
39
|
+
if (!positions[START_POSITION_NAME] && (obj.class === START_POSITION_NAME || obj.type === START_POSITION_NAME)) positions[START_POSITION_NAME] = {
|
|
40
|
+
x: obj.x,
|
|
41
|
+
y: obj.y
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
return positions;
|
|
45
|
+
}
|
|
46
|
+
function mergeTiledPositions(existingPositions, tiledPositions) {
|
|
47
|
+
return {
|
|
48
|
+
...existingPositions && typeof existingPositions === "object" ? existingPositions : {},
|
|
49
|
+
...tiledPositions
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
function getEventName(eventEntry) {
|
|
53
|
+
const event = eventEntry?.event ?? eventEntry;
|
|
54
|
+
if (typeof event === "function") {
|
|
55
|
+
const staticEventName = event._name;
|
|
56
|
+
const prototypeEventName = event.prototype?._name;
|
|
57
|
+
const staticName = event.name;
|
|
58
|
+
const prototypeName = event.prototype?.name;
|
|
59
|
+
if (typeof prototypeEventName === "string") return prototypeEventName;
|
|
60
|
+
if (typeof staticEventName === "string") return staticEventName;
|
|
61
|
+
if (typeof prototypeName === "string") return prototypeName;
|
|
62
|
+
if (typeof staticName === "string") return staticName;
|
|
63
|
+
}
|
|
64
|
+
if (typeof event?.name === "string") return event.name;
|
|
65
|
+
}
|
|
28
66
|
function collectBlockedTileHitboxes(tiledMap) {
|
|
29
67
|
const hitboxes = [];
|
|
30
68
|
const mapWidth = tiledMap.width;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rpgjs/tiledmap",
|
|
3
|
-
"version": "5.0.0-beta.
|
|
3
|
+
"version": "5.0.0-beta.8",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"types": "dist/index.d.ts",
|
|
6
6
|
"exports": {
|
|
@@ -23,10 +23,10 @@
|
|
|
23
23
|
"description": "RPGJS is a framework for creating RPG/MMORPG games",
|
|
24
24
|
"peerDependencies": {
|
|
25
25
|
"@canvasengine/presets": "*",
|
|
26
|
-
"@rpgjs/client": "5.0.0-beta.
|
|
27
|
-
"@rpgjs/common": "5.0.0-beta.
|
|
28
|
-
"@rpgjs/server": "5.0.0-beta.
|
|
29
|
-
"@rpgjs/vite": "5.0.0-beta.
|
|
26
|
+
"@rpgjs/client": "5.0.0-beta.8",
|
|
27
|
+
"@rpgjs/common": "5.0.0-beta.8",
|
|
28
|
+
"@rpgjs/server": "5.0.0-beta.8",
|
|
29
|
+
"@rpgjs/vite": "5.0.0-beta.8",
|
|
30
30
|
"canvasengine": "*"
|
|
31
31
|
},
|
|
32
32
|
"publishConfig": {
|
package/src/physics.spec.ts
CHANGED
|
@@ -32,7 +32,7 @@ vi.mock("@canvasengine/tiled", () => {
|
|
|
32
32
|
return { MapClass };
|
|
33
33
|
});
|
|
34
34
|
|
|
35
|
-
import { prepareTiledPhysicsData } from "./physics";
|
|
35
|
+
import { applyTiledPointEvents, prepareTiledPhysicsData } from "./physics";
|
|
36
36
|
|
|
37
37
|
describe("prepareTiledPhysicsData", () => {
|
|
38
38
|
it("adds tiled collision hitboxes without duplicating them on repeated preparation", () => {
|
|
@@ -88,3 +88,158 @@ describe("prepareTiledPhysicsData", () => {
|
|
|
88
88
|
expect(mapData.hitboxes).toEqual([]);
|
|
89
89
|
});
|
|
90
90
|
});
|
|
91
|
+
|
|
92
|
+
describe("tiled point positions", () => {
|
|
93
|
+
it("extracts named point objects as map positions", () => {
|
|
94
|
+
const mapData = {
|
|
95
|
+
parsedMap: {
|
|
96
|
+
width: 1,
|
|
97
|
+
height: 1,
|
|
98
|
+
objects: [
|
|
99
|
+
{ point: true, name: "start", x: 10, y: 20 },
|
|
100
|
+
{ point: true, name: "entrance", x: 30, y: 40 },
|
|
101
|
+
],
|
|
102
|
+
},
|
|
103
|
+
};
|
|
104
|
+
|
|
105
|
+
prepareTiledPhysicsData(mapData, {});
|
|
106
|
+
|
|
107
|
+
expect(mapData.positions).toEqual({
|
|
108
|
+
start: { x: 10, y: 20 },
|
|
109
|
+
entrance: { x: 30, y: 40 },
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
it("uses class or type as a fallback for the special start position", () => {
|
|
114
|
+
const mapData = {
|
|
115
|
+
parsedMap: {
|
|
116
|
+
width: 1,
|
|
117
|
+
height: 1,
|
|
118
|
+
objects: [
|
|
119
|
+
{ point: true, class: "start", x: 10, y: 20 },
|
|
120
|
+
{ point: true, type: "start", x: 30, y: 40 },
|
|
121
|
+
],
|
|
122
|
+
},
|
|
123
|
+
};
|
|
124
|
+
|
|
125
|
+
prepareTiledPhysicsData(mapData, {});
|
|
126
|
+
|
|
127
|
+
expect(mapData.positions).toEqual({
|
|
128
|
+
start: { x: 10, y: 20 },
|
|
129
|
+
});
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
it("keeps explicitly named start before class or type fallback", () => {
|
|
133
|
+
const mapData = {
|
|
134
|
+
parsedMap: {
|
|
135
|
+
width: 1,
|
|
136
|
+
height: 1,
|
|
137
|
+
objects: [
|
|
138
|
+
{ point: true, name: "start", x: 10, y: 20 },
|
|
139
|
+
{ point: true, class: "start", x: 30, y: 40 },
|
|
140
|
+
],
|
|
141
|
+
},
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
prepareTiledPhysicsData(mapData, {});
|
|
145
|
+
|
|
146
|
+
expect(mapData.positions).toEqual({
|
|
147
|
+
start: { x: 10, y: 20 },
|
|
148
|
+
});
|
|
149
|
+
});
|
|
150
|
+
});
|
|
151
|
+
|
|
152
|
+
describe("applyTiledPointEvents", () => {
|
|
153
|
+
it("places direct object events by matching their name with a tiled point", () => {
|
|
154
|
+
const mapData = {
|
|
155
|
+
parsedMap: {
|
|
156
|
+
objects: [
|
|
157
|
+
{ point: true, name: "EV-1", x: 10, y: 20 },
|
|
158
|
+
],
|
|
159
|
+
},
|
|
160
|
+
events: [
|
|
161
|
+
{ name: "EV-1", onInit() {} },
|
|
162
|
+
],
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
applyTiledPointEvents(mapData);
|
|
166
|
+
|
|
167
|
+
expect(mapData.events).toEqual([
|
|
168
|
+
{
|
|
169
|
+
event: { name: "EV-1", onInit: expect.any(Function) },
|
|
170
|
+
x: 10,
|
|
171
|
+
y: 20,
|
|
172
|
+
},
|
|
173
|
+
]);
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it("places wrapped object events by matching the wrapped event name", () => {
|
|
177
|
+
const mapData = {
|
|
178
|
+
parsedMap: {
|
|
179
|
+
objects: [
|
|
180
|
+
{ point: true, name: "EV-1", x: 10, y: 20 },
|
|
181
|
+
],
|
|
182
|
+
},
|
|
183
|
+
events: [
|
|
184
|
+
{ id: "event-id", event: { name: "EV-1", onInit() {} } },
|
|
185
|
+
],
|
|
186
|
+
};
|
|
187
|
+
|
|
188
|
+
applyTiledPointEvents(mapData);
|
|
189
|
+
|
|
190
|
+
expect(mapData.events).toEqual([
|
|
191
|
+
{
|
|
192
|
+
id: "event-id",
|
|
193
|
+
event: { name: "EV-1", onInit: expect.any(Function) },
|
|
194
|
+
x: 10,
|
|
195
|
+
y: 20,
|
|
196
|
+
},
|
|
197
|
+
]);
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it("places class events decorated with EventData metadata", () => {
|
|
201
|
+
class NpcEvent {}
|
|
202
|
+
(NpcEvent as any)._name = "EV-1";
|
|
203
|
+
(NpcEvent as any).prototype._name = "EV-1";
|
|
204
|
+
|
|
205
|
+
const mapData = {
|
|
206
|
+
parsedMap: {
|
|
207
|
+
objects: [
|
|
208
|
+
{ point: true, name: "EV-1", x: 10, y: 20 },
|
|
209
|
+
],
|
|
210
|
+
},
|
|
211
|
+
events: [
|
|
212
|
+
{ event: NpcEvent },
|
|
213
|
+
],
|
|
214
|
+
};
|
|
215
|
+
|
|
216
|
+
applyTiledPointEvents(mapData);
|
|
217
|
+
|
|
218
|
+
expect(mapData.events).toEqual([
|
|
219
|
+
{
|
|
220
|
+
event: NpcEvent,
|
|
221
|
+
x: 10,
|
|
222
|
+
y: 20,
|
|
223
|
+
},
|
|
224
|
+
]);
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
it("does not override explicit event coordinates", () => {
|
|
228
|
+
const mapData = {
|
|
229
|
+
parsedMap: {
|
|
230
|
+
objects: [
|
|
231
|
+
{ point: true, name: "EV-1", x: 10, y: 20 },
|
|
232
|
+
],
|
|
233
|
+
},
|
|
234
|
+
events: [
|
|
235
|
+
{ x: 50, y: 60, event: { name: "EV-1" } },
|
|
236
|
+
],
|
|
237
|
+
};
|
|
238
|
+
|
|
239
|
+
applyTiledPointEvents(mapData);
|
|
240
|
+
|
|
241
|
+
expect(mapData.events).toEqual([
|
|
242
|
+
{ x: 50, y: 60, event: { name: "EV-1" } },
|
|
243
|
+
]);
|
|
244
|
+
});
|
|
245
|
+
});
|
package/src/physics.ts
CHANGED
|
@@ -13,6 +13,7 @@ type RectHitbox = {
|
|
|
13
13
|
};
|
|
14
14
|
|
|
15
15
|
const TILED_HITBOX_ID_PREFIX = "__tiled_collision__:";
|
|
16
|
+
const START_POSITION_NAME = "start";
|
|
16
17
|
|
|
17
18
|
export function prepareTiledPhysicsData(mapData: any, map: AnyMap): void {
|
|
18
19
|
if (!mapData?.parsedMap) {
|
|
@@ -26,6 +27,7 @@ export function prepareTiledPhysicsData(mapData: any, map: AnyMap): void {
|
|
|
26
27
|
mapData.hitboxes = mergeTiledHitboxes(mapData.hitboxes, tiledHitboxes);
|
|
27
28
|
mapData.width = tiledMap.widthPx;
|
|
28
29
|
mapData.height = tiledMap.heightPx;
|
|
30
|
+
mapData.positions = mergeTiledPositions(mapData.positions, collectTiledPointPositions(mapData.parsedMap.objects));
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
export function applyTiledPointEvents(mapData: any): void {
|
|
@@ -41,9 +43,15 @@ export function applyTiledPointEvents(mapData: any): void {
|
|
|
41
43
|
|
|
42
44
|
mapData.events = mapData.events
|
|
43
45
|
.map((eventEntry: any) => {
|
|
44
|
-
if (
|
|
46
|
+
if (
|
|
47
|
+
obj.name &&
|
|
48
|
+
eventEntry?.x === undefined &&
|
|
49
|
+
eventEntry?.y === undefined &&
|
|
50
|
+
getEventName(eventEntry) === obj.name
|
|
51
|
+
) {
|
|
52
|
+
const isWrappedEvent = eventEntry && typeof eventEntry === "object" && "event" in eventEntry;
|
|
45
53
|
return {
|
|
46
|
-
event: eventEntry,
|
|
54
|
+
...(isWrappedEvent ? eventEntry : { event: eventEntry }),
|
|
47
55
|
x: obj.x,
|
|
48
56
|
y: obj.y,
|
|
49
57
|
};
|
|
@@ -54,6 +62,69 @@ export function applyTiledPointEvents(mapData: any): void {
|
|
|
54
62
|
}
|
|
55
63
|
}
|
|
56
64
|
|
|
65
|
+
function collectTiledPointPositions(objects: any): Record<string, { x: number; y: number }> {
|
|
66
|
+
if (!Array.isArray(objects)) {
|
|
67
|
+
return {};
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
const positions: Record<string, { x: number; y: number }> = {};
|
|
71
|
+
|
|
72
|
+
for (const obj of objects) {
|
|
73
|
+
if (!obj?.point || typeof obj.x !== "number" || typeof obj.y !== "number") {
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
if (typeof obj.name === "string" && obj.name.length > 0) {
|
|
78
|
+
positions[obj.name] = { x: obj.x, y: obj.y };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
if (
|
|
82
|
+
!positions[START_POSITION_NAME] &&
|
|
83
|
+
(obj.class === START_POSITION_NAME || obj.type === START_POSITION_NAME)
|
|
84
|
+
) {
|
|
85
|
+
positions[START_POSITION_NAME] = { x: obj.x, y: obj.y };
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return positions;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function mergeTiledPositions(existingPositions: any, tiledPositions: Record<string, { x: number; y: number }>) {
|
|
93
|
+
return {
|
|
94
|
+
...(existingPositions && typeof existingPositions === "object" ? existingPositions : {}),
|
|
95
|
+
...tiledPositions,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function getEventName(eventEntry: any): string | undefined {
|
|
100
|
+
const event = eventEntry?.event ?? eventEntry;
|
|
101
|
+
|
|
102
|
+
if (typeof event === "function") {
|
|
103
|
+
const staticEventName = (event as any)._name;
|
|
104
|
+
const prototypeEventName = (event as any).prototype?._name;
|
|
105
|
+
const staticName = (event as any).name;
|
|
106
|
+
const prototypeName = (event as any).prototype?.name;
|
|
107
|
+
if (typeof prototypeEventName === "string") {
|
|
108
|
+
return prototypeEventName;
|
|
109
|
+
}
|
|
110
|
+
if (typeof staticEventName === "string") {
|
|
111
|
+
return staticEventName;
|
|
112
|
+
}
|
|
113
|
+
if (typeof prototypeName === "string") {
|
|
114
|
+
return prototypeName;
|
|
115
|
+
}
|
|
116
|
+
if (typeof staticName === "string") {
|
|
117
|
+
return staticName;
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
if (typeof event?.name === "string") {
|
|
122
|
+
return event.name;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return undefined;
|
|
126
|
+
}
|
|
127
|
+
|
|
57
128
|
function collectBlockedTileHitboxes(tiledMap: MapClass): RectHitbox[] {
|
|
58
129
|
const hitboxes: RectHitbox[] = [];
|
|
59
130
|
const mapWidth = tiledMap.width;
|