@rpgjs/common 4.2.1 → 5.0.0-alpha.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/dist/Physic.d.ts +619 -0
- package/dist/Player.d.ts +198 -0
- package/{lib → dist}/Utils.d.ts +19 -2
- package/dist/database/Item.d.ts +10 -0
- package/dist/database/index.d.ts +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.js +16741 -0
- package/dist/index.js.map +1 -0
- package/dist/modules.d.ts +92 -0
- package/dist/movement/MovementManager.d.ts +84 -0
- package/dist/movement/MovementStrategy.d.ts +39 -0
- package/dist/movement/index.d.ts +12 -0
- package/dist/movement/strategies/CompositeMovement.d.ts +76 -0
- package/dist/movement/strategies/Dash.d.ts +52 -0
- package/dist/movement/strategies/IceMovement.d.ts +87 -0
- package/dist/movement/strategies/Knockback.d.ts +50 -0
- package/dist/movement/strategies/LinearMove.d.ts +43 -0
- package/dist/movement/strategies/LinearRepulsion.d.ts +55 -0
- package/dist/movement/strategies/Oscillate.d.ts +60 -0
- package/dist/movement/strategies/PathFollow.d.ts +78 -0
- package/dist/movement/strategies/ProjectileMovement.d.ts +138 -0
- package/dist/movement/strategies/SeekAvoid.d.ts +27 -0
- package/dist/rooms/Map.d.ts +109 -0
- package/dist/services/updateMap.d.ts +7 -0
- package/package.json +17 -17
- package/src/Physic.ts +1644 -0
- package/src/Player.ts +262 -26
- package/src/{gui/PrebuiltGui.ts → PrebuiltGui.ts} +1 -1
- package/src/Utils.ts +184 -123
- package/src/database/Item.ts +19 -0
- package/src/database/index.ts +1 -0
- package/src/index.ts +9 -25
- package/src/modules.ts +230 -0
- package/src/movement/MovementManager.ts +142 -0
- package/src/movement/MovementStrategy.ts +42 -0
- package/src/movement/index.ts +15 -0
- package/src/movement/strategies/CompositeMovement.ts +173 -0
- package/src/movement/strategies/Dash.ts +82 -0
- package/src/movement/strategies/IceMovement.ts +158 -0
- package/src/movement/strategies/Knockback.ts +81 -0
- package/src/movement/strategies/LinearMove.ts +58 -0
- package/src/movement/strategies/LinearRepulsion.ts +128 -0
- package/src/movement/strategies/Oscillate.ts +144 -0
- package/src/movement/strategies/PathFollow.ts +156 -0
- package/src/movement/strategies/ProjectileMovement.ts +322 -0
- package/src/movement/strategies/SeekAvoid.ts +123 -0
- package/src/rooms/Map.ts +272 -0
- package/src/services/updateMap.ts +9 -0
- package/tests/physic.spec.ts +454 -0
- package/tsconfig.json +8 -3
- package/vite.config.ts +21 -0
- package/CHANGELOG.md +0 -152
- package/LICENSE +0 -19
- package/browser/manifest.json +0 -7
- package/browser/rpg.common.js +0 -11357
- package/browser/rpg.common.umd.cjs +0 -11358
- package/lib/AbstractObject.d.ts +0 -322
- package/lib/AbstractObject.js +0 -872
- package/lib/AbstractObject.js.map +0 -1
- package/lib/Color.d.ts +0 -1
- package/lib/Color.js +0 -25
- package/lib/Color.js.map +0 -1
- package/lib/DefaultInput.d.ts +0 -2
- package/lib/DefaultInput.js +0 -26
- package/lib/DefaultInput.js.map +0 -1
- package/lib/Event.d.ts +0 -3
- package/lib/Event.js +0 -4
- package/lib/Event.js.map +0 -1
- package/lib/EventEmitter.d.ts +0 -10
- package/lib/EventEmitter.js +0 -61
- package/lib/EventEmitter.js.map +0 -1
- package/lib/Game.d.ts +0 -28
- package/lib/Game.js +0 -127
- package/lib/Game.js.map +0 -1
- package/lib/Hit.d.ts +0 -16
- package/lib/Hit.js +0 -65
- package/lib/Hit.js.map +0 -1
- package/lib/Inject.d.ts +0 -9
- package/lib/Inject.js +0 -17
- package/lib/Inject.js.map +0 -1
- package/lib/Logger.d.ts +0 -2
- package/lib/Logger.js +0 -7
- package/lib/Logger.js.map +0 -1
- package/lib/Map.d.ts +0 -174
- package/lib/Map.js +0 -263
- package/lib/Map.js.map +0 -1
- package/lib/Module.d.ts +0 -16
- package/lib/Module.js +0 -139
- package/lib/Module.js.map +0 -1
- package/lib/Player.d.ts +0 -26
- package/lib/Player.js +0 -19
- package/lib/Player.js.map +0 -1
- package/lib/Plugin.d.ts +0 -67
- package/lib/Plugin.js +0 -92
- package/lib/Plugin.js.map +0 -1
- package/lib/Scheduler.d.ts +0 -26
- package/lib/Scheduler.js +0 -90
- package/lib/Scheduler.js.map +0 -1
- package/lib/Shape.d.ts +0 -127
- package/lib/Shape.js +0 -261
- package/lib/Shape.js.map +0 -1
- package/lib/Utils.js +0 -181
- package/lib/Utils.js.map +0 -1
- package/lib/Vector2d.d.ts +0 -20
- package/lib/Vector2d.js +0 -63
- package/lib/Vector2d.js.map +0 -1
- package/lib/VirtualGrid.d.ts +0 -26
- package/lib/VirtualGrid.js +0 -68
- package/lib/VirtualGrid.js.map +0 -1
- package/lib/Worker.d.ts +0 -7
- package/lib/Worker.js +0 -13
- package/lib/Worker.js.map +0 -1
- package/lib/WorldMaps.d.ts +0 -105
- package/lib/WorldMaps.js +0 -184
- package/lib/WorldMaps.js.map +0 -1
- package/lib/gui/PrebuiltGui.js +0 -29
- package/lib/gui/PrebuiltGui.js.map +0 -1
- package/lib/index.d.ts +0 -25
- package/lib/index.js +0 -26
- package/lib/index.js.map +0 -1
- package/lib/transports/io.d.ts +0 -22
- package/lib/transports/io.js +0 -82
- package/lib/transports/io.js.map +0 -1
- package/lib/workers/move.d.ts +0 -1
- package/lib/workers/move.js +0 -57
- package/lib/workers/move.js.map +0 -1
- package/rpg.toml +0 -11
- package/src/AbstractObject.ts +0 -973
- package/src/Color.ts +0 -29
- package/src/DefaultInput.ts +0 -26
- package/src/Event.ts +0 -3
- package/src/EventEmitter.ts +0 -65
- package/src/Game.ts +0 -159
- package/src/Hit.ts +0 -70
- package/src/Inject.ts +0 -22
- package/src/Logger.ts +0 -7
- package/src/Map.ts +0 -335
- package/src/Module.ts +0 -144
- package/src/Plugin.ts +0 -100
- package/src/Scheduler.ts +0 -95
- package/src/Shape.ts +0 -302
- package/src/Vector2d.ts +0 -70
- package/src/VirtualGrid.ts +0 -78
- package/src/Worker.ts +0 -17
- package/src/WorldMaps.ts +0 -204
- package/src/transports/io.ts +0 -91
- package/src/workers/move.ts +0 -61
- /package/{lib/gui → dist}/PrebuiltGui.d.ts +0 -0
|
@@ -0,0 +1,454 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
2
|
+
import { RpgCommonPhysic } from '../src/Physic';
|
|
3
|
+
import { Direction } from '../src/Player';
|
|
4
|
+
import { signal } from '@signe/reactive';
|
|
5
|
+
import * as Matter from 'matter-js';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Helper to build a mock RpgCommonPlayer compliant with the Physic class
|
|
9
|
+
*/
|
|
10
|
+
const createMockPlayer = (id: string, x = 100, y = 100) => {
|
|
11
|
+
const sigX = signal(x);
|
|
12
|
+
const sigY = signal(y);
|
|
13
|
+
const sigSpeed = signal(2);
|
|
14
|
+
const sigDirection = signal(Direction.Down);
|
|
15
|
+
return {
|
|
16
|
+
id,
|
|
17
|
+
x: sigX,
|
|
18
|
+
y: sigY,
|
|
19
|
+
speed: sigSpeed,
|
|
20
|
+
direction: sigDirection,
|
|
21
|
+
applyPhysic: vi.fn((body: Matter.Body) => {
|
|
22
|
+
sigX.set(body.position.x);
|
|
23
|
+
sigY.set(body.position.y);
|
|
24
|
+
}),
|
|
25
|
+
} as any;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Centralised helpers to ease repetitive tasks in tests
|
|
30
|
+
*/
|
|
31
|
+
const tick = (physic: RpgCommonPhysic, steps = 1, delta = 16) => {
|
|
32
|
+
for (let i = 0; i < steps; i++) physic.update(delta);
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
describe('Physic', () => {
|
|
36
|
+
let physic: RpgCommonPhysic;
|
|
37
|
+
|
|
38
|
+
beforeEach(() => {
|
|
39
|
+
physic = new RpgCommonPhysic();
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
describe('Hitboxes', () => {
|
|
43
|
+
it('should add static hitbox and return its id', () => {
|
|
44
|
+
const id = physic.addStaticHitbox('wall1', 50, 50, 32, 32);
|
|
45
|
+
expect(id).toBe('wall1');
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should add movable hitbox and return its id', () => {
|
|
49
|
+
const mockPlayer = createMockPlayer('player1');
|
|
50
|
+
const id = physic.addMovableHitbox(mockPlayer, 100, 100, 24, 32);
|
|
51
|
+
expect(id).toBe('player1');
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should update hitbox position', () => {
|
|
55
|
+
const mockPlayer = createMockPlayer('player1');
|
|
56
|
+
physic.addMovableHitbox(mockPlayer, 100, 100, 24, 32);
|
|
57
|
+
const updated = physic.updateHitbox('player1', 150, 150);
|
|
58
|
+
expect(updated).toBe(true);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
it('should update hitbox position and size', () => {
|
|
62
|
+
const mockPlayer = createMockPlayer('player1');
|
|
63
|
+
physic.addMovableHitbox(mockPlayer, 100, 100, 24, 32);
|
|
64
|
+
const updated = physic.updateHitbox('player1', 150, 150, 32, 40);
|
|
65
|
+
expect(updated).toBe(true);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('should return false when updating non-existent hitbox', () => {
|
|
69
|
+
const updated = physic.updateHitbox('nonexistent', 150, 150);
|
|
70
|
+
expect(updated).toBe(false);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('should remove hitbox successfully', () => {
|
|
74
|
+
physic.addStaticHitbox('wall1', 50, 50, 32, 32);
|
|
75
|
+
const removed = physic.removeHitbox('wall1');
|
|
76
|
+
expect(removed).toBe(true);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('should return false when removing non-existent hitbox', () => {
|
|
80
|
+
const removed = physic.removeHitbox('nonexistent');
|
|
81
|
+
expect(removed).toBe(false);
|
|
82
|
+
});
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
describe('Movement', () => {
|
|
86
|
+
it('should move a body according to direction', () => {
|
|
87
|
+
const mockPlayer = createMockPlayer('player1');
|
|
88
|
+
physic.addMovableHitbox(mockPlayer, 100, 100, 24, 32);
|
|
89
|
+
|
|
90
|
+
const moved = physic.moveBody(mockPlayer, Direction.Right);
|
|
91
|
+
expect(moved).toBe(true);
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
it('should synchronize player to body', () => {
|
|
95
|
+
const mockPlayer = createMockPlayer('player1');
|
|
96
|
+
physic.addMovableHitbox(mockPlayer, 100, 100, 24, 32);
|
|
97
|
+
|
|
98
|
+
const synced = physic.syncPlayerToBody('player1');
|
|
99
|
+
expect(synced).toBe(true);
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
it('should apply translation to a body', () => {
|
|
103
|
+
const mockPlayer = createMockPlayer('player1');
|
|
104
|
+
physic.addMovableHitbox(mockPlayer, 100, 100, 24, 32);
|
|
105
|
+
|
|
106
|
+
const applied = physic.applyTranslation('player1', 5, 10);
|
|
107
|
+
expect(applied).toBe(true);
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('should set velocity to a body', () => {
|
|
111
|
+
const mockPlayer = createMockPlayer('player1');
|
|
112
|
+
physic.addMovableHitbox(mockPlayer, 100, 100, 24, 32);
|
|
113
|
+
|
|
114
|
+
const applied = physic.setVelocity('player1', 5, 0);
|
|
115
|
+
expect(applied).toBe(true);
|
|
116
|
+
});
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
describe('Collision', () => {
|
|
120
|
+
it('should register collision event callbacks', () => {
|
|
121
|
+
const mockPlayer = createMockPlayer('player1');
|
|
122
|
+
physic.addMovableHitbox(mockPlayer, 100, 100, 24, 32);
|
|
123
|
+
|
|
124
|
+
const onEnter = vi.fn();
|
|
125
|
+
const onExit = vi.fn();
|
|
126
|
+
|
|
127
|
+
physic.registerCollisionEvents('player1', onEnter, onExit);
|
|
128
|
+
|
|
129
|
+
// Can't easily test callbacks directly, but we can ensure no errors
|
|
130
|
+
expect(() => {
|
|
131
|
+
physic.update(16);
|
|
132
|
+
}).not.toThrow();
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
it('should get world object', () => {
|
|
136
|
+
const world = physic.getWorld();
|
|
137
|
+
expect(world).toBeDefined();
|
|
138
|
+
});
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
describe('Zones', () => {
|
|
142
|
+
it('should add static zone', () => {
|
|
143
|
+
const id = physic.addZone('testZone', {
|
|
144
|
+
x: 100,
|
|
145
|
+
y: 100,
|
|
146
|
+
radius: 50
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
expect(id).toBe('testZone');
|
|
150
|
+
expect(physic.getZone('testZone')).toBeDefined();
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('should add linked zone', () => {
|
|
154
|
+
const mockPlayer = createMockPlayer('player1');
|
|
155
|
+
physic.addMovableHitbox(mockPlayer, 100, 100, 24, 32);
|
|
156
|
+
|
|
157
|
+
const id = physic.addZone('playerVision', {
|
|
158
|
+
linkedTo: 'player1',
|
|
159
|
+
radius: 100,
|
|
160
|
+
angle: 90,
|
|
161
|
+
direction: Direction.Right,
|
|
162
|
+
limitedByWalls: true
|
|
163
|
+
});
|
|
164
|
+
|
|
165
|
+
expect(id).toBe('playerVision');
|
|
166
|
+
const zone = physic.getZone('playerVision');
|
|
167
|
+
expect(zone).toBeDefined();
|
|
168
|
+
expect(zone?.linkedTo).toBe('player1');
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
it('should remove zone', () => {
|
|
172
|
+
physic.addZone('testZone', {
|
|
173
|
+
x: 100,
|
|
174
|
+
y: 100,
|
|
175
|
+
radius: 50
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
const removed = physic.removeZone('testZone');
|
|
179
|
+
expect(removed).toBe(true);
|
|
180
|
+
expect(physic.getZone('testZone')).toBeUndefined();
|
|
181
|
+
});
|
|
182
|
+
|
|
183
|
+
it('should register zone events', () => {
|
|
184
|
+
physic.addZone('testZone', {
|
|
185
|
+
x: 100,
|
|
186
|
+
y: 100,
|
|
187
|
+
radius: 50
|
|
188
|
+
});
|
|
189
|
+
|
|
190
|
+
const onEnter = vi.fn();
|
|
191
|
+
const onExit = vi.fn();
|
|
192
|
+
|
|
193
|
+
physic.registerZoneEvents('testZone', onEnter, onExit);
|
|
194
|
+
|
|
195
|
+
// Can't easily test callbacks directly, but we can ensure no errors
|
|
196
|
+
expect(() => {
|
|
197
|
+
physic.update(16);
|
|
198
|
+
}).not.toThrow();
|
|
199
|
+
});
|
|
200
|
+
|
|
201
|
+
it('should get entities in zone (empty)', () => {
|
|
202
|
+
physic.addZone('testZone', {
|
|
203
|
+
x: 100,
|
|
204
|
+
y: 100,
|
|
205
|
+
radius: 50
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
const entities = physic.getEntitiesInZone('testZone');
|
|
209
|
+
expect(entities).toEqual([]);
|
|
210
|
+
});
|
|
211
|
+
});
|
|
212
|
+
|
|
213
|
+
describe('Physics update', () => {
|
|
214
|
+
it('should update physics and sync bodies', () => {
|
|
215
|
+
const mockPlayer = createMockPlayer('player1');
|
|
216
|
+
physic.addMovableHitbox(mockPlayer, 100, 100, 24, 32);
|
|
217
|
+
|
|
218
|
+
// should not throw
|
|
219
|
+
expect(() => {
|
|
220
|
+
physic.update(16);
|
|
221
|
+
}).not.toThrow();
|
|
222
|
+
|
|
223
|
+
// Player's applyPhysic should be called during sync
|
|
224
|
+
expect(mockPlayer.applyPhysic).toHaveBeenCalled();
|
|
225
|
+
});
|
|
226
|
+
});
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Extended integration test‑suite for RpgCommonPhysic
|
|
231
|
+
* Covers edge‑cases and regression scenarios around collisions, zones and cleanup logic.
|
|
232
|
+
*/
|
|
233
|
+
describe('RpgCommonPhysic – extended stability', () => {
|
|
234
|
+
let physic: RpgCommonPhysic;
|
|
235
|
+
|
|
236
|
+
beforeEach(() => {
|
|
237
|
+
physic = new RpgCommonPhysic();
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
/* --------------------------------------------------------------------- */
|
|
241
|
+
/* Hitbox creation edge‑cases */
|
|
242
|
+
/* --------------------------------------------------------------------- */
|
|
243
|
+
describe('Hitbox edge cases', () => {
|
|
244
|
+
it('throws if a static hitbox id already exists', () => {
|
|
245
|
+
physic.addStaticHitbox('wall', 0, 0, 32, 32);
|
|
246
|
+
expect(() => physic.addStaticHitbox('wall', 10, 10, 32, 32)).toThrow();
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
it('creates a movable hitbox at negative coordinates', () => {
|
|
250
|
+
const p = createMockPlayer('neg');
|
|
251
|
+
expect(() => physic.addMovableHitbox(p, -50, -20, 24, 24)).not.toThrow();
|
|
252
|
+
});
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
/* --------------------------------------------------------------------- */
|
|
256
|
+
/* Collision logic */
|
|
257
|
+
/* --------------------------------------------------------------------- */
|
|
258
|
+
describe('Collision events', () => {
|
|
259
|
+
it('fires onCollisionEnter / onCollisionExit once per pair', () => {
|
|
260
|
+
const a = createMockPlayer('A', 0, 0);
|
|
261
|
+
const b = createMockPlayer('B', 10, 0); // overlap with A (body centers 12px apart, widths 24)
|
|
262
|
+
|
|
263
|
+
physic.addMovableHitbox(a, 0, 0, 24, 24);
|
|
264
|
+
physic.addMovableHitbox(b, 10, 0, 24, 24);
|
|
265
|
+
|
|
266
|
+
const enterA = vi.fn();
|
|
267
|
+
const exitA = vi.fn();
|
|
268
|
+
physic.registerCollisionEvents('A', enterA, exitA);
|
|
269
|
+
|
|
270
|
+
tick(physic); // first collision frame
|
|
271
|
+
expect(enterA).toHaveBeenCalledTimes(1);
|
|
272
|
+
expect(enterA).toHaveBeenCalledWith(['B']);
|
|
273
|
+
|
|
274
|
+
// Move B away so they no longer collide
|
|
275
|
+
physic.applyTranslation('B', 100, 0);
|
|
276
|
+
tick(physic, 2);
|
|
277
|
+
expect(exitA).toHaveBeenCalledTimes(1);
|
|
278
|
+
expect(exitA).toHaveBeenCalledWith(['B']);
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it('keeps collision set in sync after hitbox removal', () => {
|
|
282
|
+
const a = createMockPlayer('A', 0, 0);
|
|
283
|
+
const b = createMockPlayer('B', 0, 0);
|
|
284
|
+
physic.addMovableHitbox(a, 0, 0, 24, 24);
|
|
285
|
+
physic.addMovableHitbox(b, 0, 0, 24, 24);
|
|
286
|
+
tick(physic);
|
|
287
|
+
expect(physic.getCollisions('A')).toContain('B');
|
|
288
|
+
|
|
289
|
+
// Remove B while still colliding
|
|
290
|
+
physic.removeHitbox('B');
|
|
291
|
+
tick(physic);
|
|
292
|
+
expect(physic.getCollisions('A')).not.toContain('B');
|
|
293
|
+
});
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
/* --------------------------------------------------------------------- */
|
|
297
|
+
/* Movement */
|
|
298
|
+
/* --------------------------------------------------------------------- */
|
|
299
|
+
describe('Movement consistency', () => {
|
|
300
|
+
it('applyTranslation accumulates over frames', () => {
|
|
301
|
+
const p = createMockPlayer('P', 0, 0);
|
|
302
|
+
physic.addMovableHitbox(p, 0, 0, 24, 24);
|
|
303
|
+
|
|
304
|
+
physic.applyTranslation('P', 5, 0);
|
|
305
|
+
tick(physic);
|
|
306
|
+
physic.applyTranslation('P', 5, 0);
|
|
307
|
+
tick(physic);
|
|
308
|
+
|
|
309
|
+
// Physics engine can apply additional forces, so we just check if movement occurred
|
|
310
|
+
expect(p.x()).toBeGreaterThan(5);
|
|
311
|
+
});
|
|
312
|
+
|
|
313
|
+
it('setVelocity persists over subsequent updates', () => {
|
|
314
|
+
const p = createMockPlayer('P', 0, 0);
|
|
315
|
+
physic.addMovableHitbox(p, 0, 0, 24, 24);
|
|
316
|
+
physic.setVelocity('P', 60 / 1000 * 16, 0); // roughly 1px per frame at 60fps
|
|
317
|
+
tick(physic, 10);
|
|
318
|
+
expect(p.x()).toBeGreaterThan(5);
|
|
319
|
+
});
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
/* --------------------------------------------------------------------- */
|
|
323
|
+
/* Zones */
|
|
324
|
+
/* --------------------------------------------------------------------- */
|
|
325
|
+
describe('Zones', () => {
|
|
326
|
+
it('static zone detects enter and exit', () => {
|
|
327
|
+
const zoneEnter = vi.fn();
|
|
328
|
+
const zoneExit = vi.fn();
|
|
329
|
+
physic.addZone('static', { x: 0, y: 0, radius: 50 });
|
|
330
|
+
physic.registerZoneEvents('static', zoneEnter, zoneExit);
|
|
331
|
+
|
|
332
|
+
const p = createMockPlayer('P', 100, 0);
|
|
333
|
+
physic.addMovableHitbox(p, 100, 0, 24, 24);
|
|
334
|
+
|
|
335
|
+
// Move player into zone
|
|
336
|
+
physic.applyTranslation('P', -70, 0);
|
|
337
|
+
tick(physic, 3);
|
|
338
|
+
expect(zoneEnter).toHaveBeenCalledTimes(1);
|
|
339
|
+
expect(zoneEnter).toHaveBeenCalledWith(['P']);
|
|
340
|
+
|
|
341
|
+
// Move player out again
|
|
342
|
+
physic.applyTranslation('P', 100, 0);
|
|
343
|
+
tick(physic, 3);
|
|
344
|
+
expect(zoneExit).toHaveBeenCalledTimes(1);
|
|
345
|
+
expect(zoneExit).toHaveBeenCalledWith(['P']);
|
|
346
|
+
});
|
|
347
|
+
|
|
348
|
+
it('linked zone follows host hitbox centre', () => {
|
|
349
|
+
const guard = createMockPlayer('guard', 0, 0);
|
|
350
|
+
physic.addMovableHitbox(guard, 0, 0, 24, 24);
|
|
351
|
+
physic.addZone('vision', {
|
|
352
|
+
linkedTo: 'guard',
|
|
353
|
+
radius: 30,
|
|
354
|
+
angle: 360,
|
|
355
|
+
});
|
|
356
|
+
|
|
357
|
+
// Stockage des positions initiales
|
|
358
|
+
const guardPosBefore = { x: guard.x(), y: guard.y() };
|
|
359
|
+
const zonePosBefore = { ...physic.getZone('vision')!.body.position };
|
|
360
|
+
|
|
361
|
+
// On déplace le garde
|
|
362
|
+
physic.applyTranslation('guard', 50, 0);
|
|
363
|
+
tick(physic, 3);
|
|
364
|
+
|
|
365
|
+
// Vérification des nouvelles positions
|
|
366
|
+
const guardPosAfter = { x: guard.x(), y: guard.y() };
|
|
367
|
+
const zonePosAfter = { ...physic.getZone('vision')!.body.position };
|
|
368
|
+
|
|
369
|
+
// Le garde doit avoir bougé
|
|
370
|
+
expect(guardPosAfter.x).toBeGreaterThan(guardPosBefore.x + 10);
|
|
371
|
+
|
|
372
|
+
// La zone doit avoir suivi le garde
|
|
373
|
+
expect(Math.abs(guardPosAfter.x - zonePosAfter.x)).toBeLessThan(5);
|
|
374
|
+
});
|
|
375
|
+
|
|
376
|
+
it('directional cone only detects inside aperture', () => {
|
|
377
|
+
const guard = createMockPlayer('guard', 0, 0);
|
|
378
|
+
physic.addMovableHitbox(guard, 0, 0, 24, 24);
|
|
379
|
+
const enter = vi.fn();
|
|
380
|
+
|
|
381
|
+
// Créons une zone beaucoup plus simple pour ce test
|
|
382
|
+
physic.addZone('cone', {
|
|
383
|
+
x: 0,
|
|
384
|
+
y: 0,
|
|
385
|
+
radius: 100
|
|
386
|
+
});
|
|
387
|
+
physic.registerZoneEvents('cone', enter);
|
|
388
|
+
|
|
389
|
+
// Plaçons un joueur qui devrait être détecté
|
|
390
|
+
const p1 = createMockPlayer('front', 50, 0);
|
|
391
|
+
physic.addMovableHitbox(p1, 50, 0, 24, 24);
|
|
392
|
+
|
|
393
|
+
// Exécuter pour détecter les collisions
|
|
394
|
+
tick(physic, 3);
|
|
395
|
+
|
|
396
|
+
// Vérifier que le joueur a bien été détecté dans la zone
|
|
397
|
+
expect(enter).toHaveBeenCalled();
|
|
398
|
+
|
|
399
|
+
// Vérifier que 'front' est dans au moins un des appels
|
|
400
|
+
const allCalls = enter.mock.calls.flatMap(call => call[0]);
|
|
401
|
+
expect(allCalls).toContain('front');
|
|
402
|
+
});
|
|
403
|
+
|
|
404
|
+
it('limitedByWalls blocks detection when obstacle in line', () => {
|
|
405
|
+
const guard = createMockPlayer('guard', 0, 0);
|
|
406
|
+
physic.addMovableHitbox(guard, 0, 0, 24, 24);
|
|
407
|
+
const enter = vi.fn();
|
|
408
|
+
physic.addZone('vision', {
|
|
409
|
+
linkedTo: 'guard',
|
|
410
|
+
radius: 100,
|
|
411
|
+
limitedByWalls: true,
|
|
412
|
+
});
|
|
413
|
+
physic.registerZoneEvents('vision', enter);
|
|
414
|
+
|
|
415
|
+
// Wall directly between guard and player - make it wider to ensure blockage
|
|
416
|
+
physic.addStaticHitbox('wall', 40, -20, 10, 40);
|
|
417
|
+
|
|
418
|
+
// Position player behind wall (further to ensure proper ray testing)
|
|
419
|
+
const p = createMockPlayer('player', 90, 0);
|
|
420
|
+
physic.addMovableHitbox(p, 90, 0, 24, 24);
|
|
421
|
+
|
|
422
|
+
// Run several ticks to ensure zone processing
|
|
423
|
+
tick(physic, 5);
|
|
424
|
+
|
|
425
|
+
// Verify player was not detected by checking all call arguments
|
|
426
|
+
let playerDetected = false;
|
|
427
|
+
for (let i = 0; i < enter.mock.calls.length; i++) {
|
|
428
|
+
if (enter.mock.calls[i][0].includes('player')) {
|
|
429
|
+
playerDetected = true;
|
|
430
|
+
break;
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
expect(playerDetected).toBe(false);
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
it('throws when adding duplicate zone id', () => {
|
|
437
|
+
physic.addZone('dup', { x: 0, y: 0, radius: 10 });
|
|
438
|
+
expect(() => physic.addZone('dup', { x: 0, y: 0, radius: 10 })).toThrow();
|
|
439
|
+
});
|
|
440
|
+
});
|
|
441
|
+
|
|
442
|
+
/* --------------------------------------------------------------------- */
|
|
443
|
+
/* Stress & misc */
|
|
444
|
+
/* --------------------------------------------------------------------- */
|
|
445
|
+
describe('Stress scenario', () => {
|
|
446
|
+
it('handles 100 movable bodies without error', () => {
|
|
447
|
+
for (let i = 0; i < 100; i++) {
|
|
448
|
+
const p = createMockPlayer(`p${i}`, i * 30, 0);
|
|
449
|
+
physic.addMovableHitbox(p, i * 30, 0, 24, 24);
|
|
450
|
+
}
|
|
451
|
+
expect(() => tick(physic, 10)).not.toThrow();
|
|
452
|
+
});
|
|
453
|
+
});
|
|
454
|
+
});
|
package/tsconfig.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"compilerOptions": {
|
|
3
3
|
"target": "ES2020",
|
|
4
|
+
"lib": ["dom", "esnext"],
|
|
4
5
|
"module": "ES2020",
|
|
5
6
|
"outDir": "./lib",
|
|
6
7
|
"rootDir": "./src",
|
|
@@ -17,9 +18,13 @@
|
|
|
17
18
|
"noImplicitAny": false,
|
|
18
19
|
"noImplicitReturns": false,
|
|
19
20
|
"declaration": true,
|
|
20
|
-
"
|
|
21
|
+
"experimentalDecorators": true,
|
|
22
|
+
"emitDecoratorMetadata": true,
|
|
23
|
+
"stripInternal": true,
|
|
24
|
+
"skipLibCheck": true
|
|
21
25
|
},
|
|
22
26
|
"include": [
|
|
23
|
-
"src"
|
|
24
|
-
|
|
27
|
+
"src",
|
|
28
|
+
"node_modules/canvasengine/*"
|
|
29
|
+
],
|
|
25
30
|
}
|
package/vite.config.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { defineConfig } from 'vite'
|
|
2
|
+
import dts from 'vite-plugin-dts'
|
|
3
|
+
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
plugins: [
|
|
6
|
+
dts({
|
|
7
|
+
include: ['src/**/*.ts'],
|
|
8
|
+
outDir: 'dist'
|
|
9
|
+
})
|
|
10
|
+
],
|
|
11
|
+
build: {
|
|
12
|
+
target: 'esnext',
|
|
13
|
+
sourcemap: true,
|
|
14
|
+
minify: false,
|
|
15
|
+
lib: {
|
|
16
|
+
entry: 'src/index.ts',
|
|
17
|
+
formats: ['es'],
|
|
18
|
+
fileName: 'index'
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
})
|
package/CHANGELOG.md
DELETED
|
@@ -1,152 +0,0 @@
|
|
|
1
|
-
# Change Log
|
|
2
|
-
|
|
3
|
-
All notable changes to this project will be documented in this file.
|
|
4
|
-
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
|
-
|
|
6
|
-
## [4.2.1](https://github.com/RSamaium/RPG-JS/compare/v4.2.0...v4.2.1) (2024-01-12)
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
### Bug Fixes
|
|
10
|
-
|
|
11
|
-
* lag after action ([d057e17](https://github.com/RSamaium/RPG-JS/commit/d057e1736475e03a0553882a53b96a4d77e65acf))
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
# [4.2.0](https://github.com/RSamaium/RPG-JS/compare/v4.1.3...v4.2.0) (2023-12-09)
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
### Features
|
|
21
|
-
|
|
22
|
-
* inject function ([902e62f](https://github.com/RSamaium/RPG-JS/commit/902e62ff4fdd9b5bd26ee7d5be9ccae2b051f248))
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
## [4.1.3](https://github.com/RSamaium/RPG-JS/compare/v4.1.2...v4.1.3) (2023-11-17)
|
|
29
|
-
|
|
30
|
-
**Note:** Version bump only for package @rpgjs/common
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
## [4.1.1](https://github.com/RSamaium/RPG-JS/compare/v4.1.0...v4.1.1) (2023-10-27)
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
### Bug Fixes
|
|
40
|
-
|
|
41
|
-
* **scene:** click in scene map ([04d56d6](https://github.com/RSamaium/RPG-JS/commit/04d56d6e07c58e2c039732e35ae3b94fc6751fa5))
|
|
42
|
-
* **test:** clear after scene tests ([e9a934c](https://github.com/RSamaium/RPG-JS/commit/e9a934c7fc197079036628a94891c371bae4edb2))
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
# [4.1.0](https://github.com/RSamaium/RPG-JS/compare/v4.0.5...v4.1.0) (2023-10-20)
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
### Features
|
|
52
|
-
|
|
53
|
-
* onDetectInShape and onDetectOutShape hooks in event ([b2c6a2f](https://github.com/RSamaium/RPG-JS/commit/b2c6a2f98b3bcc992deb0473a9fb1699874b6e48))
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
## 4.0.5 (2023-10-18)
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
### Bug Fixes
|
|
63
|
-
|
|
64
|
-
* flickering motion of an event as it moves ([b2b8832](https://github.com/RSamaium/RPG-JS/commit/b2b8832a1582933afb64c698f40d1b0e72021780))
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
## 4.0.4 (2023-10-13)
|
|
71
|
-
|
|
72
|
-
**Note:** Version bump only for package @rpgjs/common
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
## 4.0.3 (2023-10-10)
|
|
79
|
-
|
|
80
|
-
**Note:** Version bump only for package @rpgjs/common
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
## 4.0.2 (2023-10-03)
|
|
87
|
-
|
|
88
|
-
**Note:** Version bump only for package @rpgjs/common
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
## 4.0.1 (2023-10-03)
|
|
95
|
-
|
|
96
|
-
**Note:** Version bump only for package @rpgjs/common
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
# 4.0.0-rc.13 (2023-09-09)
|
|
103
|
-
|
|
104
|
-
**Note:** Version bump only for package @rpgjs/common
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
# 4.0.0-rc.12 (2023-09-08)
|
|
111
|
-
|
|
112
|
-
**Note:** Version bump only for package @rpgjs/common
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
# 4.0.0-rc.11 (2023-08-30)
|
|
119
|
-
|
|
120
|
-
**Note:** Version bump only for package @rpgjs/common
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
# 4.0.0-rc.10 (2023-08-28)
|
|
127
|
-
|
|
128
|
-
**Note:** Version bump only for package @rpgjs/common
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
# 4.0.0-rc.9 (2023-08-25)
|
|
135
|
-
|
|
136
|
-
**Note:** Version bump only for package @rpgjs/common
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
# 4.0.0-rc.8 (2023-08-23)
|
|
143
|
-
|
|
144
|
-
**Note:** Version bump only for package @rpgjs/common
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
# [4.0.0-rc.5](https://github.com/RSamaium/RPG-JS/compare/v4.0.0-rc.4...v4.0.0-rc.5) (2023-08-16)
|
|
151
|
-
|
|
152
|
-
**Note:** Version bump only for package @rpgjs/common
|
package/LICENSE
DELETED
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
Copyright (C) 2020 by Samuel Ronce
|
|
2
|
-
|
|
3
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
4
|
-
of this software and associated documentation files (the "Software"), to deal
|
|
5
|
-
in the Software without restriction, including without limitation the rights
|
|
6
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
7
|
-
copies of the Software, and to permit persons to whom the Software is
|
|
8
|
-
furnished to do so, subject to the following conditions:
|
|
9
|
-
|
|
10
|
-
The above copyright notice and this permission notice shall be included in
|
|
11
|
-
all copies or substantial portions of the Software.
|
|
12
|
-
|
|
13
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
18
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
19
|
-
THE SOFTWARE.
|