@gg-web-engine/rapier3d 0.0.72 → 0.0.73
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/components/rapier-3d-character-controller.component.d.ts +13 -8
- package/dist/components/rapier-3d-character-controller.component.js +49 -8
- package/dist/components/rapier-3d-raycast-vehicle.component.d.ts +47 -2
- package/dist/components/rapier-3d-raycast-vehicle.component.js +153 -45
- package/dist/components/rapier-3d-rigid-body.component.d.ts +20 -1
- package/dist/components/rapier-3d-rigid-body.component.js +73 -2
- package/dist/components/rapier-3d-trigger.component.d.ts +7 -6
- package/dist/components/rapier-3d-trigger.component.js +6 -0
- package/dist/components/rapier-3d-world.component.d.ts +35 -1
- package/dist/components/rapier-3d-world.component.js +59 -4
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -1
- package/dist/rapier-3d-factory.d.ts +3 -2
- package/dist/rapier-3d-factory.js +24 -5
- package/dist/types.d.ts +2 -1
- package/package.json +3 -3
- package/test/components/rapier-3d-player-character-controller-integration.spec.ts +3 -0
- package/test/components/rapier-3d-raycast-vehicle.component.spec.ts +160 -0
- package/test/components/rapier-3d-rigid-body.component.spec.ts +68 -0
- package/test/components/rapier-3d-trigger-character-controller-integration.spec.ts +85 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { CharacterController3dOptions, Pnt3 } from '@gg-web-engine/core';
|
|
2
|
+
import { Rapier3dFactory, Rapier3dWorldComponent } from '../../src';
|
|
3
|
+
|
|
4
|
+
// Regression coverage for the gap where `Trigger3dEntity.onEntityEntered`/`onEntityLeft` silently
|
|
5
|
+
// never fired for a `Rapier3dCharacterControllerComponent` (the "Player" built-in / any app-authored
|
|
6
|
+
// character), because `Rapier3dWorldComponent.handleIdEntityMap` never registered a character
|
|
7
|
+
// controller's native body handle - `dispatchCollisionEvents` resolved both sides of every sensor
|
|
8
|
+
// pair through that same map, so a pair involving a character controller always bailed out at
|
|
9
|
+
// `if (!comp1 || !comp2 ...)` before ever reaching `Rapier3dTriggerComponent.notifyOverlap`. See
|
|
10
|
+
// `Rapier3dCharacterControllerComponent`'s own class doc and `Rapier3dWorldComponent.handleIdEntityMap`'s
|
|
11
|
+
// doc for the fix. Vehicles need no equivalent test here - a raycast vehicle's chassis is an ordinary
|
|
12
|
+
// `Rapier3dRigidBodyComponent` (see `packages/core`'s `RaycastVehicle3dEntity`), already covered by
|
|
13
|
+
// `rapier-3d-trigger.component.spec.ts`'s plain rigid-body cases; Rapier3d itself doesn't implement
|
|
14
|
+
// raycast vehicles at all (`Rapier3dFactory.createRaycastVehicle` throws), so Ammo is the only adapter
|
|
15
|
+
// with real vehicle physics to exercise.
|
|
16
|
+
describe(`Rapier3dTriggerComponent x Rapier3dCharacterControllerComponent`, () => {
|
|
17
|
+
let world: Rapier3dWorldComponent;
|
|
18
|
+
let factory: Rapier3dFactory;
|
|
19
|
+
|
|
20
|
+
beforeEach(async () => {
|
|
21
|
+
if (world) {
|
|
22
|
+
world.dispose();
|
|
23
|
+
}
|
|
24
|
+
world = new Rapier3dWorldComponent();
|
|
25
|
+
factory = new Rapier3dFactory(world);
|
|
26
|
+
await world.init();
|
|
27
|
+
world.gravity = Pnt3.O;
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
afterAll(() => {
|
|
31
|
+
world.dispose();
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
const CHAR_OPTIONS: CharacterController3dOptions = { radius: 0.4, centersDistance: 1.0 };
|
|
35
|
+
|
|
36
|
+
// Mirrors `rapier-3d-trigger.component.spec.ts`'s own `advance` helper/doc - many small steps so a
|
|
37
|
+
// step-boundary lag in `EventQueue` drainage never reads as a missed event, and `checkOverlaps()`
|
|
38
|
+
// runs every step (not just once at the end) since `EventQueue` is constructed with `autoDrain: true`.
|
|
39
|
+
const advance = (totalMs: number, onStep: () => void, stepMs = 10) => {
|
|
40
|
+
for (let elapsed = 0; elapsed < totalMs; elapsed += stepMs) {
|
|
41
|
+
world.simulate(stepMs);
|
|
42
|
+
onStep();
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
it('fires onEntityEntered/onEntityLeft for a character controller walking through it', () => {
|
|
47
|
+
const trigger = factory.createTrigger({ shape: 'BOX', dimensions: { x: 10, y: 10, z: 10 } });
|
|
48
|
+
trigger.addToWorld({ physicsWorld: world } as any);
|
|
49
|
+
|
|
50
|
+
const character = factory.createCharacterController(CHAR_OPTIONS, { position: { x: -8, y: 0, z: 0 } });
|
|
51
|
+
character.addToWorld({ physicsWorld: world } as any);
|
|
52
|
+
// register the freshly-created colliders with Rapier's broad-phase before the first move, same
|
|
53
|
+
// as `rapier-3d-character-controller.component.spec.ts`'s own `settleWorld()`.
|
|
54
|
+
world.simulate(0);
|
|
55
|
+
|
|
56
|
+
let entered: unknown;
|
|
57
|
+
let exited: unknown;
|
|
58
|
+
trigger.onEntityEntered.subscribe(obj => (entered = obj));
|
|
59
|
+
trigger.onEntityLeft.subscribe(obj => (exited = obj));
|
|
60
|
+
|
|
61
|
+
// walk from x=-8 to x=12 (1 unit/step over 20 steps), straight through the trigger's -5..5 span.
|
|
62
|
+
for (let i = 0; i < 20; i++) {
|
|
63
|
+
character.move({ x: 1, y: 0, z: 0 });
|
|
64
|
+
advance(10, () => trigger.checkOverlaps());
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
expect(entered).toBe(character);
|
|
68
|
+
expect(exited).toBe(character);
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('fires onEntityEntered for a character controller already spawned inside it', () => {
|
|
72
|
+
const trigger = factory.createTrigger({ shape: 'BOX', dimensions: { x: 10, y: 10, z: 10 } });
|
|
73
|
+
trigger.addToWorld({ physicsWorld: world } as any);
|
|
74
|
+
|
|
75
|
+
const character = factory.createCharacterController(CHAR_OPTIONS, { position: { x: 0, y: 0, z: 0 } });
|
|
76
|
+
character.addToWorld({ physicsWorld: world } as any);
|
|
77
|
+
|
|
78
|
+
let entered: unknown;
|
|
79
|
+
trigger.onEntityEntered.subscribe(obj => (entered = obj));
|
|
80
|
+
|
|
81
|
+
advance(500, () => trigger.checkOverlaps());
|
|
82
|
+
|
|
83
|
+
expect(entered).toBe(character);
|
|
84
|
+
});
|
|
85
|
+
});
|