@react-three/rapier 0.3.0 → 0.4.1
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/CHANGELOG.md +22 -0
- package/dist/declarations/src/api.d.ts +114 -18
- package/dist/declarations/src/components.d.ts +1 -9
- package/dist/declarations/src/hooks.d.ts +21 -161
- package/dist/declarations/src/utils.d.ts +4 -4
- package/dist/react-three-rapier.cjs.dev.js +117 -89
- package/dist/react-three-rapier.cjs.prod.js +117 -89
- package/dist/react-three-rapier.esm.js +118 -90
- package/package.json +2 -2
- package/readme.md +176 -0
@@ -1,4 +1,4 @@
|
|
1
|
-
import React, { useRef, useState,
|
1
|
+
import React, { useRef, useState, useEffect, useMemo, createContext, useContext, forwardRef, useImperativeHandle, memo } from 'react';
|
2
2
|
import { useAsset } from 'use-asset';
|
3
3
|
import { useFrame } from '@react-three/fiber';
|
4
4
|
import { ColliderDesc, CoefficientCombineRule, ActiveEvents, EventQueue, ShapeType } from '@dimforge/rapier3d-compat';
|
@@ -38,7 +38,7 @@ const scaleColliderArgs = (shape, args, scale) => {
|
|
38
38
|
const scaleArray = [scale.x, scale.y, scale.z];
|
39
39
|
return newArgs.map((arg, index) => scaleArray[index] * arg);
|
40
40
|
};
|
41
|
-
const createColliderFromOptions = (options, world,
|
41
|
+
const createColliderFromOptions = (options, world, rigidBody, scale = {
|
42
42
|
x: 1,
|
43
43
|
y: 1,
|
44
44
|
z: 1
|
@@ -85,7 +85,7 @@ const createColliderFromOptions = (options, world, rigidBodyHandle, scale = {
|
|
85
85
|
});
|
86
86
|
}
|
87
87
|
|
88
|
-
const collider = world.createCollider(colliderDesc,
|
88
|
+
const collider = world.createCollider(colliderDesc, rigidBody);
|
89
89
|
return collider;
|
90
90
|
};
|
91
91
|
const createCollidersFromChildren = (object, rigidBody, type, world, hasCollisionEvents = false) => {
|
@@ -166,7 +166,7 @@ const createCollidersFromChildren = (object, rigidBody, type, world, hasCollisio
|
|
166
166
|
desc.setActiveEvents(ActiveEvents.COLLISION_EVENTS);
|
167
167
|
}
|
168
168
|
|
169
|
-
const collider = world.createCollider(desc, rigidBody
|
169
|
+
const collider = world.createCollider(desc, rigidBody);
|
170
170
|
colliders.push(collider);
|
171
171
|
}
|
172
172
|
});
|
@@ -184,7 +184,47 @@ const scaleVertices = (vertices, scale) => {
|
|
184
184
|
return scaledVerts;
|
185
185
|
};
|
186
186
|
|
187
|
-
|
187
|
+
function _defineProperty(obj, key, value) {
|
188
|
+
if (key in obj) {
|
189
|
+
Object.defineProperty(obj, key, {
|
190
|
+
value: value,
|
191
|
+
enumerable: true,
|
192
|
+
configurable: true,
|
193
|
+
writable: true
|
194
|
+
});
|
195
|
+
} else {
|
196
|
+
obj[key] = value;
|
197
|
+
}
|
198
|
+
|
199
|
+
return obj;
|
200
|
+
}
|
201
|
+
|
202
|
+
function ownKeys(object, enumerableOnly) {
|
203
|
+
var keys = Object.keys(object);
|
204
|
+
|
205
|
+
if (Object.getOwnPropertySymbols) {
|
206
|
+
var symbols = Object.getOwnPropertySymbols(object);
|
207
|
+
enumerableOnly && (symbols = symbols.filter(function (sym) {
|
208
|
+
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
|
209
|
+
})), keys.push.apply(keys, symbols);
|
210
|
+
}
|
211
|
+
|
212
|
+
return keys;
|
213
|
+
}
|
214
|
+
|
215
|
+
function _objectSpread2(target) {
|
216
|
+
for (var i = 1; i < arguments.length; i++) {
|
217
|
+
var source = null != arguments[i] ? arguments[i] : {};
|
218
|
+
i % 2 ? ownKeys(Object(source), !0).forEach(function (key) {
|
219
|
+
_defineProperty(target, key, source[key]);
|
220
|
+
}) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) {
|
221
|
+
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
|
222
|
+
});
|
223
|
+
}
|
224
|
+
|
225
|
+
return target;
|
226
|
+
}
|
227
|
+
|
188
228
|
const createRigidBodyApi = ref => {
|
189
229
|
return {
|
190
230
|
raw: () => ref.current(),
|
@@ -193,30 +233,21 @@ const createRigidBodyApi = ref => {
|
|
193
233
|
return ref.current().handle;
|
194
234
|
},
|
195
235
|
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
}) {
|
201
|
-
ref.current().applyImpulse({
|
202
|
-
x,
|
203
|
-
y,
|
204
|
-
z
|
205
|
-
}, true);
|
236
|
+
mass: () => ref.current().mass(),
|
237
|
+
|
238
|
+
applyImpulse(impulseVector) {
|
239
|
+
ref.current().applyImpulse(impulseVector, true);
|
206
240
|
},
|
207
241
|
|
208
|
-
applyTorqueImpulse({
|
209
|
-
|
210
|
-
y,
|
211
|
-
z
|
212
|
-
}) {
|
213
|
-
ref.current().applyTorqueImpulse({
|
214
|
-
x,
|
215
|
-
y,
|
216
|
-
z
|
217
|
-
}, true);
|
242
|
+
applyTorqueImpulse(torqueVector) {
|
243
|
+
ref.current().applyTorqueImpulse(torqueVector, true);
|
218
244
|
},
|
219
245
|
|
246
|
+
applyImpulseAtPoint: (impulseVector, impulsePoint) => ref.current().applyImpulseAtPoint(impulseVector, impulsePoint, true),
|
247
|
+
addForce: force => ref.current().addForce(force, true),
|
248
|
+
addForceAtPoint: (force, point) => ref.current().addForceAtPoint(force, point, true),
|
249
|
+
addTorque: torque => ref.current().addTorque(torque, true),
|
250
|
+
|
220
251
|
translation() {
|
221
252
|
const {
|
222
253
|
x,
|
@@ -226,6 +257,8 @@ const createRigidBodyApi = ref => {
|
|
226
257
|
return new Vector3(x, y, z);
|
227
258
|
},
|
228
259
|
|
260
|
+
setTranslation: translation => ref.current().setTranslation(translation, true),
|
261
|
+
|
229
262
|
rotation() {
|
230
263
|
const {
|
231
264
|
x,
|
@@ -234,8 +267,39 @@ const createRigidBodyApi = ref => {
|
|
234
267
|
w
|
235
268
|
} = ref.current().rotation();
|
236
269
|
return new Quaternion(x, y, z, w);
|
237
|
-
}
|
270
|
+
},
|
238
271
|
|
272
|
+
setRotation: rotation => ref.current().setRotation(_objectSpread2(_objectSpread2({}, rotation), {}, {
|
273
|
+
w: 1
|
274
|
+
}), true),
|
275
|
+
|
276
|
+
linvel() {
|
277
|
+
const {
|
278
|
+
x,
|
279
|
+
y,
|
280
|
+
z
|
281
|
+
} = ref.current().linvel();
|
282
|
+
return new Vector3(x, y, z);
|
283
|
+
},
|
284
|
+
|
285
|
+
setLinvel: velocity => ref.current().setLinvel(velocity, true),
|
286
|
+
|
287
|
+
angvel() {
|
288
|
+
const {
|
289
|
+
x,
|
290
|
+
y,
|
291
|
+
z
|
292
|
+
} = ref.current().angvel();
|
293
|
+
return new Vector3(x, y, z);
|
294
|
+
},
|
295
|
+
|
296
|
+
setAngvel: velocity => ref.current().setAngvel(velocity, true),
|
297
|
+
setNextKinematicRotation: rotation => ref.current().setNextKinematicRotation(_objectSpread2(_objectSpread2({}, rotation), {}, {
|
298
|
+
w: 1
|
299
|
+
})),
|
300
|
+
setNextKinematicTranslation: translation => ref.current().setNextKinematicTranslation(translation),
|
301
|
+
resetForces: () => ref.current().resetForces(true),
|
302
|
+
resetTorques: () => ref.current().resetTorques(true)
|
239
303
|
};
|
240
304
|
}; // TODO: Flesh this out
|
241
305
|
|
@@ -255,10 +319,10 @@ const createWorldApi = ref => {
|
|
255
319
|
getCollider: handle => ref.current().getCollider(handle),
|
256
320
|
getRigidBody: handle => ref.current().getRigidBody(handle),
|
257
321
|
createRigidBody: desc => ref.current().createRigidBody(desc),
|
258
|
-
createCollider: (desc,
|
322
|
+
createCollider: (desc, rigidBody) => ref.current().createCollider(desc, rigidBody),
|
259
323
|
removeRigidBody: rigidBody => ref.current().removeRigidBody(rigidBody),
|
260
324
|
removeCollider: collider => ref.current().removeCollider(collider, true),
|
261
|
-
createImpulseJoint: (params, rigidBodyA, rigidBodyB) => ref.current().createImpulseJoint(params, rigidBodyA, rigidBodyB),
|
325
|
+
createImpulseJoint: (params, rigidBodyA, rigidBodyB) => ref.current().createImpulseJoint(params, rigidBodyA, rigidBodyB, true),
|
262
326
|
removeImpulseJoint: joint => ref.current().removeImpulseJoint(joint, true),
|
263
327
|
forEachCollider: callback => ref.current().forEachCollider(callback)
|
264
328
|
};
|
@@ -305,7 +369,7 @@ const Physics = ({
|
|
305
369
|
const [rigidBodyEvents] = useState(() => new Map());
|
306
370
|
const [eventQueue] = useState(() => new EventQueue(false)); // Init world
|
307
371
|
|
308
|
-
|
372
|
+
useEffect(() => {
|
309
373
|
const world = getWorldRef.current();
|
310
374
|
return () => {
|
311
375
|
if (world) {
|
@@ -374,10 +438,12 @@ const Physics = ({
|
|
374
438
|
}); // Collision events
|
375
439
|
|
376
440
|
eventQueue.drainCollisionEvents((handle1, handle2, started) => {
|
441
|
+
var _collider1$parent, _collider2$parent;
|
442
|
+
|
377
443
|
const collider1 = world.getCollider(handle1);
|
378
444
|
const collider2 = world.getCollider(handle2);
|
379
|
-
const rigidBodyHandle1 = collider1.parent();
|
380
|
-
const rigidBodyHandle2 = collider2.parent();
|
445
|
+
const rigidBodyHandle1 = (_collider1$parent = collider1.parent()) === null || _collider1$parent === void 0 ? void 0 : _collider1$parent.handle;
|
446
|
+
const rigidBodyHandle2 = (_collider2$parent = collider2.parent()) === null || _collider2$parent === void 0 ? void 0 : _collider2$parent.handle;
|
381
447
|
|
382
448
|
if (!collider1 || !collider2 || !rigidBodyHandle1 || !rigidBodyHandle2) {
|
383
449
|
return;
|
@@ -389,7 +455,7 @@ const Physics = ({
|
|
389
455
|
const events2 = rigidBodyEvents.get(rigidBodyHandle2);
|
390
456
|
|
391
457
|
if (started) {
|
392
|
-
world.contactPair(
|
458
|
+
world.contactPair(collider1, collider2, (manifold, flipped) => {
|
393
459
|
var _events1$onCollisionE, _events2$onCollisionE;
|
394
460
|
|
395
461
|
events1 === null || events1 === void 0 ? void 0 : (_events1$onCollisionE = events1.onCollisionEnter) === null || _events1$onCollisionE === void 0 ? void 0 : _events1$onCollisionE.call(events1, {
|
@@ -433,47 +499,6 @@ const Physics = ({
|
|
433
499
|
}, children);
|
434
500
|
};
|
435
501
|
|
436
|
-
function _defineProperty(obj, key, value) {
|
437
|
-
if (key in obj) {
|
438
|
-
Object.defineProperty(obj, key, {
|
439
|
-
value: value,
|
440
|
-
enumerable: true,
|
441
|
-
configurable: true,
|
442
|
-
writable: true
|
443
|
-
});
|
444
|
-
} else {
|
445
|
-
obj[key] = value;
|
446
|
-
}
|
447
|
-
|
448
|
-
return obj;
|
449
|
-
}
|
450
|
-
|
451
|
-
function ownKeys(object, enumerableOnly) {
|
452
|
-
var keys = Object.keys(object);
|
453
|
-
|
454
|
-
if (Object.getOwnPropertySymbols) {
|
455
|
-
var symbols = Object.getOwnPropertySymbols(object);
|
456
|
-
enumerableOnly && (symbols = symbols.filter(function (sym) {
|
457
|
-
return Object.getOwnPropertyDescriptor(object, sym).enumerable;
|
458
|
-
})), keys.push.apply(keys, symbols);
|
459
|
-
}
|
460
|
-
|
461
|
-
return keys;
|
462
|
-
}
|
463
|
-
|
464
|
-
function _objectSpread2(target) {
|
465
|
-
for (var i = 1; i < arguments.length; i++) {
|
466
|
-
var source = null != arguments[i] ? arguments[i] : {};
|
467
|
-
i % 2 ? ownKeys(Object(source), !0).forEach(function (key) {
|
468
|
-
_defineProperty(target, key, source[key]);
|
469
|
-
}) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) {
|
470
|
-
Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
|
471
|
-
});
|
472
|
-
}
|
473
|
-
|
474
|
-
return target;
|
475
|
-
}
|
476
|
-
|
477
502
|
const useRapier = () => {
|
478
503
|
return useContext(RapierContext);
|
479
504
|
};
|
@@ -504,7 +529,7 @@ const useRigidBody = (options = {}) => {
|
|
504
529
|
z: avz
|
505
530
|
}).setGravityScale(gravityScale).setCanSleep(canSleep).setCcdEnabled(ccdEnabled);
|
506
531
|
const rigidBody = world.createRigidBody(desc);
|
507
|
-
rigidBodyRef.current = rigidBody;
|
532
|
+
rigidBodyRef.current = world.getRigidBody(rigidBody.handle);
|
508
533
|
}
|
509
534
|
|
510
535
|
return rigidBodyRef.current;
|
@@ -555,8 +580,8 @@ const useRigidBody = (options = {}) => {
|
|
555
580
|
rigidBody.wakeUp();
|
556
581
|
rigidBodyMeshes.set(rigidBody.handle, ref.current);
|
557
582
|
return () => {
|
558
|
-
autoColliders.forEach(collider => world.removeCollider(collider));
|
559
583
|
world.removeRigidBody(rigidBody);
|
584
|
+
autoColliders.forEach(collider => world.removeCollider(collider));
|
560
585
|
rigidBodyRef.current = undefined;
|
561
586
|
rigidBodyMeshes.delete(rigidBody.handle);
|
562
587
|
};
|
@@ -585,7 +610,7 @@ const useCollider = (body, options = {}) => {
|
|
585
610
|
const objectRef = useRef();
|
586
611
|
const getColliderRef = useRef(() => {
|
587
612
|
if (!colliderRef.current) {
|
588
|
-
colliderRef.current = createColliderFromOptions(options, world, body.handle);
|
613
|
+
colliderRef.current = createColliderFromOptions(options, world, world.getRigidBody(body.handle));
|
589
614
|
}
|
590
615
|
|
591
616
|
return colliderRef.current;
|
@@ -611,7 +636,7 @@ const useRigidBodyWithCollider = (rigidBodyOptions, colliderOptions) => {
|
|
611
636
|
}
|
612
637
|
|
613
638
|
const scale = ref.current.getWorldScale(new Vector3());
|
614
|
-
const collider = createColliderFromOptions(colliderOptions, world, rigidBody.handle, scale);
|
639
|
+
const collider = createColliderFromOptions(colliderOptions, world, world.getRigidBody(rigidBody.handle), scale);
|
615
640
|
return () => {
|
616
641
|
world.removeCollider(collider);
|
617
642
|
};
|
@@ -767,7 +792,6 @@ const useImpulseJoint = (body1, body2, params) => {
|
|
767
792
|
const joint = getJointRef.current();
|
768
793
|
return () => {
|
769
794
|
if (joint) {
|
770
|
-
console.log('remove joint', joint);
|
771
795
|
world.removeImpulseJoint(joint);
|
772
796
|
jointRef.current = undefined;
|
773
797
|
}
|
@@ -918,7 +942,7 @@ const AnyCollider = _ref2 => {
|
|
918
942
|
const ref = useRef(null);
|
919
943
|
useEffect(() => {
|
920
944
|
const scale = ref.current.getWorldScale(new Vector3());
|
921
|
-
const collider = createColliderFromOptions(props, world, rigidBody.
|
945
|
+
const collider = createColliderFromOptions(props, world, rigidBody.raw(), scale, hasCollisionEvents);
|
922
946
|
return () => {
|
923
947
|
world.removeCollider(collider);
|
924
948
|
};
|
@@ -975,20 +999,20 @@ const ConvexHullCollider = props => {
|
|
975
999
|
};
|
976
1000
|
|
977
1001
|
const geometryFromCollider = collider => {
|
978
|
-
switch (collider.
|
1002
|
+
switch (collider.shape.type) {
|
979
1003
|
case ShapeType.Cuboid:
|
980
1004
|
{
|
981
1005
|
const {
|
982
1006
|
x,
|
983
1007
|
y,
|
984
1008
|
z
|
985
|
-
} = collider.halfExtents
|
1009
|
+
} = collider.shape.halfExtents;
|
986
1010
|
return new BoxBufferGeometry(x * 2 + 0.01, y * 2 + 0.01, z * 2 + 0.01);
|
987
1011
|
}
|
988
1012
|
|
989
1013
|
case ShapeType.Ball:
|
990
1014
|
{
|
991
|
-
const r = collider.radius
|
1015
|
+
const r = collider.shape.radius;
|
992
1016
|
return new SphereBufferGeometry(r + +0.01, 8, 8);
|
993
1017
|
}
|
994
1018
|
|
@@ -996,10 +1020,12 @@ const geometryFromCollider = collider => {
|
|
996
1020
|
{
|
997
1021
|
var _g$index;
|
998
1022
|
|
999
|
-
const v = collider.vertices
|
1000
|
-
const i = collider.indices
|
1001
|
-
const g = new BufferGeometry();
|
1002
|
-
|
1023
|
+
const v = collider.shape.vertices;
|
1024
|
+
const i = collider.shape.indices;
|
1025
|
+
const g = new BufferGeometry(); // Vertices are not always a float3darray (???), so we need to convert them
|
1026
|
+
|
1027
|
+
const safeVerts = Float32Array.from(v);
|
1028
|
+
g.setAttribute("position", new BufferAttribute(safeVerts, 3));
|
1003
1029
|
(_g$index = g.index) === null || _g$index === void 0 ? void 0 : _g$index.set(i);
|
1004
1030
|
g.setDrawRange(0, g.attributes.position.array.length / 3 - 1);
|
1005
1031
|
return g;
|
@@ -1007,16 +1033,18 @@ const geometryFromCollider = collider => {
|
|
1007
1033
|
|
1008
1034
|
case ShapeType.ConvexPolyhedron:
|
1009
1035
|
{
|
1010
|
-
const cv = collider.vertices()
|
1036
|
+
const cv = collider.shape.vertices; // Vertices are not always a float3darray (???), so we need to convert them
|
1037
|
+
|
1038
|
+
const safeVerts = Float32Array.from(cv);
|
1011
1039
|
const cg = new BufferGeometry();
|
1012
|
-
cg.setAttribute("position", new BufferAttribute(
|
1040
|
+
cg.setAttribute("position", new BufferAttribute(safeVerts, 3));
|
1013
1041
|
return cg;
|
1014
1042
|
}
|
1015
1043
|
|
1016
1044
|
case ShapeType.Cylinder:
|
1017
1045
|
{
|
1018
|
-
const r = collider.radius
|
1019
|
-
const h = collider.halfHeight
|
1046
|
+
const r = collider.shape.radius;
|
1047
|
+
const h = collider.shape.halfHeight;
|
1020
1048
|
const g = new CylinderBufferGeometry(r, r, h);
|
1021
1049
|
return g;
|
1022
1050
|
}
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@react-three/rapier",
|
3
|
-
"version": "0.
|
3
|
+
"version": "0.4.1",
|
4
4
|
"source": "src/index.ts",
|
5
5
|
"main": "dist/react-three-rapier.cjs.js",
|
6
6
|
"module": "dist/react-three-rapier.esm.js",
|
@@ -23,7 +23,7 @@
|
|
23
23
|
"three": "^0.139.2"
|
24
24
|
},
|
25
25
|
"dependencies": {
|
26
|
-
"@dimforge/rapier3d-compat": "
|
26
|
+
"@dimforge/rapier3d-compat": "0.8.1",
|
27
27
|
"use-asset": "^1.0.4"
|
28
28
|
},
|
29
29
|
"repository": "https://github.com/pmndrs/react-three-rapier/tree/master/packages/react-three-rapier"
|
package/readme.md
ADDED
@@ -0,0 +1,176 @@
|
|
1
|
+
<h1 align="center">@react-three/rapier 🗡</h1>
|
2
|
+
|
3
|
+
<p align="center">⚠️ Under heavy development. All APIs are subject to change. ⚠️</p>
|
4
|
+
|
5
|
+
## Usage
|
6
|
+
|
7
|
+
```tsx
|
8
|
+
import { Box } from "@react-three/drei";
|
9
|
+
import { Canvas } from "@react-three/fiber";
|
10
|
+
import { Physics, RigidBody } from "@react-three/rapier";
|
11
|
+
|
12
|
+
const App = () => {
|
13
|
+
return (
|
14
|
+
<Canvas>
|
15
|
+
<Physics>
|
16
|
+
<RigidBody>
|
17
|
+
<Box />
|
18
|
+
</RigidBody>
|
19
|
+
</Physics>
|
20
|
+
</Canvas>
|
21
|
+
);
|
22
|
+
};
|
23
|
+
```
|
24
|
+
|
25
|
+
## Automatic colliders
|
26
|
+
|
27
|
+
RigidBodies generate automatic colliders by default for all meshes that it contains. You can control the default collider by setting the `colliders` prop on a `<RigidBody />`, or change it globally by setting `colliders` on `<Physics />`. Setting `colliders={false}` disables auto-generation.
|
28
|
+
|
29
|
+
Supported values:
|
30
|
+
|
31
|
+
- `"cuboid"`, creates a CuboidCollider based on the bounding box of the mesh
|
32
|
+
- `"ball"`, creates a SphereCollider based on the bounding sphere of the mesh
|
33
|
+
- `"trimesh"`, creates a TrimeshCollider based on the mesh's geometry -- note trimeshes are massless by default (https://rapier.rs/docs/user_guides/javascript/common_mistakes#rigid-body-isnt-affected-by-gravity)
|
34
|
+
- `"hull"`, creates a ConvexHullCollider based on the mesh's geometry
|
35
|
+
- `false`, disables auto-generation
|
36
|
+
|
37
|
+
Generate ConvexHull colliders for all meshes in a RigidBody by default:
|
38
|
+
|
39
|
+
```tsx
|
40
|
+
const Scene = () => (
|
41
|
+
<Physics colliders="hull">
|
42
|
+
<RigidBody>
|
43
|
+
<Box />
|
44
|
+
</RigidBody>
|
45
|
+
<RigidBody position={[0, 10, 0]}>
|
46
|
+
<Sphere />
|
47
|
+
</RigidBody>
|
48
|
+
</Physics>
|
49
|
+
);
|
50
|
+
```
|
51
|
+
|
52
|
+
Turn off automatic collider generation globally, but apply auto generation locally:
|
53
|
+
|
54
|
+
```tsx
|
55
|
+
const Scene = () => (
|
56
|
+
<Physics colliders={false}>
|
57
|
+
<RigidBody colliders="cuboid">
|
58
|
+
<Box />
|
59
|
+
</RigidBody>
|
60
|
+
|
61
|
+
<RigidBody position={[0, 10, 0]} colliders="ball">
|
62
|
+
<Sphere />
|
63
|
+
</RigidBody>
|
64
|
+
|
65
|
+
<RigidBody position={[0, 10, 0]}>
|
66
|
+
<Sphere />
|
67
|
+
<BallCollider args={0.5} />
|
68
|
+
<BallCollider args={0.5} position={[1, 0, 0]} />
|
69
|
+
</RigidBody>
|
70
|
+
</Physics>
|
71
|
+
);
|
72
|
+
```
|
73
|
+
|
74
|
+
Objects work inside other transformed objects as well. Simulation runs in world space and is transformed to the objects local space, so that things act as you'd expect.
|
75
|
+
|
76
|
+
```tsx
|
77
|
+
import { Box } from "@react-three/drei";
|
78
|
+
import { RigidBody, CuboidCollider } from "@react-three/rapier";
|
79
|
+
|
80
|
+
const Scene = () => {
|
81
|
+
return (
|
82
|
+
<group position={[2, 5, 0]} rotation={[0, 0.3, 2]}>
|
83
|
+
<RigidBody>
|
84
|
+
<Box />
|
85
|
+
<CuboidCollider args={[0.5, 0.5, 0.5]} />
|
86
|
+
</RigidBody>
|
87
|
+
</group>
|
88
|
+
);
|
89
|
+
};
|
90
|
+
```
|
91
|
+
|
92
|
+
## Debug
|
93
|
+
|
94
|
+
Use the Debug component to see live representations of all colliders in a scene.
|
95
|
+
|
96
|
+
> Note: Experimental. Not all shapes are supported. Unsupported shapes are always represented by cubes.
|
97
|
+
|
98
|
+
```tsx
|
99
|
+
import { Box, Sphere } from "@react-three/drei";
|
100
|
+
import { RigidBody, Debug } from "@react-three/rapier";
|
101
|
+
|
102
|
+
const Scene = () => {
|
103
|
+
return (
|
104
|
+
<Physics>
|
105
|
+
<Debug />
|
106
|
+
|
107
|
+
<RigidBody>
|
108
|
+
<Box />
|
109
|
+
</RigidBody>
|
110
|
+
<RigidBody>
|
111
|
+
<Sphere />
|
112
|
+
</RigidBody>
|
113
|
+
</Physics>
|
114
|
+
);
|
115
|
+
};
|
116
|
+
```
|
117
|
+
|
118
|
+
## Events
|
119
|
+
|
120
|
+
You can subscribe collision and state events on the RigidBody.
|
121
|
+
|
122
|
+
```tsx
|
123
|
+
const RigidBottle = () => {
|
124
|
+
const [isAsleep, setIsAsleep] = useState(false);
|
125
|
+
|
126
|
+
return (
|
127
|
+
<RigidBody
|
128
|
+
colliders="hull"
|
129
|
+
onSleep={() => setIsAsleep(true)}
|
130
|
+
onWake={() => setIsAsleep(false)}
|
131
|
+
onCollision={({manifold}) => {
|
132
|
+
console.log('Collision at world position ', manifold.solverContactPoint(0))
|
133
|
+
}}
|
134
|
+
>
|
135
|
+
<Sphere>
|
136
|
+
<meshPhysicalMaterial color={isAsleep ? 'white' : 'blue'}>
|
137
|
+
</Sphere>
|
138
|
+
</RigidBody>
|
139
|
+
)
|
140
|
+
}
|
141
|
+
```
|
142
|
+
|
143
|
+
## Hooks
|
144
|
+
|
145
|
+
You can also use hooks to generate rigid bodies and colliders, but it's not encouraged.
|
146
|
+
|
147
|
+
```tsx
|
148
|
+
import { Box } from "@react-three/drei";
|
149
|
+
import { useCuboid } from "@react-three/rapier";
|
150
|
+
|
151
|
+
const RigidBox = () => {
|
152
|
+
// Generates a RigidBody and attaches a BoxCollider to it, returns a ref
|
153
|
+
const [box, rigidBody, collider] = useCuboid(
|
154
|
+
{ position: [1, 1, 1] },
|
155
|
+
{ args: [0.5, 0.5, 0.5] }
|
156
|
+
);
|
157
|
+
|
158
|
+
return <Box ref={box} />;
|
159
|
+
};
|
160
|
+
```
|
161
|
+
|
162
|
+
## Roadmap?
|
163
|
+
|
164
|
+
In order, but also not necessarily:
|
165
|
+
|
166
|
+
- [x] Draft of all base shapes
|
167
|
+
- [x] Draft of all base joints
|
168
|
+
- [x] Nested objects retain world transforms
|
169
|
+
- [x] Nested objects retain correct collider scale
|
170
|
+
- [x] Automatic colliders based on rigidbody children
|
171
|
+
- [ ] Translation and rotational constraints
|
172
|
+
- [x] Collision events
|
173
|
+
- [ ] InstancedMesh support
|
174
|
+
- [ ] Docs
|
175
|
+
- [ ] CodeSandbox examples
|
176
|
+
- [ ] Helpers, for things like Vehicle, Rope, Player, etc
|