@rpgjs/tiledmap 5.0.0-alpha.40 → 5.0.0-alpha.42
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/dist/client/index2.js +16 -1
- package/dist/client/index3.js +581 -1
- package/dist/client/index5.js +95 -0
- package/dist/physics.d.ts +17 -0
- package/dist/server/index2.js +17 -138
- package/dist/server/index4.js +117 -0
- package/dist/server.d.ts +0 -53
- package/package.json +5 -5
- package/src/client.ts +23 -3
- package/src/physics.ts +143 -0
- package/src/server.ts +22 -266
package/src/server.ts
CHANGED
|
@@ -1,288 +1,44 @@
|
|
|
1
1
|
import { RpgMap, RpgServer } from "@rpgjs/server";
|
|
2
2
|
import { MapClass } from "@canvasengine/tiled";
|
|
3
3
|
import { defineModule } from "@rpgjs/common";
|
|
4
|
+
import {
|
|
5
|
+
applyTiledPointEvents,
|
|
6
|
+
attachTiledCollisionToEntity,
|
|
7
|
+
detachTiledCollisionFromEntity,
|
|
8
|
+
prepareTiledPhysicsData,
|
|
9
|
+
resetTiledCollisionHandlers,
|
|
10
|
+
} from "./physics";
|
|
4
11
|
|
|
5
|
-
// Extend RpgMap interface to include tiled property
|
|
6
12
|
declare module "@rpgjs/server" {
|
|
7
13
|
interface RpgMap {
|
|
8
14
|
tiled?: MapClass;
|
|
9
15
|
}
|
|
10
16
|
}
|
|
11
17
|
|
|
12
|
-
/**
|
|
13
|
-
* Interface for an RpgMap extended with Tiled functionality
|
|
14
|
-
*
|
|
15
|
-
* @description This interface combines RpgMap with MapClass to enable
|
|
16
|
-
* the use of Tiled methods on RPG maps
|
|
17
|
-
*/
|
|
18
18
|
export interface RpgTiledMap extends RpgMap {
|
|
19
19
|
tiled: MapClass;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
-
/**
|
|
23
|
-
* Tiled Module for RPGJS
|
|
24
|
-
*
|
|
25
|
-
* @description This module extends RPGJS maps with Tiled functionality,
|
|
26
|
-
* allowing TMX map parsing and automatic tile-based collision detection
|
|
27
|
-
* using the physics engine's tile grid system
|
|
28
|
-
*
|
|
29
|
-
* ## Features
|
|
30
|
-
*
|
|
31
|
-
* - **Automatic parsing**: Parses TMX files from Tiled Map Editor
|
|
32
|
-
* - **Collision detection**: Scans all tiles to detect collisions
|
|
33
|
-
* - **Tile grid system**: Uses physics engine tile grid to block movement on collision tiles
|
|
34
|
-
* - **RpgMap extension**: Adds the `tiled` property to all RpgMap instances
|
|
35
|
-
*
|
|
36
|
-
* ## Usage
|
|
37
|
-
*
|
|
38
|
-
* Once this module is activated, you can use Tiled methods on your maps:
|
|
39
|
-
*
|
|
40
|
-
* @example
|
|
41
|
-
* ```ts
|
|
42
|
-
* // In a map class
|
|
43
|
-
* class MyMap extends RpgMap {
|
|
44
|
-
* onLoad() {
|
|
45
|
-
* // Access Tiled functionality
|
|
46
|
-
* const tiles = this.tiled.getTileByPosition(100, 100);
|
|
47
|
-
*
|
|
48
|
-
* if (tiles.hasCollision) {
|
|
49
|
-
* console.log('This position has a collision');
|
|
50
|
-
* }
|
|
51
|
-
*
|
|
52
|
-
* // Iterate through all tiles by index
|
|
53
|
-
* for (let i = 0; i < this.tiled.width * this.tiled.height; i++) {
|
|
54
|
-
* const tileInfo = this.tiled.getTileByIndex(i);
|
|
55
|
-
* if (tileInfo.hasCollision) {
|
|
56
|
-
* console.log(`Tile ${i} has collision`);
|
|
57
|
-
* }
|
|
58
|
-
* }
|
|
59
|
-
*
|
|
60
|
-
* // Get information about a specific layer
|
|
61
|
-
* const layer = this.tiled.getLayerByName('Collision');
|
|
62
|
-
* if (layer) {
|
|
63
|
-
* console.log('Collision layer found:', layer);
|
|
64
|
-
* }
|
|
65
|
-
* }
|
|
66
|
-
* }
|
|
67
|
-
* ```
|
|
68
|
-
*/
|
|
69
22
|
export default defineModule<RpgServer>({
|
|
70
23
|
map: {
|
|
71
|
-
/**
|
|
72
|
-
* Hook called before map update
|
|
73
|
-
*
|
|
74
|
-
* @description Parses Tiled data and sets up tile-based collision detection
|
|
75
|
-
* using the physics engine's tile grid system instead of individual hitboxes.
|
|
76
|
-
*
|
|
77
|
-
* This method:
|
|
78
|
-
* 1. Parses TMX data with TiledParser
|
|
79
|
-
* 2. Creates a MapClass instance with parsed data
|
|
80
|
-
* 3. Attaches the Tiled instance to the RpgMap
|
|
81
|
-
* 4. Scans all tiles to detect collisions
|
|
82
|
-
* 5. Stores blocked tiles in a Set for use with the physics engine tile grid
|
|
83
|
-
* 6. Configures tile dimensions for proper coordinate conversion
|
|
84
|
-
*
|
|
85
|
-
* The blocked tiles are used by the physics engine's `canEnterTile` hook
|
|
86
|
-
* to prevent entities from entering collision tiles, which is more efficient
|
|
87
|
-
* than creating individual hitboxes for each tile.
|
|
88
|
-
*
|
|
89
|
-
* @param mapData - Map data containing TMX information
|
|
90
|
-
* @param map - RpgMap instance to extend
|
|
91
|
-
* @returns The modified map instance with tiled property
|
|
92
|
-
*
|
|
93
|
-
* @example
|
|
94
|
-
* ```ts
|
|
95
|
-
* // Blocked tiles are stored as a Set with keys "x,y" (tile coordinates)
|
|
96
|
-
* // The physics engine will automatically check these tiles when entities
|
|
97
|
-
* // try to move, using the canEnterTile hook applied to all entities
|
|
98
|
-
* ```
|
|
99
|
-
*/
|
|
100
24
|
onBeforeUpdate<T = RpgMap>(mapData: any, map: T): T {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
// Attach Tiled instance to the map
|
|
104
|
-
(map as any).tiled = tiledMap;
|
|
105
|
-
|
|
106
|
-
// Initialize hitboxes array (for backward compatibility, but we won't populate it)
|
|
107
|
-
mapData.hitboxes = mapData.hitboxes || [];
|
|
108
|
-
mapData.width = tiledMap.widthPx;
|
|
109
|
-
mapData.height = tiledMap.heightPx;
|
|
110
|
-
|
|
111
|
-
// Store tile dimensions for coordinate conversion
|
|
112
|
-
const tileWidth = tiledMap.tilewidth;
|
|
113
|
-
const tileHeight = tiledMap.tileheight;
|
|
114
|
-
(map as any)._tiledTileWidth = tileWidth;
|
|
115
|
-
(map as any)._tiledTileHeight = tileHeight;
|
|
116
|
-
|
|
117
|
-
// Store blocked tiles in a Set for efficient lookup
|
|
118
|
-
// Key format: "x,y" where x and y are tile coordinates in Tiled's coordinate system
|
|
119
|
-
const blockedTiles = new Set<string>();
|
|
120
|
-
|
|
121
|
-
// Iterate through all map tiles to detect collisions
|
|
122
|
-
const mapWidth = tiledMap.width;
|
|
123
|
-
const mapHeight = tiledMap.height;
|
|
124
|
-
|
|
125
|
-
// Iterate through each tile on the map
|
|
126
|
-
for (let y = 0; y < mapHeight; y++) {
|
|
127
|
-
for (let x = 0; x < mapWidth; x++) {
|
|
128
|
-
// Use getTileByPosition which is simpler and handles pixel coordinates directly
|
|
129
|
-
const pixelX = x * tileWidth;
|
|
130
|
-
const pixelY = y * tileHeight;
|
|
131
|
-
const tileInfo = tiledMap.getTileByPosition(pixelX, pixelY, [0, 0], {
|
|
132
|
-
populateTiles: true,
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
// If tile has collision, add it to the blocked tiles set
|
|
136
|
-
if (tileInfo.hasCollision) {
|
|
137
|
-
blockedTiles.add(`${x},${y}`);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// Store blocked tiles on the map instance
|
|
143
|
-
(map as any)._blockedTiles = blockedTiles;
|
|
144
|
-
|
|
145
|
-
for (let obj of mapData.parsedMap.objects) {
|
|
146
|
-
if (obj.point) {
|
|
147
|
-
mapData.events = mapData.events
|
|
148
|
-
.map((e) => {
|
|
149
|
-
if (e.name === obj.name) {
|
|
150
|
-
return {
|
|
151
|
-
event: e,
|
|
152
|
-
x: obj.x,
|
|
153
|
-
y: obj.y,
|
|
154
|
-
};
|
|
155
|
-
}
|
|
156
|
-
return e;
|
|
157
|
-
})
|
|
158
|
-
.filter((e) => e !== null);
|
|
159
|
-
}
|
|
160
|
-
}
|
|
161
|
-
|
|
162
|
-
// Apply tile collision to all existing entities after a short delay
|
|
163
|
-
// to ensure physics entities are created
|
|
164
|
-
setTimeout(() => {
|
|
165
|
-
applyTileCollisionToEntities(map as any);
|
|
166
|
-
}, 0);
|
|
167
|
-
|
|
25
|
+
prepareTiledPhysicsData(mapData, map as any);
|
|
26
|
+
applyTiledPointEvents(mapData);
|
|
168
27
|
return map;
|
|
169
28
|
},
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
setTimeout(() => {
|
|
184
|
-
applyTileCollisionToEntity(player, map);
|
|
185
|
-
}, 0);
|
|
29
|
+
onPhysicsInit(map: any, context: { mapData: any }) {
|
|
30
|
+
if (!map?._blockedTiles || !map?.tiled) {
|
|
31
|
+
prepareTiledPhysicsData(context?.mapData, map);
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
onPhysicsEntityAdd(map: any, context: { owner: any }) {
|
|
35
|
+
attachTiledCollisionToEntity(context?.owner, map);
|
|
36
|
+
},
|
|
37
|
+
onPhysicsEntityRemove(map: any, context: { owner: any }) {
|
|
38
|
+
detachTiledCollisionFromEntity(context?.owner, map);
|
|
39
|
+
},
|
|
40
|
+
onPhysicsReset(map: any) {
|
|
41
|
+
resetTiledCollisionHandlers(map);
|
|
186
42
|
},
|
|
187
43
|
},
|
|
188
44
|
});
|
|
189
|
-
|
|
190
|
-
/**
|
|
191
|
-
* Applies tile-based collision detection to a single entity
|
|
192
|
-
*
|
|
193
|
-
* @description This function sets up the `canEnterTile` hook on an entity's physics body
|
|
194
|
-
* to prevent movement into blocked tiles. It converts tile coordinates from the physics
|
|
195
|
-
* engine's coordinate system (based on default 32x32 tiles) to Tiled's coordinate system.
|
|
196
|
-
*
|
|
197
|
-
* @param owner - The owner object (player or event) that has a physics entity
|
|
198
|
-
* @param map - The map instance containing blocked tiles
|
|
199
|
-
*
|
|
200
|
-
* @example
|
|
201
|
-
* ```ts
|
|
202
|
-
* // This is called automatically when a player joins a map or an event is created
|
|
203
|
-
* // The function checks if the tile the entity is trying to enter is in the
|
|
204
|
-
* // blocked tiles set, converting coordinates as needed
|
|
205
|
-
* ```
|
|
206
|
-
*/
|
|
207
|
-
function applyTileCollisionToEntity(owner: any, map: any) {
|
|
208
|
-
if (!owner?.id || !map?._blockedTiles) {
|
|
209
|
-
return;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
const entity = map.physic?.getEntityByUUID(owner.id);
|
|
213
|
-
if (!entity) {
|
|
214
|
-
return;
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
const blockedTiles = map._blockedTiles as Set<string>;
|
|
218
|
-
const tiledTileWidth = map._tiledTileWidth ?? 32;
|
|
219
|
-
const tiledTileHeight = map._tiledTileHeight ?? 32;
|
|
220
|
-
|
|
221
|
-
// Physics engine uses default 32x32 tiles, but Tiled may have different dimensions
|
|
222
|
-
// We need to convert physics engine tile coordinates to Tiled tile coordinates
|
|
223
|
-
const physicsTileWidth = 32; // Default physics engine tile width
|
|
224
|
-
const physicsTileHeight = 32; // Default physics engine tile height
|
|
225
|
-
|
|
226
|
-
// Apply canEnterTile hook to the entity
|
|
227
|
-
entity.canEnterTile(({ x, y }) => {
|
|
228
|
-
// x, y are tile coordinates from the physics engine (based on 32x32 tiles)
|
|
229
|
-
// Convert to Tiled tile coordinates
|
|
230
|
-
const tiledX = Math.floor((x * physicsTileWidth) / tiledTileWidth);
|
|
231
|
-
const tiledY = Math.floor((y * physicsTileHeight) / tiledTileHeight);
|
|
232
|
-
|
|
233
|
-
// Check if this tile is blocked
|
|
234
|
-
const tileKey = `${tiledX},${tiledY}`;
|
|
235
|
-
if (blockedTiles.has(tileKey)) {
|
|
236
|
-
return false; // Block movement into this tile
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
return true; // Allow movement
|
|
240
|
-
});
|
|
241
|
-
}
|
|
242
|
-
|
|
243
|
-
/**
|
|
244
|
-
* Applies tile-based collision detection to all existing entities on a map
|
|
245
|
-
*
|
|
246
|
-
* @description This function iterates through all players and events on the map
|
|
247
|
-
* and applies the tile collision hook to each one's physics entity. This is useful
|
|
248
|
-
* when setting up the map for the first time or when entities already exist before
|
|
249
|
-
* the map is loaded.
|
|
250
|
-
*
|
|
251
|
-
* @param map - The map instance containing blocked tiles
|
|
252
|
-
*
|
|
253
|
-
* @example
|
|
254
|
-
* ```ts
|
|
255
|
-
* // Called automatically in onBeforeUpdate to apply collision to existing entities
|
|
256
|
-
* ```
|
|
257
|
-
*/
|
|
258
|
-
function applyTileCollisionToEntities(map: any) {
|
|
259
|
-
if (!map?._blockedTiles) {
|
|
260
|
-
return;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
// Apply to all players
|
|
264
|
-
if (map.players && typeof map.players === 'function') {
|
|
265
|
-
const players = map.players();
|
|
266
|
-
if (players && typeof players === 'object') {
|
|
267
|
-
for (const playerId in players) {
|
|
268
|
-
const player = players[playerId];
|
|
269
|
-
if (player) {
|
|
270
|
-
applyTileCollisionToEntity(player, map);
|
|
271
|
-
}
|
|
272
|
-
}
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
// Apply to all events
|
|
277
|
-
if (map.events && typeof map.events === 'function') {
|
|
278
|
-
const events = map.events();
|
|
279
|
-
if (events && typeof events === 'object') {
|
|
280
|
-
for (const eventId in events) {
|
|
281
|
-
const event = events[eventId];
|
|
282
|
-
if (event) {
|
|
283
|
-
applyTileCollisionToEntity(event, map);
|
|
284
|
-
}
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
}
|