@gg-web-engine/rapier3d 0.0.70 → 0.0.71
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 +0 -1
- package/dist/components/rapier-3d-character-controller.component.js +5 -12
- package/dist/components/rapier-3d-rigid-body.component.d.ts +3 -3
- package/dist/components/rapier-3d-rigid-body.component.js +30 -6
- package/dist/rapier-3d-factory.js +36 -9
- package/package.json +3 -3
- package/test/components/rapier-3d-character-controller.component.spec.ts +3 -3
- package/test/components/rapier-3d-object-grab-integration.spec.ts +2 -2
- package/test/components/rapier-3d-player-character-controller-integration.spec.ts +3 -3
- package/test/components/rapier-3d-rigid-body-collision.spec.ts +2 -2
- package/test/components/rapier-3d-trigger.component.spec.ts +5 -5
- package/test/components/rapier-3d-world.component.spec.ts +14 -14
- package/test/rapier-3d-factory.spec.ts +21 -1
|
@@ -50,7 +50,6 @@ export declare class Rapier3dCharacterControllerComponent implements ICharacterC
|
|
|
50
50
|
* Rapier's character controller supports excluding specific colliders from a single query
|
|
51
51
|
* natively, so no such trick is needed here. */
|
|
52
52
|
readonly ignoredBodies: Set<Rapier3dRigidBodyComponent>;
|
|
53
|
-
private static warnedMissingDtForPush;
|
|
54
53
|
protected _nativeBody: RigidBody | null;
|
|
55
54
|
protected _nativeCollider: Collider | null;
|
|
56
55
|
protected _nativeController: KinematicCharacterController | null;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BitMask, DebugBody3DSettings, Pnt3, Qtrn, } from '@gg-web-engine/core';
|
|
1
|
+
import { BitMask, DebugBody3DSettings, Pnt3, Qtrn, warnOnce, } from '@gg-web-engine/core';
|
|
2
2
|
import { Quaternion, RigidBodyDesc, Vector3, } from '@dimforge/rapier3d-compat';
|
|
3
3
|
/**
|
|
4
4
|
* A capsule-shaped kinematic character controller backed by Rapier's own `KinematicCharacterController`
|
|
@@ -253,13 +253,10 @@ export class Rapier3dCharacterControllerComponent {
|
|
|
253
253
|
// `dt` - silently wrong, not just imprecise - so skip the push for this tick instead when `dt`
|
|
254
254
|
// isn't available, same as `AmmoCharacterControllerComponent.pushDynamicBody`.
|
|
255
255
|
if (!dt || dt <= 1e-9) {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
'per-tick displacement (which would understate push force by roughly 1/dt). Pass the ' +
|
|
261
|
-
'real tick delta (seconds) as the third argument to move() to enable pushing dynamic bodies.');
|
|
262
|
-
}
|
|
256
|
+
warnOnce('[Rapier3dCharacterControllerComponent] move() was called without `dt` while `pushMass` > ' +
|
|
257
|
+
'0 - skipping this dynamic-body push rather than approximating character speed from raw ' +
|
|
258
|
+
'per-tick displacement (which would understate push force by roughly 1/dt). Pass the ' +
|
|
259
|
+
'real tick delta (seconds) as the third argument to move() to enable pushing dynamic bodies.');
|
|
263
260
|
return;
|
|
264
261
|
}
|
|
265
262
|
const direction = Pnt3.scalarMult(horizontal, 1 / horizLen);
|
|
@@ -423,7 +420,3 @@ export class Rapier3dCharacterControllerComponent {
|
|
|
423
420
|
}
|
|
424
421
|
}
|
|
425
422
|
}
|
|
426
|
-
// Module-wide (not per-instance) so a scene with several characters all being driven without
|
|
427
|
-
// `dt` still only logs once, not once per character per tick - see `pushDynamicBodies`'s
|
|
428
|
-
// missing-`dt` handling below.
|
|
429
|
-
Rapier3dCharacterControllerComponent.warnedMissingDtForPush = false;
|
|
@@ -8,7 +8,7 @@ export declare class Rapier3dRigidBodyComponent implements IRigidBody3dComponent
|
|
|
8
8
|
protected _colliderDescr: ColliderDesc[];
|
|
9
9
|
readonly shape: Shape3DDescriptor;
|
|
10
10
|
protected _bodyDescr: RigidBodyDesc;
|
|
11
|
-
protected _colliderOptions: Omit<Omit<Body3DOptions, '
|
|
11
|
+
protected _colliderOptions: Omit<Omit<Body3DOptions, 'bodyType'>, 'mass'>;
|
|
12
12
|
entity: Entity3d | null;
|
|
13
13
|
get position(): Point3;
|
|
14
14
|
set position(value: Point3);
|
|
@@ -55,9 +55,9 @@ export declare class Rapier3dRigidBodyComponent implements IRigidBody3dComponent
|
|
|
55
55
|
ColliderDesc[],
|
|
56
56
|
Shape3DDescriptor,
|
|
57
57
|
RigidBodyDesc,
|
|
58
|
-
Omit<Omit<Body3DOptions, '
|
|
58
|
+
Omit<Omit<Body3DOptions, 'bodyType'>, 'mass'>
|
|
59
59
|
];
|
|
60
|
-
constructor(world: Rapier3dWorldComponent, _colliderDescr: ColliderDesc[], shape: Shape3DDescriptor, _bodyDescr: RigidBodyDesc, _colliderOptions: Omit<Omit<Body3DOptions, '
|
|
60
|
+
constructor(world: Rapier3dWorldComponent, _colliderDescr: ColliderDesc[], shape: Shape3DDescriptor, _bodyDescr: RigidBodyDesc, _colliderOptions: Omit<Omit<Body3DOptions, 'bodyType'>, 'mass'>);
|
|
61
61
|
protected collisionGroups: InteractionGroups;
|
|
62
62
|
get interactWithCollisionGroups(): ReadonlyArray<CollisionGroup>;
|
|
63
63
|
set interactWithCollisionGroups(value: ReadonlyArray<CollisionGroup> | 'all');
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { BitMask, DebugBody3DSettings, Pnt3, Qtrn, } from '@gg-web-engine/core';
|
|
2
|
-
import { ColliderDesc, Quaternion, RigidBodyDesc, Vector3, } from '@dimforge/rapier3d-compat';
|
|
2
|
+
import { ColliderDesc, Quaternion, RigidBodyDesc, RigidBodyType, Vector3, } from '@dimforge/rapier3d-compat';
|
|
3
3
|
import { Subject } from 'rxjs';
|
|
4
4
|
export class Rapier3dRigidBodyComponent {
|
|
5
5
|
get position() {
|
|
@@ -7,7 +7,18 @@ export class Rapier3dRigidBodyComponent {
|
|
|
7
7
|
}
|
|
8
8
|
set position(value) {
|
|
9
9
|
if (this.nativeBody) {
|
|
10
|
-
|
|
10
|
+
// A `kinematicPositionBased` body must move through `setNextKinematicTranslation` rather
|
|
11
|
+
// than the immediate teleport `setTranslation` does - only that path lets Rapier derive the
|
|
12
|
+
// body's effective velocity for this step and correctly push/wake dynamic bodies in its way
|
|
13
|
+
// (see `BodyOptions.kinematic_pos`'s own doc, and the "plain teleport" pitfall it links to).
|
|
14
|
+
// `kinematicVelocityBased` and `dynamic` bodies keep the immediate teleport - the former is
|
|
15
|
+
// already driven by `linearVelocity` each step, not by `position` writes.
|
|
16
|
+
if (this.nativeBody.bodyType() === RigidBodyType.KinematicPositionBased) {
|
|
17
|
+
this.nativeBody.setNextKinematicTranslation(new Vector3(value.x, value.y, value.z));
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
this.nativeBody.setTranslation(new Vector3(value.x, value.y, value.z), true);
|
|
21
|
+
}
|
|
11
22
|
}
|
|
12
23
|
else {
|
|
13
24
|
this._bodyDescr.setTranslation(value.x, value.y, value.z);
|
|
@@ -18,7 +29,14 @@ export class Rapier3dRigidBodyComponent {
|
|
|
18
29
|
}
|
|
19
30
|
set rotation(value) {
|
|
20
31
|
if (this.nativeBody) {
|
|
21
|
-
|
|
32
|
+
// see `position`'s setter above for why a kinematic-position-based body needs the "next
|
|
33
|
+
// kinematic" API instead of an immediate teleport.
|
|
34
|
+
if (this.nativeBody.bodyType() === RigidBodyType.KinematicPositionBased) {
|
|
35
|
+
this.nativeBody.setNextKinematicRotation(new Quaternion(value.x, value.y, value.z, value.w));
|
|
36
|
+
}
|
|
37
|
+
else {
|
|
38
|
+
this.nativeBody.setRotation(new Quaternion(value.x, value.y, value.z, value.w), true);
|
|
39
|
+
}
|
|
22
40
|
}
|
|
23
41
|
else {
|
|
24
42
|
this._bodyDescr.setRotation(new Quaternion(value.x, value.y, value.z, value.w));
|
|
@@ -93,6 +111,10 @@ export class Rapier3dRigidBodyComponent {
|
|
|
93
111
|
bd.mass = this._bodyDescr.mass;
|
|
94
112
|
bd.setTranslation(this._bodyDescr.translation.x, this._bodyDescr.translation.y, this._bodyDescr.translation.z);
|
|
95
113
|
bd.setRotation(Object.assign({}, this._bodyDescr.rotation));
|
|
114
|
+
// `ccdEnabled` is a plain field on `RigidBodyDesc` (not copied by the constructor above), not
|
|
115
|
+
// just a constructor-only `setCcdEnabled` call - carry it over explicitly so `clone()` doesn't
|
|
116
|
+
// silently drop CCD off the copy.
|
|
117
|
+
bd.setCcdEnabled(this._bodyDescr.ccdEnabled);
|
|
96
118
|
// TODO more fields here?
|
|
97
119
|
return [colliderDescr, this.shape, bd, this._colliderOptions];
|
|
98
120
|
}
|
|
@@ -103,9 +125,11 @@ export class Rapier3dRigidBodyComponent {
|
|
|
103
125
|
this._bodyDescr = _bodyDescr;
|
|
104
126
|
this._colliderOptions = _colliderOptions;
|
|
105
127
|
this.entity = null;
|
|
106
|
-
this.debugBodySettings = new DebugBody3DSettings(this._bodyDescr.
|
|
107
|
-
? { type: '
|
|
108
|
-
:
|
|
128
|
+
this.debugBodySettings = new DebugBody3DSettings(this._bodyDescr.status == RigidBodyType.Fixed
|
|
129
|
+
? { type: 'RIGID_STATIC' }
|
|
130
|
+
: this._bodyDescr.status == RigidBodyType.Dynamic
|
|
131
|
+
? { type: 'RIGID_DYNAMIC', sleeping: () => { var _a; return !!((_a = this._nativeBody) === null || _a === void 0 ? void 0 : _a.isSleeping()); } }
|
|
132
|
+
: { type: 'RIGID_KINEMATIC' }, this.shape);
|
|
109
133
|
this._nativeBody = null;
|
|
110
134
|
this._nativeBodyColliders = null;
|
|
111
135
|
this.name = '';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Pnt3, Qtrn, } from '@gg-web-engine/core';
|
|
1
|
+
import { getCylinderRadii, Pnt3, Qtrn, } from '@gg-web-engine/core';
|
|
2
2
|
import { ActiveEvents, ColliderDesc, Quaternion, RigidBodyDesc } from '@dimforge/rapier3d-compat';
|
|
3
3
|
import { Rapier3dRigidBodyComponent } from './components/rapier-3d-rigid-body.component';
|
|
4
4
|
import { Rapier3dTriggerComponent } from './components/rapier-3d-trigger.component';
|
|
@@ -29,7 +29,7 @@ export class Rapier3dFactory {
|
|
|
29
29
|
// ordinary rigid-body-vs-rigid-body contact needs it here too, since neither side had it before).
|
|
30
30
|
const colliderDescr = this.createColliderDescr(descriptor.shape);
|
|
31
31
|
colliderDescr.forEach(c => c.setActiveEvents(ActiveEvents.COLLISION_EVENTS));
|
|
32
|
-
return new Rapier3dRigidBodyComponent(this.world, colliderDescr, descriptor.shape, this.createRigidBodyDescr(descriptor.body, transform), Object.assign({ friction: 0.5, restitution: 0.1, ownCollisionGroups: [this.world.mainCollisionGroup], interactWithCollisionGroups: [this.world.mainCollisionGroup] }, descriptor.body));
|
|
32
|
+
return new Rapier3dRigidBodyComponent(this.world, colliderDescr, descriptor.shape, this.createRigidBodyDescr(descriptor.body, transform), Object.assign({ friction: 0.5, restitution: 0.1, ownCollisionGroups: [this.world.mainCollisionGroup], interactWithCollisionGroups: [this.world.mainCollisionGroup], ccd: false }, descriptor.body));
|
|
33
33
|
}
|
|
34
34
|
createTrigger(descriptor, transform) {
|
|
35
35
|
const colliderDescr = this.createColliderDescr(descriptor);
|
|
@@ -37,7 +37,7 @@ export class Rapier3dFactory {
|
|
|
37
37
|
c.isSensor = true;
|
|
38
38
|
c.setActiveEvents(ActiveEvents.COLLISION_EVENTS);
|
|
39
39
|
});
|
|
40
|
-
return new Rapier3dTriggerComponent(this.world, colliderDescr, descriptor, this.createRigidBodyDescr({
|
|
40
|
+
return new Rapier3dTriggerComponent(this.world, colliderDescr, descriptor, this.createRigidBodyDescr({ bodyType: 'static' }, transform));
|
|
41
41
|
}
|
|
42
42
|
createRaycastVehicle(chassis) {
|
|
43
43
|
throw new Error('Raycast vehicle bindings for rapier3D are not implemented');
|
|
@@ -66,10 +66,27 @@ export class Rapier3dFactory {
|
|
|
66
66
|
const capsule = ColliderDesc.capsule(descriptor.centersDistance / 2, descriptor.radius);
|
|
67
67
|
capsule.setRotation(new Quaternion(yToZUp.x, yToZUp.y, yToZUp.z, yToZUp.w));
|
|
68
68
|
return [capsule];
|
|
69
|
-
case 'CYLINDER':
|
|
70
|
-
const
|
|
71
|
-
|
|
72
|
-
|
|
69
|
+
case 'CYLINDER': {
|
|
70
|
+
const { radiusX, radiusY } = getCylinderRadii(descriptor);
|
|
71
|
+
if (radiusX === radiusY) {
|
|
72
|
+
const cylinder = ColliderDesc.cylinder(descriptor.height / 2, radiusX);
|
|
73
|
+
cylinder.setRotation(new Quaternion(yToZUp.x, yToZUp.y, yToZUp.z, yToZUp.w));
|
|
74
|
+
return [cylinder];
|
|
75
|
+
}
|
|
76
|
+
// Rapier/parry has no native elliptical-radius primitive (unlike Bullet's
|
|
77
|
+
// btCylinderShapeZ, which takes independent X/Y half-extents) - approximate with a
|
|
78
|
+
// convex hull over the two elliptical end-cap rings instead.
|
|
79
|
+
const ellipseSegments = 32;
|
|
80
|
+
const halfHeight = descriptor.height / 2;
|
|
81
|
+
const vertices = [];
|
|
82
|
+
for (let i = 0; i < ellipseSegments; i++) {
|
|
83
|
+
const angle = (i / ellipseSegments) * Math.PI * 2;
|
|
84
|
+
const x = radiusX * Math.cos(angle);
|
|
85
|
+
const y = radiusY * Math.sin(angle);
|
|
86
|
+
vertices.push(x, y, -halfHeight, x, y, halfHeight);
|
|
87
|
+
}
|
|
88
|
+
return [ColliderDesc.convexHull(new Float32Array(vertices))];
|
|
89
|
+
}
|
|
73
90
|
case 'CONE':
|
|
74
91
|
const cone = ColliderDesc.cone(descriptor.height / 2, descriptor.radius);
|
|
75
92
|
cone.setRotation(new Quaternion(yToZUp.x, yToZUp.y, yToZUp.z, yToZUp.w));
|
|
@@ -113,14 +130,24 @@ export class Rapier3dFactory {
|
|
|
113
130
|
createRigidBodyDescr(options, transform) {
|
|
114
131
|
const pos = (transform === null || transform === void 0 ? void 0 : transform.position) || Pnt3.O;
|
|
115
132
|
const rot = (transform === null || transform === void 0 ? void 0 : transform.rotation) || Qtrn.O;
|
|
116
|
-
const fixed = options.dynamic === false || !options.mass;
|
|
117
133
|
let bodyDesc;
|
|
118
|
-
|
|
134
|
+
let bodyType = options.bodyType || (options.mass ? 'dynamic' : 'static');
|
|
135
|
+
if (bodyType === 'static') {
|
|
119
136
|
bodyDesc = RigidBodyDesc.fixed();
|
|
120
137
|
}
|
|
138
|
+
else if (bodyType === 'kinematic_pos') {
|
|
139
|
+
bodyDesc = RigidBodyDesc.kinematicPositionBased();
|
|
140
|
+
}
|
|
141
|
+
else if (bodyType === 'kinematic_vel') {
|
|
142
|
+
bodyDesc = RigidBodyDesc.kinematicVelocityBased();
|
|
143
|
+
}
|
|
121
144
|
else {
|
|
122
145
|
bodyDesc = RigidBodyDesc.dynamic();
|
|
123
146
|
bodyDesc.mass = options.mass || 1;
|
|
147
|
+
// Only a dynamic body can tunnel through geometry it crosses within a single step - a fixed
|
|
148
|
+
// or kinematic body is never the one doing the moving-too-fast-to-detect part of that, so CCD
|
|
149
|
+
// is meaningless for either (see `BodyOptions.ccd`'s own doc).
|
|
150
|
+
bodyDesc.setCcdEnabled(!!options.ccd);
|
|
124
151
|
}
|
|
125
152
|
return bodyDesc.setTranslation(pos.x, pos.y, pos.z).setRotation(new Quaternion(rot.x, rot.y, rot.z, rot.w));
|
|
126
153
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gg-web-engine/rapier3d",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.71",
|
|
4
4
|
"description": "An attempt to create open source game engine for browser",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -28,7 +28,7 @@
|
|
|
28
28
|
"homepage": "https://github.com/AndyGura/gg-web-engine#readme",
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@dimforge/rapier3d-compat": "0.20.0",
|
|
31
|
-
"@gg-web-engine/core": "0.0.
|
|
31
|
+
"@gg-web-engine/core": "0.0.71",
|
|
32
32
|
"@types/jest": "^30.0.0",
|
|
33
33
|
"@types/node": "^26.4.0",
|
|
34
34
|
"jest": "^30.5.0",
|
|
@@ -40,7 +40,7 @@
|
|
|
40
40
|
},
|
|
41
41
|
"peerDependencies": {
|
|
42
42
|
"@dimforge/rapier3d-compat": "0.20.0",
|
|
43
|
-
"@gg-web-engine/core": "0.0.
|
|
43
|
+
"@gg-web-engine/core": "0.0.71",
|
|
44
44
|
"rxjs": "7.8.2"
|
|
45
45
|
},
|
|
46
46
|
"jest": {
|
|
@@ -29,7 +29,7 @@ describe('Rapier3dCharacterControllerComponent', () => {
|
|
|
29
29
|
const floor = factory.createRigidBody(
|
|
30
30
|
{
|
|
31
31
|
shape: { shape: 'BOX', dimensions: { x: sizeX, y: 20, z: thickness } },
|
|
32
|
-
body: {
|
|
32
|
+
body: { bodyType: 'static', mass: 0 },
|
|
33
33
|
},
|
|
34
34
|
{ position: { x: centerX, y: 0, z: topZ - thickness / 2 } },
|
|
35
35
|
);
|
|
@@ -42,7 +42,7 @@ describe('Rapier3dCharacterControllerComponent', () => {
|
|
|
42
42
|
const wall = factory.createRigidBody(
|
|
43
43
|
{
|
|
44
44
|
shape: { shape: 'BOX', dimensions: { x: thickness, y: 20, z: 5 } },
|
|
45
|
-
body: {
|
|
45
|
+
body: { bodyType: 'static', mass: 0 },
|
|
46
46
|
},
|
|
47
47
|
{ position: { x: x + thickness / 2, y: 0, z: 2.5 } },
|
|
48
48
|
);
|
|
@@ -98,7 +98,7 @@ describe('Rapier3dCharacterControllerComponent', () => {
|
|
|
98
98
|
// continued contact with the steep surface.
|
|
99
99
|
addFloor(0, 20, 0);
|
|
100
100
|
const sphere = factory.createRigidBody(
|
|
101
|
-
{ shape: { shape: 'SPHERE', radius: 1 }, body: {
|
|
101
|
+
{ shape: { shape: 'SPHERE', radius: 1 }, body: { bodyType: 'static', mass: 0 } },
|
|
102
102
|
{ position: { x: 0, y: 0, z: 1 } },
|
|
103
103
|
);
|
|
104
104
|
sphere.addToWorld({ physicsWorld: world } as any);
|
|
@@ -36,13 +36,13 @@ import { Rapier3dWorldComponent } from '../../src';
|
|
|
36
36
|
describe('ObjectGrabController + Rapier3dWorldComponent - end-to-end pick-up range', () => {
|
|
37
37
|
const setupPedestalAndRadio = (world: Rapier3dWorldComponent, radioPosition: Point3) => {
|
|
38
38
|
const pedestal = world.factory.createRigidBody(
|
|
39
|
-
{ shape: { shape: 'CYLINDER', radius: 0.5, height: 0.9 }, body: {
|
|
39
|
+
{ shape: { shape: 'CYLINDER', radius: 0.5, height: 0.9 }, body: { bodyType: 'static', mass: 0 } },
|
|
40
40
|
{ position: { x: 0, y: 0, z: 0.45 } },
|
|
41
41
|
);
|
|
42
42
|
pedestal.addToWorld({ physicsWorld: world } as any);
|
|
43
43
|
|
|
44
44
|
const propBody = world.factory.createRigidBody(
|
|
45
|
-
{ shape: { shape: 'BOX', dimensions: { x: 0.41, y: 0.23, z: 0.49 } }, body: {
|
|
45
|
+
{ shape: { shape: 'BOX', dimensions: { x: 0.41, y: 0.23, z: 0.49 } }, body: { bodyType: 'dynamic', mass: 3 } },
|
|
46
46
|
{ position: radioPosition },
|
|
47
47
|
);
|
|
48
48
|
propBody.addToWorld({ physicsWorld: world } as any);
|
|
@@ -21,7 +21,7 @@ const setup = async () => {
|
|
|
21
21
|
await world.init();
|
|
22
22
|
world.gravity = { x: 0, y: 0, z: 0 };
|
|
23
23
|
const floor = world.factory.createRigidBody(
|
|
24
|
-
{ shape: { shape: 'BOX', dimensions: { x: 100, y: 100, z: 1 } }, body: {
|
|
24
|
+
{ shape: { shape: 'BOX', dimensions: { x: 100, y: 100, z: 1 } }, body: { bodyType: 'static', mass: 0 } },
|
|
25
25
|
{ position: { x: 0, y: 0, z: -0.5 } },
|
|
26
26
|
);
|
|
27
27
|
floor.addToWorld({ physicsWorld: world } as any);
|
|
@@ -149,12 +149,12 @@ describe('CharacterController3dEntity + Rapier3dCharacterControllerComponent - s
|
|
|
149
149
|
await world.init();
|
|
150
150
|
world.gravity = { x: 0, y: 0, z: -9.82 };
|
|
151
151
|
const floor = world.factory.createRigidBody(
|
|
152
|
-
{ shape: { shape: 'BOX', dimensions: { x: 100, y: 100, z: 1 } }, body: {
|
|
152
|
+
{ shape: { shape: 'BOX', dimensions: { x: 100, y: 100, z: 1 } }, body: { bodyType: 'static', mass: 0 } },
|
|
153
153
|
{ position: { x: 0, y: 0, z: -0.5 } },
|
|
154
154
|
);
|
|
155
155
|
floor.addToWorld({ physicsWorld: world } as any);
|
|
156
156
|
const sphere = world.factory.createRigidBody(
|
|
157
|
-
{ shape: { shape: 'SPHERE', radius: 1 }, body: {
|
|
157
|
+
{ shape: { shape: 'SPHERE', radius: 1 }, body: { bodyType: 'static', mass: 0 } },
|
|
158
158
|
{ position: { x: 0, y: 0, z: 1 } },
|
|
159
159
|
);
|
|
160
160
|
sphere.addToWorld({ physicsWorld: world } as any);
|
|
@@ -32,7 +32,7 @@ describe('Rapier3dRigidBodyComponent collision events', () => {
|
|
|
32
32
|
|
|
33
33
|
const createFloor = () => {
|
|
34
34
|
const floor = factory.createRigidBody(
|
|
35
|
-
{ shape: { shape: 'BOX', dimensions: { x: 20, y: 20, z: 1 } }, body: {
|
|
35
|
+
{ shape: { shape: 'BOX', dimensions: { x: 20, y: 20, z: 1 } }, body: { bodyType: 'static' } },
|
|
36
36
|
{ position: { x: 0, y: 0, z: -0.5 } },
|
|
37
37
|
);
|
|
38
38
|
floor.addToWorld({ physicsWorld: world } as any);
|
|
@@ -43,7 +43,7 @@ describe('Rapier3dRigidBodyComponent collision events', () => {
|
|
|
43
43
|
// restitution 0 so the ball settles without bouncing, keeping the "no further onCollisionStart
|
|
44
44
|
// once resting" assertion below unambiguous.
|
|
45
45
|
const ball = factory.createRigidBody(
|
|
46
|
-
{ shape: { shape: 'SPHERE', radius: 1 }, body: {
|
|
46
|
+
{ shape: { shape: 'SPHERE', radius: 1 }, body: { bodyType: 'dynamic', mass: 1, restitution: 0 } },
|
|
47
47
|
{ position: { x: 0, y: 0, z } },
|
|
48
48
|
);
|
|
49
49
|
ball.addToWorld({ physicsWorld: world } as any);
|
|
@@ -41,7 +41,7 @@ describe(`Rapier3dTriggerComponent`, () => {
|
|
|
41
41
|
const ball = factory.createRigidBody(
|
|
42
42
|
{
|
|
43
43
|
shape: { shape: 'SPHERE', radius: 1 },
|
|
44
|
-
body: {
|
|
44
|
+
body: { bodyType: 'dynamic', mass: 1 },
|
|
45
45
|
},
|
|
46
46
|
{ position: { x: 0, y: 0, z: 12 } },
|
|
47
47
|
);
|
|
@@ -70,7 +70,7 @@ describe(`Rapier3dTriggerComponent`, () => {
|
|
|
70
70
|
const ball = factory.createRigidBody(
|
|
71
71
|
{
|
|
72
72
|
shape: { shape: 'SPHERE', radius: 1 },
|
|
73
|
-
body: {
|
|
73
|
+
body: { bodyType: 'dynamic', mass: 1 },
|
|
74
74
|
},
|
|
75
75
|
{ position: { x: 0, y: 0, z: 12 } },
|
|
76
76
|
);
|
|
@@ -92,7 +92,7 @@ describe(`Rapier3dTriggerComponent`, () => {
|
|
|
92
92
|
const ball = factory.createRigidBody(
|
|
93
93
|
{
|
|
94
94
|
shape: { shape: 'SPHERE', radius: 1 },
|
|
95
|
-
body: {
|
|
95
|
+
body: { bodyType: 'dynamic', mass: 1 },
|
|
96
96
|
},
|
|
97
97
|
{ position: { x: 0, y: 0, z: 0 } },
|
|
98
98
|
);
|
|
@@ -112,7 +112,7 @@ describe(`Rapier3dTriggerComponent`, () => {
|
|
|
112
112
|
const ball = factory.createRigidBody(
|
|
113
113
|
{
|
|
114
114
|
shape: { shape: 'SPHERE', radius: 1 },
|
|
115
|
-
body: {
|
|
115
|
+
body: { bodyType: 'dynamic', mass: 1 },
|
|
116
116
|
},
|
|
117
117
|
{ position: { x: 0, y: 0, z: 0 } },
|
|
118
118
|
);
|
|
@@ -133,7 +133,7 @@ describe(`Rapier3dTriggerComponent`, () => {
|
|
|
133
133
|
const ball = factory.createRigidBody(
|
|
134
134
|
{
|
|
135
135
|
shape: { shape: 'SPHERE', radius: 1 },
|
|
136
|
-
body: {
|
|
136
|
+
body: { bodyType: 'dynamic', mass: 1 },
|
|
137
137
|
},
|
|
138
138
|
{ position: { x: 0, y: 0, z: 0 } },
|
|
139
139
|
);
|
|
@@ -23,7 +23,7 @@ describe('Rapier3dWorldComponent', () => {
|
|
|
23
23
|
|
|
24
24
|
const ball = world.factory.createRigidBody({
|
|
25
25
|
shape: { shape: 'SPHERE', radius: 1 },
|
|
26
|
-
body: {
|
|
26
|
+
body: { bodyType: 'dynamic', mass: 5 },
|
|
27
27
|
}, { position: { x: -5, y: 0, z: 0 } });
|
|
28
28
|
ball.addToWorld({ physicsWorld: world } as any);
|
|
29
29
|
ball.linearVelocity = { x: 1, y: 0, z: 0 };
|
|
@@ -39,14 +39,14 @@ describe('Rapier3dWorldComponent', () => {
|
|
|
39
39
|
|
|
40
40
|
const ball0 = world.factory.createRigidBody({
|
|
41
41
|
shape: { shape: 'SPHERE', radius: 1 },
|
|
42
|
-
body: {
|
|
42
|
+
body: { bodyType: 'dynamic', mass: 5 },
|
|
43
43
|
}, { position: { x: -5, y: 0, z: 0 } });
|
|
44
44
|
ball0.addToWorld({ physicsWorld: world } as any);
|
|
45
45
|
ball0.linearVelocity = { x: 1, y: 0, z: 0 };
|
|
46
46
|
|
|
47
47
|
const ball1 = world.factory.createRigidBody({
|
|
48
48
|
shape: { shape: 'SPHERE', radius: 1 },
|
|
49
|
-
body: {
|
|
49
|
+
body: { bodyType: 'dynamic', mass: 5 },
|
|
50
50
|
}, { position: { x: 5, y: 0, z: 0 } });
|
|
51
51
|
ball1.addToWorld({ physicsWorld: world } as any);
|
|
52
52
|
ball1.linearVelocity = { x: -1, y: 0, z: 0 };
|
|
@@ -63,7 +63,7 @@ describe('Rapier3dWorldComponent', () => {
|
|
|
63
63
|
const cg0 = world.registerCollisionGroup();
|
|
64
64
|
const ball0 = world.factory.createRigidBody({
|
|
65
65
|
shape: { shape: 'SPHERE', radius: 1 },
|
|
66
|
-
body: {
|
|
66
|
+
body: { bodyType: 'dynamic', mass: 5 },
|
|
67
67
|
}, { position: { x: -5, y: 0, z: 0 } });
|
|
68
68
|
ball0.addToWorld({ physicsWorld: world } as any);
|
|
69
69
|
ball0.linearVelocity = { x: 1, y: 0, z: 0 };
|
|
@@ -72,7 +72,7 @@ describe('Rapier3dWorldComponent', () => {
|
|
|
72
72
|
const cg1 = world.registerCollisionGroup();
|
|
73
73
|
const ball1 = world.factory.createRigidBody({
|
|
74
74
|
shape: { shape: 'SPHERE', radius: 1 },
|
|
75
|
-
body: {
|
|
75
|
+
body: { bodyType: 'dynamic', mass: 5 },
|
|
76
76
|
}, { position: { x: 5, y: 0, z: 0 } });
|
|
77
77
|
ball1.addToWorld({ physicsWorld: world } as any);
|
|
78
78
|
ball1.linearVelocity = { x: -1, y: 0, z: 0 };
|
|
@@ -94,7 +94,7 @@ describe('Rapier3dWorldComponent', () => {
|
|
|
94
94
|
'transform/velocity write passing wakeUp=false was silently never simulated)',
|
|
95
95
|
() => {
|
|
96
96
|
const ball = world.factory.createRigidBody(
|
|
97
|
-
{ shape: { shape: 'SPHERE', radius: 1 }, body: {
|
|
97
|
+
{ shape: { shape: 'SPHERE', radius: 1 }, body: { bodyType: 'dynamic', mass: 5 } },
|
|
98
98
|
{ position: { x: 0, y: 0, z: 0 } },
|
|
99
99
|
);
|
|
100
100
|
ball.addToWorld({ physicsWorld: world } as any);
|
|
@@ -121,7 +121,7 @@ describe('Rapier3dWorldComponent', () => {
|
|
|
121
121
|
// Create a box far away from the ray
|
|
122
122
|
const box = world.factory.createRigidBody({
|
|
123
123
|
shape: { shape: 'BOX', dimensions: { x: 1, y: 1, z: 1 } },
|
|
124
|
-
body: {
|
|
124
|
+
body: { bodyType: 'static', mass: 0 },
|
|
125
125
|
}, { position: { x: 10, y: 10, z: 10 } });
|
|
126
126
|
box.addToWorld({ physicsWorld: world } as any);
|
|
127
127
|
|
|
@@ -144,7 +144,7 @@ describe('Rapier3dWorldComponent', () => {
|
|
|
144
144
|
// Create a box in the path of the ray
|
|
145
145
|
const box = world.factory.createRigidBody({
|
|
146
146
|
shape: { shape: 'BOX', dimensions: { x: 2, y: 2, z: 2 } },
|
|
147
|
-
body: {
|
|
147
|
+
body: { bodyType: 'static', mass: 0 },
|
|
148
148
|
}, { position: { x: 0, y: 0, z: -5 } });
|
|
149
149
|
box.addToWorld({ physicsWorld: world } as any);
|
|
150
150
|
|
|
@@ -179,7 +179,7 @@ describe('Rapier3dWorldComponent', () => {
|
|
|
179
179
|
const box1 = world.factory.createRigidBody({
|
|
180
180
|
shape: { shape: 'BOX', dimensions: { x: 2, y: 2, z: 2 } },
|
|
181
181
|
body: {
|
|
182
|
-
|
|
182
|
+
bodyType: 'static',
|
|
183
183
|
mass: 0,
|
|
184
184
|
ownCollisionGroups: [group1],
|
|
185
185
|
interactWithCollisionGroups: [group1, group2],
|
|
@@ -217,7 +217,7 @@ describe('Rapier3dWorldComponent', () => {
|
|
|
217
217
|
// Create a box at a known distance
|
|
218
218
|
const box = world.factory.createRigidBody({
|
|
219
219
|
shape: { shape: 'BOX', dimensions: { x: 2, y: 2, z: 2 } },
|
|
220
|
-
body: {
|
|
220
|
+
body: { bodyType: 'static', mass: 0 },
|
|
221
221
|
}, { position: { x: 0, y: 0, z: -5 } });
|
|
222
222
|
box.addToWorld({ physicsWorld: world } as any);
|
|
223
223
|
|
|
@@ -246,7 +246,7 @@ describe('Rapier3dWorldComponent', () => {
|
|
|
246
246
|
const box = world.factory.createRigidBody({
|
|
247
247
|
shape: { shape: 'BOX', dimensions: { x: 2, y: 2, z: 2 } },
|
|
248
248
|
body: {
|
|
249
|
-
|
|
249
|
+
bodyType: 'static',
|
|
250
250
|
mass: 0,
|
|
251
251
|
ownCollisionGroups: [group1],
|
|
252
252
|
interactWithCollisionGroups: [group1, group2],
|
|
@@ -272,13 +272,13 @@ describe('Rapier3dWorldComponent', () => {
|
|
|
272
272
|
// Create two boxes at different positions
|
|
273
273
|
const box1 = world.factory.createRigidBody({
|
|
274
274
|
shape: { shape: 'BOX', dimensions: { x: 1, y: 1, z: 1 } },
|
|
275
|
-
body: {
|
|
275
|
+
body: { bodyType: 'static', mass: 0 },
|
|
276
276
|
}, { position: { x: 0, y: 0, z: -3 } });
|
|
277
277
|
box1.addToWorld({ physicsWorld: world } as any);
|
|
278
278
|
|
|
279
279
|
const box2 = world.factory.createRigidBody({
|
|
280
280
|
shape: { shape: 'BOX', dimensions: { x: 1, y: 1, z: 1 } },
|
|
281
|
-
body: {
|
|
281
|
+
body: { bodyType: 'static', mass: 0 },
|
|
282
282
|
}, { position: { x: 0, y: 0, z: -7 } });
|
|
283
283
|
box2.addToWorld({ physicsWorld: world } as any);
|
|
284
284
|
|
|
@@ -300,7 +300,7 @@ describe('Rapier3dWorldComponent', () => {
|
|
|
300
300
|
// Create a box
|
|
301
301
|
const box = world.factory.createRigidBody({
|
|
302
302
|
shape: { shape: 'BOX', dimensions: { x: 4, y: 4, z: 4 } },
|
|
303
|
-
body: {
|
|
303
|
+
body: { bodyType: 'static', mass: 0 },
|
|
304
304
|
}, { position: { x: 0, y: 0, z: 0 } });
|
|
305
305
|
box.addToWorld({ physicsWorld: world } as any);
|
|
306
306
|
|
|
@@ -19,6 +19,26 @@ describe('Rapier3dFactory', () => {
|
|
|
19
19
|
world.dispose();
|
|
20
20
|
});
|
|
21
21
|
|
|
22
|
+
describe('createColliderDescr', () => {
|
|
23
|
+
it('creates a circular cylinder collider that can be added to the world', () => {
|
|
24
|
+
const body = factory.createRigidBody(
|
|
25
|
+
{ shape: { shape: 'CYLINDER', radius: 0.5, height: 1 }, body: { bodyType: 'static', mass: 0 } },
|
|
26
|
+
{ position: { x: 0, y: 0, z: 0 } },
|
|
27
|
+
);
|
|
28
|
+
body.addToWorld({ physicsWorld: world } as any);
|
|
29
|
+
world.simulate(16);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it('falls back to a convex-hull approximation for an elliptical cylinder', () => {
|
|
33
|
+
const body = factory.createRigidBody(
|
|
34
|
+
{ shape: { shape: 'CYLINDER', radiusX: 0.5, radiusY: 1, height: 1 }, body: { bodyType: 'static', mass: 0 } },
|
|
35
|
+
{ position: { x: 0, y: 0, z: 0 } },
|
|
36
|
+
);
|
|
37
|
+
body.addToWorld({ physicsWorld: world } as any);
|
|
38
|
+
world.simulate(16);
|
|
39
|
+
});
|
|
40
|
+
});
|
|
41
|
+
|
|
22
42
|
describe('createCharacterController', () => {
|
|
23
43
|
it('should produce a component usable without any extra setup', () => {
|
|
24
44
|
const character = factory.createCharacterController(
|
|
@@ -38,7 +58,7 @@ describe('Rapier3dFactory', () => {
|
|
|
38
58
|
|
|
39
59
|
// works: a downward move against a floor grounds it, fully synchronously
|
|
40
60
|
const floor = factory.createRigidBody(
|
|
41
|
-
{ shape: { shape: 'BOX', dimensions: { x: 20, y: 20, z: 1 } }, body: {
|
|
61
|
+
{ shape: { shape: 'BOX', dimensions: { x: 20, y: 20, z: 1 } }, body: { bodyType: 'static', mass: 0 } },
|
|
42
62
|
{ position: { x: 0, y: 0, z: -0.5 } },
|
|
43
63
|
);
|
|
44
64
|
floor.addToWorld({ physicsWorld: world } as any);
|