@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
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { MapClass } from '@canvasengine/tiled';
|
|
2
|
+
type AnyMap = {
|
|
3
|
+
tiled?: MapClass;
|
|
4
|
+
physic?: {
|
|
5
|
+
getEntityByUUID(id: string): any;
|
|
6
|
+
};
|
|
7
|
+
_blockedTiles?: Set<string>;
|
|
8
|
+
_tiledTileWidth?: number;
|
|
9
|
+
_tiledTileHeight?: number;
|
|
10
|
+
_tiledCollisionUnsubscribers?: Map<string, () => void>;
|
|
11
|
+
};
|
|
12
|
+
export declare function prepareTiledPhysicsData(mapData: any, map: AnyMap): void;
|
|
13
|
+
export declare function applyTiledPointEvents(mapData: any): void;
|
|
14
|
+
export declare function attachTiledCollisionToEntity(owner: any, map: AnyMap): void;
|
|
15
|
+
export declare function detachTiledCollisionFromEntity(owner: any, map: AnyMap): void;
|
|
16
|
+
export declare function resetTiledCollisionHandlers(map: AnyMap): void;
|
|
17
|
+
export {};
|
package/dist/server/index2.js
CHANGED
|
@@ -1,149 +1,28 @@
|
|
|
1
|
-
import { MapClass } from "./index3.js";
|
|
2
1
|
import { defineModule } from "@rpgjs/common";
|
|
2
|
+
import { resetTiledCollisionHandlers, detachTiledCollisionFromEntity, attachTiledCollisionToEntity, 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 sets up tile-based collision detection
|
|
9
|
-
* using the physics engine's tile grid system instead of individual hitboxes.
|
|
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. Stores blocked tiles in a Set for use with the physics engine tile grid
|
|
17
|
-
* 6. Configures tile dimensions for proper coordinate conversion
|
|
18
|
-
*
|
|
19
|
-
* The blocked tiles are used by the physics engine's `canEnterTile` hook
|
|
20
|
-
* to prevent entities from entering collision tiles, which is more efficient
|
|
21
|
-
* than creating individual hitboxes for each tile.
|
|
22
|
-
*
|
|
23
|
-
* @param mapData - Map data containing TMX information
|
|
24
|
-
* @param map - RpgMap instance to extend
|
|
25
|
-
* @returns The modified map instance with tiled property
|
|
26
|
-
*
|
|
27
|
-
* @example
|
|
28
|
-
* ```ts
|
|
29
|
-
* // Blocked tiles are stored as a Set with keys "x,y" (tile coordinates)
|
|
30
|
-
* // The physics engine will automatically check these tiles when entities
|
|
31
|
-
* // try to move, using the canEnterTile hook applied to all entities
|
|
32
|
-
* ```
|
|
33
|
-
*/
|
|
34
5
|
onBeforeUpdate(mapData, map) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
mapData.hitboxes = mapData.hitboxes || [];
|
|
38
|
-
mapData.width = tiledMap.widthPx;
|
|
39
|
-
mapData.height = tiledMap.heightPx;
|
|
40
|
-
const tileWidth = tiledMap.tilewidth;
|
|
41
|
-
const tileHeight = tiledMap.tileheight;
|
|
42
|
-
map._tiledTileWidth = tileWidth;
|
|
43
|
-
map._tiledTileHeight = tileHeight;
|
|
44
|
-
const blockedTiles = /* @__PURE__ */ new Set();
|
|
45
|
-
const mapWidth = tiledMap.width;
|
|
46
|
-
const mapHeight = tiledMap.height;
|
|
47
|
-
for (let y = 0; y < mapHeight; y++) {
|
|
48
|
-
for (let x = 0; x < mapWidth; x++) {
|
|
49
|
-
const pixelX = x * tileWidth;
|
|
50
|
-
const pixelY = y * tileHeight;
|
|
51
|
-
const tileInfo = tiledMap.getTileByPosition(pixelX, pixelY, [0, 0], {
|
|
52
|
-
populateTiles: true
|
|
53
|
-
});
|
|
54
|
-
if (tileInfo.hasCollision) {
|
|
55
|
-
blockedTiles.add(`${x},${y}`);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
map._blockedTiles = blockedTiles;
|
|
60
|
-
for (let obj of mapData.parsedMap.objects) {
|
|
61
|
-
if (obj.point) {
|
|
62
|
-
mapData.events = mapData.events.map((e) => {
|
|
63
|
-
if (e.name === obj.name) {
|
|
64
|
-
return {
|
|
65
|
-
event: e,
|
|
66
|
-
x: obj.x,
|
|
67
|
-
y: obj.y
|
|
68
|
-
};
|
|
69
|
-
}
|
|
70
|
-
return e;
|
|
71
|
-
}).filter((e) => e !== null);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
74
|
-
setTimeout(() => {
|
|
75
|
-
applyTileCollisionToEntities(map);
|
|
76
|
-
}, 0);
|
|
6
|
+
prepareTiledPhysicsData(mapData, map);
|
|
7
|
+
applyTiledPointEvents(mapData);
|
|
77
8
|
return map;
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
* Hook called when a player joins a map
|
|
83
|
-
*
|
|
84
|
-
* @description Applies tile-based collision detection to the player's physics entity
|
|
85
|
-
* using the blocked tiles stored on the map
|
|
86
|
-
*
|
|
87
|
-
* @param player - The player instance
|
|
88
|
-
* @param map - The map instance
|
|
89
|
-
*/
|
|
90
|
-
onJoinMap(player, map) {
|
|
91
|
-
setTimeout(() => {
|
|
92
|
-
applyTileCollisionToEntity(player, map);
|
|
93
|
-
}, 0);
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
});
|
|
97
|
-
function applyTileCollisionToEntity(owner, map) {
|
|
98
|
-
if (!owner?.id || !map?._blockedTiles) {
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
const entity = map.physic?.getEntityByUUID(owner.id);
|
|
102
|
-
if (!entity) {
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
const blockedTiles = map._blockedTiles;
|
|
106
|
-
const tiledTileWidth = map._tiledTileWidth ?? 32;
|
|
107
|
-
const tiledTileHeight = map._tiledTileHeight ?? 32;
|
|
108
|
-
const physicsTileWidth = 32;
|
|
109
|
-
const physicsTileHeight = 32;
|
|
110
|
-
entity.canEnterTile(({ x, y }) => {
|
|
111
|
-
const tiledX = Math.floor(x * physicsTileWidth / tiledTileWidth);
|
|
112
|
-
const tiledY = Math.floor(y * physicsTileHeight / tiledTileHeight);
|
|
113
|
-
const tileKey = `${tiledX},${tiledY}`;
|
|
114
|
-
if (blockedTiles.has(tileKey)) {
|
|
115
|
-
return false;
|
|
116
|
-
}
|
|
117
|
-
return true;
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
function applyTileCollisionToEntities(map) {
|
|
121
|
-
if (!map?._blockedTiles) {
|
|
122
|
-
return;
|
|
123
|
-
}
|
|
124
|
-
if (map.players && typeof map.players === "function") {
|
|
125
|
-
const players = map.players();
|
|
126
|
-
if (players && typeof players === "object") {
|
|
127
|
-
for (const playerId in players) {
|
|
128
|
-
const player = players[playerId];
|
|
129
|
-
if (player) {
|
|
130
|
-
applyTileCollisionToEntity(player, map);
|
|
131
|
-
}
|
|
9
|
+
},
|
|
10
|
+
onPhysicsInit(map, context) {
|
|
11
|
+
if (!map?._blockedTiles || !map?.tiled) {
|
|
12
|
+
prepareTiledPhysicsData(context?.mapData, map);
|
|
132
13
|
}
|
|
14
|
+
},
|
|
15
|
+
onPhysicsEntityAdd(map, context) {
|
|
16
|
+
attachTiledCollisionToEntity(context?.owner, map);
|
|
17
|
+
},
|
|
18
|
+
onPhysicsEntityRemove(map, context) {
|
|
19
|
+
detachTiledCollisionFromEntity(context?.owner, map);
|
|
20
|
+
},
|
|
21
|
+
onPhysicsReset(map) {
|
|
22
|
+
resetTiledCollisionHandlers(map);
|
|
133
23
|
}
|
|
134
24
|
}
|
|
135
|
-
|
|
136
|
-
const events = map.events();
|
|
137
|
-
if (events && typeof events === "object") {
|
|
138
|
-
for (const eventId in events) {
|
|
139
|
-
const event = events[eventId];
|
|
140
|
-
if (event) {
|
|
141
|
-
applyTileCollisionToEntity(event, map);
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
}
|
|
146
|
-
}
|
|
25
|
+
});
|
|
147
26
|
export {
|
|
148
27
|
server as default
|
|
149
28
|
};
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { MapClass } from "./index3.js";
|
|
2
|
+
function prepareTiledPhysicsData(mapData, map) {
|
|
3
|
+
if (!mapData?.parsedMap) {
|
|
4
|
+
return;
|
|
5
|
+
}
|
|
6
|
+
const tiledMap = new MapClass(mapData.parsedMap);
|
|
7
|
+
map.tiled = tiledMap;
|
|
8
|
+
mapData.hitboxes = mapData.hitboxes || [];
|
|
9
|
+
mapData.width = tiledMap.widthPx;
|
|
10
|
+
mapData.height = tiledMap.heightPx;
|
|
11
|
+
map._tiledTileWidth = tiledMap.tilewidth;
|
|
12
|
+
map._tiledTileHeight = tiledMap.tileheight;
|
|
13
|
+
map._blockedTiles = collectBlockedTiles(tiledMap);
|
|
14
|
+
}
|
|
15
|
+
function applyTiledPointEvents(mapData) {
|
|
16
|
+
const objects = mapData?.parsedMap?.objects;
|
|
17
|
+
if (!Array.isArray(objects) || !Array.isArray(mapData?.events)) {
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
for (const obj of objects) {
|
|
21
|
+
if (!obj?.point) {
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
mapData.events = mapData.events.map((eventEntry) => {
|
|
25
|
+
if (eventEntry?.name === obj.name) {
|
|
26
|
+
return {
|
|
27
|
+
event: eventEntry,
|
|
28
|
+
x: obj.x,
|
|
29
|
+
y: obj.y
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
return eventEntry;
|
|
33
|
+
}).filter((eventEntry) => eventEntry !== null);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
function attachTiledCollisionToEntity(owner, map) {
|
|
37
|
+
if (!owner?.id || !map?._blockedTiles) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
const entity = map.physic?.getEntityByUUID(owner.id);
|
|
41
|
+
if (!entity || typeof entity.canEnterTile !== "function") {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
const unsubscribers = ensureUnsubscribers(map);
|
|
45
|
+
const previousUnsubscribe = unsubscribers.get(owner.id);
|
|
46
|
+
if (previousUnsubscribe) {
|
|
47
|
+
previousUnsubscribe();
|
|
48
|
+
unsubscribers.delete(owner.id);
|
|
49
|
+
}
|
|
50
|
+
const blockedTiles = map._blockedTiles;
|
|
51
|
+
const tiledTileWidth = map._tiledTileWidth ?? 32;
|
|
52
|
+
const tiledTileHeight = map._tiledTileHeight ?? 32;
|
|
53
|
+
const physicsTileWidth = 32;
|
|
54
|
+
const physicsTileHeight = 32;
|
|
55
|
+
const unsubscribe = entity.canEnterTile(({ x, y }) => {
|
|
56
|
+
const tiledX = Math.floor(x * physicsTileWidth / tiledTileWidth);
|
|
57
|
+
const tiledY = Math.floor(y * physicsTileHeight / tiledTileHeight);
|
|
58
|
+
return !blockedTiles.has(`${tiledX},${tiledY}`);
|
|
59
|
+
});
|
|
60
|
+
unsubscribers.set(owner.id, unsubscribe);
|
|
61
|
+
}
|
|
62
|
+
function detachTiledCollisionFromEntity(owner, map) {
|
|
63
|
+
if (!owner?.id) {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
const unsubscribers = map._tiledCollisionUnsubscribers;
|
|
67
|
+
if (!unsubscribers) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
const unsubscribe = unsubscribers.get(owner.id);
|
|
71
|
+
if (!unsubscribe) {
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
unsubscribe();
|
|
75
|
+
unsubscribers.delete(owner.id);
|
|
76
|
+
}
|
|
77
|
+
function resetTiledCollisionHandlers(map) {
|
|
78
|
+
const unsubscribers = map._tiledCollisionUnsubscribers;
|
|
79
|
+
if (unsubscribers) {
|
|
80
|
+
for (const unsubscribe of unsubscribers.values()) {
|
|
81
|
+
unsubscribe();
|
|
82
|
+
}
|
|
83
|
+
unsubscribers.clear();
|
|
84
|
+
}
|
|
85
|
+
map._blockedTiles = void 0;
|
|
86
|
+
map._tiledTileWidth = void 0;
|
|
87
|
+
map._tiledTileHeight = void 0;
|
|
88
|
+
}
|
|
89
|
+
function collectBlockedTiles(tiledMap) {
|
|
90
|
+
const blockedTiles = /* @__PURE__ */ new Set();
|
|
91
|
+
const mapWidth = tiledMap.width;
|
|
92
|
+
const mapHeight = tiledMap.height;
|
|
93
|
+
const tileWidth = tiledMap.tilewidth;
|
|
94
|
+
const tileHeight = tiledMap.tileheight;
|
|
95
|
+
for (let y = 0; y < mapHeight; y++) {
|
|
96
|
+
for (let x = 0; x < mapWidth; x++) {
|
|
97
|
+
const tileInfo = tiledMap.getTileByPosition(x * tileWidth, y * tileHeight, [0, 0], {
|
|
98
|
+
populateTiles: true
|
|
99
|
+
});
|
|
100
|
+
if (tileInfo.hasCollision) {
|
|
101
|
+
blockedTiles.add(`${x},${y}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return blockedTiles;
|
|
106
|
+
}
|
|
107
|
+
function ensureUnsubscribers(map) {
|
|
108
|
+
map._tiledCollisionUnsubscribers = map._tiledCollisionUnsubscribers || /* @__PURE__ */ new Map();
|
|
109
|
+
return map._tiledCollisionUnsubscribers;
|
|
110
|
+
}
|
|
111
|
+
export {
|
|
112
|
+
applyTiledPointEvents,
|
|
113
|
+
attachTiledCollisionToEntity,
|
|
114
|
+
detachTiledCollisionFromEntity,
|
|
115
|
+
prepareTiledPhysicsData,
|
|
116
|
+
resetTiledCollisionHandlers
|
|
117
|
+
};
|
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 tile-based collision detection
|
|
22
|
-
* using the physics engine's tile grid system
|
|
23
|
-
*
|
|
24
|
-
* ## Features
|
|
25
|
-
*
|
|
26
|
-
* - **Automatic parsing**: Parses TMX files from Tiled Map Editor
|
|
27
|
-
* - **Collision detection**: Scans all tiles to detect collisions
|
|
28
|
-
* - **Tile grid system**: Uses physics engine tile grid to block movement on collision tiles
|
|
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;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rpgjs/tiledmap",
|
|
3
|
-
"version": "5.0.0-alpha.
|
|
3
|
+
"version": "5.0.0-alpha.42",
|
|
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-alpha.
|
|
27
|
-
"@rpgjs/common": "5.0.0-alpha.
|
|
28
|
-
"@rpgjs/server": "5.0.0-alpha.
|
|
29
|
-
"@rpgjs/vite": "5.0.0-alpha.
|
|
26
|
+
"@rpgjs/client": "5.0.0-alpha.42",
|
|
27
|
+
"@rpgjs/common": "5.0.0-alpha.42",
|
|
28
|
+
"@rpgjs/server": "5.0.0-alpha.42",
|
|
29
|
+
"@rpgjs/vite": "5.0.0-alpha.42",
|
|
30
30
|
"canvasengine": "*"
|
|
31
31
|
},
|
|
32
32
|
"publishConfig": {
|
package/src/client.ts
CHANGED
|
@@ -1,6 +1,26 @@
|
|
|
1
|
-
import { RpgClient
|
|
1
|
+
import { RpgClient } from "@rpgjs/client";
|
|
2
2
|
import { defineModule } from "@rpgjs/common";
|
|
3
|
+
import {
|
|
4
|
+
attachTiledCollisionToEntity,
|
|
5
|
+
detachTiledCollisionFromEntity,
|
|
6
|
+
prepareTiledPhysicsData,
|
|
7
|
+
resetTiledCollisionHandlers,
|
|
8
|
+
} from "./physics";
|
|
3
9
|
|
|
4
10
|
export default defineModule<RpgClient>({
|
|
5
|
-
|
|
6
|
-
|
|
11
|
+
componentAnimations: [],
|
|
12
|
+
sceneMap: {
|
|
13
|
+
onPhysicsInit(map: any, context: { mapData: any }) {
|
|
14
|
+
prepareTiledPhysicsData(context?.mapData, map);
|
|
15
|
+
},
|
|
16
|
+
onPhysicsEntityAdd(map: any, context: { owner: any }) {
|
|
17
|
+
attachTiledCollisionToEntity(context?.owner, map);
|
|
18
|
+
},
|
|
19
|
+
onPhysicsEntityRemove(map: any, context: { owner: any }) {
|
|
20
|
+
detachTiledCollisionFromEntity(context?.owner, map);
|
|
21
|
+
},
|
|
22
|
+
onPhysicsReset(map: any) {
|
|
23
|
+
resetTiledCollisionHandlers(map);
|
|
24
|
+
},
|
|
25
|
+
},
|
|
26
|
+
});
|
package/src/physics.ts
ADDED
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { MapClass } from "@canvasengine/tiled";
|
|
2
|
+
|
|
3
|
+
type AnyMap = {
|
|
4
|
+
tiled?: MapClass;
|
|
5
|
+
physic?: {
|
|
6
|
+
getEntityByUUID(id: string): any;
|
|
7
|
+
};
|
|
8
|
+
_blockedTiles?: Set<string>;
|
|
9
|
+
_tiledTileWidth?: number;
|
|
10
|
+
_tiledTileHeight?: number;
|
|
11
|
+
_tiledCollisionUnsubscribers?: Map<string, () => void>;
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export function prepareTiledPhysicsData(mapData: any, map: AnyMap): void {
|
|
15
|
+
if (!mapData?.parsedMap) {
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const tiledMap = new MapClass(mapData.parsedMap);
|
|
20
|
+
map.tiled = tiledMap;
|
|
21
|
+
|
|
22
|
+
mapData.hitboxes = mapData.hitboxes || [];
|
|
23
|
+
mapData.width = tiledMap.widthPx;
|
|
24
|
+
mapData.height = tiledMap.heightPx;
|
|
25
|
+
|
|
26
|
+
map._tiledTileWidth = tiledMap.tilewidth;
|
|
27
|
+
map._tiledTileHeight = tiledMap.tileheight;
|
|
28
|
+
map._blockedTiles = collectBlockedTiles(tiledMap);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export function applyTiledPointEvents(mapData: any): void {
|
|
32
|
+
const objects = mapData?.parsedMap?.objects;
|
|
33
|
+
if (!Array.isArray(objects) || !Array.isArray(mapData?.events)) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
for (const obj of objects) {
|
|
38
|
+
if (!obj?.point) {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
mapData.events = mapData.events
|
|
43
|
+
.map((eventEntry: any) => {
|
|
44
|
+
if (eventEntry?.name === obj.name) {
|
|
45
|
+
return {
|
|
46
|
+
event: eventEntry,
|
|
47
|
+
x: obj.x,
|
|
48
|
+
y: obj.y,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
return eventEntry;
|
|
52
|
+
})
|
|
53
|
+
.filter((eventEntry: any) => eventEntry !== null);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export function attachTiledCollisionToEntity(owner: any, map: AnyMap): void {
|
|
58
|
+
if (!owner?.id || !map?._blockedTiles) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const entity = map.physic?.getEntityByUUID(owner.id);
|
|
63
|
+
if (!entity || typeof entity.canEnterTile !== "function") {
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const unsubscribers = ensureUnsubscribers(map);
|
|
68
|
+
const previousUnsubscribe = unsubscribers.get(owner.id);
|
|
69
|
+
if (previousUnsubscribe) {
|
|
70
|
+
previousUnsubscribe();
|
|
71
|
+
unsubscribers.delete(owner.id);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const blockedTiles = map._blockedTiles;
|
|
75
|
+
const tiledTileWidth = map._tiledTileWidth ?? 32;
|
|
76
|
+
const tiledTileHeight = map._tiledTileHeight ?? 32;
|
|
77
|
+
const physicsTileWidth = 32;
|
|
78
|
+
const physicsTileHeight = 32;
|
|
79
|
+
|
|
80
|
+
const unsubscribe = entity.canEnterTile(({ x, y }) => {
|
|
81
|
+
const tiledX = Math.floor((x * physicsTileWidth) / tiledTileWidth);
|
|
82
|
+
const tiledY = Math.floor((y * physicsTileHeight) / tiledTileHeight);
|
|
83
|
+
return !blockedTiles.has(`${tiledX},${tiledY}`);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
unsubscribers.set(owner.id, unsubscribe);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
export function detachTiledCollisionFromEntity(owner: any, map: AnyMap): void {
|
|
90
|
+
if (!owner?.id) {
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
const unsubscribers = map._tiledCollisionUnsubscribers;
|
|
94
|
+
if (!unsubscribers) {
|
|
95
|
+
return;
|
|
96
|
+
}
|
|
97
|
+
const unsubscribe = unsubscribers.get(owner.id);
|
|
98
|
+
if (!unsubscribe) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
unsubscribe();
|
|
102
|
+
unsubscribers.delete(owner.id);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export function resetTiledCollisionHandlers(map: AnyMap): void {
|
|
106
|
+
const unsubscribers = map._tiledCollisionUnsubscribers;
|
|
107
|
+
if (unsubscribers) {
|
|
108
|
+
for (const unsubscribe of unsubscribers.values()) {
|
|
109
|
+
unsubscribe();
|
|
110
|
+
}
|
|
111
|
+
unsubscribers.clear();
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
map._blockedTiles = undefined;
|
|
115
|
+
map._tiledTileWidth = undefined;
|
|
116
|
+
map._tiledTileHeight = undefined;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
function collectBlockedTiles(tiledMap: MapClass): Set<string> {
|
|
120
|
+
const blockedTiles = new Set<string>();
|
|
121
|
+
const mapWidth = tiledMap.width;
|
|
122
|
+
const mapHeight = tiledMap.height;
|
|
123
|
+
const tileWidth = tiledMap.tilewidth;
|
|
124
|
+
const tileHeight = tiledMap.tileheight;
|
|
125
|
+
|
|
126
|
+
for (let y = 0; y < mapHeight; y++) {
|
|
127
|
+
for (let x = 0; x < mapWidth; x++) {
|
|
128
|
+
const tileInfo = tiledMap.getTileByPosition(x * tileWidth, y * tileHeight, [0, 0], {
|
|
129
|
+
populateTiles: true,
|
|
130
|
+
});
|
|
131
|
+
if (tileInfo.hasCollision) {
|
|
132
|
+
blockedTiles.add(`${x},${y}`);
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return blockedTiles;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
function ensureUnsubscribers(map: AnyMap): Map<string, () => void> {
|
|
141
|
+
map._tiledCollisionUnsubscribers = map._tiledCollisionUnsubscribers || new Map();
|
|
142
|
+
return map._tiledCollisionUnsubscribers;
|
|
143
|
+
}
|