@react-three/rapier 0.3.1 → 0.4.2

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