@react-three/rapier 0.1.2 → 0.3.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.
@@ -63,11 +63,11 @@ const scaleColliderArgs = (shape, args, scale) => {
63
63
  const scaleArray = [scale.x, scale.y, scale.z];
64
64
  return newArgs.map((arg, index) => scaleArray[index] * arg);
65
65
  };
66
- const createColliderFromOptions = (options, world, body, scale = {
66
+ const createColliderFromOptions = (options, world, rigidBodyHandle, scale = {
67
67
  x: 1,
68
68
  y: 1,
69
69
  z: 1
70
- }) => {
70
+ }, hasCollisionEvents = false) => {
71
71
  var _options$shape, _options$args, _options$restitution, _options$restitutionC, _options$friction, _options$frictionComb;
72
72
 
73
73
  const mass = (options === null || options === void 0 ? void 0 : options.mass) || 1;
@@ -85,7 +85,12 @@ const createColliderFromOptions = (options, world, body, scale = {
85
85
  y: ry,
86
86
  z: rz,
87
87
  w: 1
88
- }).setRestitution((_options$restitution = options === null || options === void 0 ? void 0 : options.restitution) !== null && _options$restitution !== void 0 ? _options$restitution : 0).setRestitutionCombineRule((_options$restitutionC = options === null || options === void 0 ? void 0 : options.restitutionCombineRule) !== null && _options$restitutionC !== void 0 ? _options$restitutionC : rapier3dCompat.CoefficientCombineRule.Average).setFriction((_options$friction = options === null || options === void 0 ? void 0 : options.friction) !== null && _options$friction !== void 0 ? _options$friction : 0.7).setFrictionCombineRule((_options$frictionComb = options === null || options === void 0 ? void 0 : options.frictionCombineRule) !== null && _options$frictionComb !== void 0 ? _options$frictionComb : rapier3dCompat.CoefficientCombineRule.Average); // If any of the mass properties are specified, add mass properties
88
+ }).setRestitution((_options$restitution = options === null || options === void 0 ? void 0 : options.restitution) !== null && _options$restitution !== void 0 ? _options$restitution : 0).setRestitutionCombineRule((_options$restitutionC = options === null || options === void 0 ? void 0 : options.restitutionCombineRule) !== null && _options$restitutionC !== void 0 ? _options$restitutionC : rapier3dCompat.CoefficientCombineRule.Average).setFriction((_options$friction = options === null || options === void 0 ? void 0 : options.friction) !== null && _options$friction !== void 0 ? _options$friction : 0.7).setFrictionCombineRule((_options$frictionComb = options === null || options === void 0 ? void 0 : options.frictionCombineRule) !== null && _options$frictionComb !== void 0 ? _options$frictionComb : rapier3dCompat.CoefficientCombineRule.Average);
89
+
90
+ if (hasCollisionEvents) {
91
+ colliderDesc = colliderDesc.setActiveEvents(rapier3dCompat.ActiveEvents.COLLISION_EVENTS);
92
+ } // If any of the mass properties are specified, add mass properties
93
+
89
94
 
90
95
  if (options !== null && options !== void 0 && options.mass || options !== null && options !== void 0 && options.centerOfMass || options !== null && options !== void 0 && options.principalAngularInertia) {
91
96
  colliderDesc.setDensity(0);
@@ -105,12 +110,13 @@ const createColliderFromOptions = (options, world, body, scale = {
105
110
  });
106
111
  }
107
112
 
108
- const collider = world.createCollider(colliderDesc, body.handle);
113
+ const collider = world.createCollider(colliderDesc, rigidBodyHandle);
109
114
  return collider;
110
115
  };
111
- const createCollidersFromChildren = (object, rigidBody, type, world) => {
116
+ const createCollidersFromChildren = (object, rigidBody, type, world, hasCollisionEvents = false) => {
112
117
  const colliders = [];
113
118
  let desc;
119
+ let offset = new three.Vector3();
114
120
  object.traverse(child => {
115
121
  if ("isMesh" in child) {
116
122
  const {
@@ -137,6 +143,7 @@ const createCollidersFromChildren = (object, rigidBody, type, world) => {
137
143
  boundingBox
138
144
  } = geometry;
139
145
  const size = boundingBox.getSize(new three.Vector3());
146
+ boundingBox.getCenter(offset);
140
147
  desc = rapier3dCompat.ColliderDesc.cuboid(size.x / 2 * scale.x, size.y / 2 * scale.y, size.z / 2 * scale.z);
141
148
  }
142
149
  break;
@@ -148,6 +155,7 @@ const createCollidersFromChildren = (object, rigidBody, type, world) => {
148
155
  boundingSphere
149
156
  } = geometry;
150
157
  const radius = boundingSphere.radius * scale.x;
158
+ offset.copy(boundingSphere.center);
151
159
  desc = rapier3dCompat.ColliderDesc.ball(radius);
152
160
  }
153
161
  break;
@@ -172,12 +180,17 @@ const createCollidersFromChildren = (object, rigidBody, type, world) => {
172
180
 
173
181
 
174
182
  const parentWorldScale = child.parent.getWorldScale(new three.Vector3());
175
- desc.setTranslation(x * parentWorldScale.x, y * parentWorldScale.y, z * parentWorldScale.z).setRotation({
183
+ desc.setTranslation((x + offset.x) * parentWorldScale.x, (y + offset.y) * parentWorldScale.y, (z + offset.z) * parentWorldScale.z).setRotation({
176
184
  x: rx,
177
185
  y: ry,
178
186
  z: rz,
179
187
  w: rw
180
188
  });
189
+
190
+ if (hasCollisionEvents) {
191
+ desc.setActiveEvents(rapier3dCompat.ActiveEvents.COLLISION_EVENTS);
192
+ }
193
+
181
194
  const collider = world.createCollider(desc, rigidBody.handle);
182
195
  colliders.push(collider);
183
196
  }
@@ -196,6 +209,99 @@ const scaleVertices = (vertices, scale) => {
196
209
  return scaledVerts;
197
210
  };
198
211
 
212
+ // TODO: Flesh this out
213
+ const createRigidBodyApi = ref => {
214
+ return {
215
+ raw: () => ref.current(),
216
+
217
+ get handle() {
218
+ return ref.current().handle;
219
+ },
220
+
221
+ applyImpulse({
222
+ x,
223
+ y,
224
+ z
225
+ }) {
226
+ ref.current().applyImpulse({
227
+ x,
228
+ y,
229
+ z
230
+ }, true);
231
+ },
232
+
233
+ applyTorqueImpulse({
234
+ x,
235
+ y,
236
+ z
237
+ }) {
238
+ ref.current().applyTorqueImpulse({
239
+ x,
240
+ y,
241
+ z
242
+ }, true);
243
+ },
244
+
245
+ translation() {
246
+ const {
247
+ x,
248
+ y,
249
+ z
250
+ } = ref.current().translation();
251
+ return new three.Vector3(x, y, z);
252
+ },
253
+
254
+ rotation() {
255
+ const {
256
+ x,
257
+ y,
258
+ z,
259
+ w
260
+ } = ref.current().rotation();
261
+ return new three.Quaternion(x, y, z, w);
262
+ }
263
+
264
+ };
265
+ }; // TODO: Flesh this out
266
+
267
+ const createColliderApi = ref => {
268
+ return {
269
+ raw: () => ref.current(),
270
+
271
+ get handle() {
272
+ return ref.current().handle;
273
+ }
274
+
275
+ };
276
+ };
277
+ const createWorldApi = ref => {
278
+ return {
279
+ raw: () => ref.current(),
280
+ getCollider: handle => ref.current().getCollider(handle),
281
+ getRigidBody: handle => ref.current().getRigidBody(handle),
282
+ createRigidBody: desc => ref.current().createRigidBody(desc),
283
+ createCollider: (desc, rigidBodyHandle) => ref.current().createCollider(desc, rigidBodyHandle),
284
+ removeRigidBody: rigidBody => ref.current().removeRigidBody(rigidBody),
285
+ removeCollider: collider => ref.current().removeCollider(collider, true),
286
+ createImpulseJoint: (params, rigidBodyA, rigidBodyB) => ref.current().createImpulseJoint(params, rigidBodyA, rigidBodyB),
287
+ removeImpulseJoint: joint => ref.current().removeImpulseJoint(joint, true),
288
+ forEachCollider: callback => ref.current().forEachCollider(callback)
289
+ };
290
+ }; // TODO: Broken currently, waiting for Rapier3D to fix
291
+
292
+ const createJointApi = ref => {
293
+ return {
294
+ raw: () => ref.current(),
295
+
296
+ get handle() {
297
+ return ref.current().handle;
298
+ },
299
+
300
+ configureMotorPosition: (targetPos, stiffness, damping) => ref.current().configureMotorPosition(targetPos, stiffness, damping),
301
+ configureMotorVelocity: (targetVel, damping) => ref.current().configureMotorVelocity(targetVel, damping)
302
+ };
303
+ };
304
+
199
305
  const RapierContext = /*#__PURE__*/React.createContext(undefined);
200
306
 
201
307
  const importRapier = async () => {
@@ -210,30 +316,143 @@ const Physics = ({
210
316
  children
211
317
  }) => {
212
318
  const rapier = useAsset.useAsset(importRapier);
213
- const stepFuncs = React.useRef([]);
214
- const world = React.useMemo(() => {
215
- if (!rapier.World) return null;
216
- let world = new rapier.World(vectorArrayToObject(_gravity));
217
- return world;
218
- }, [rapier]);
319
+ const worldRef = React.useRef();
320
+ const getWorldRef = React.useRef(() => {
321
+ if (!worldRef.current) {
322
+ const world = new rapier.World(vectorArrayToObject(_gravity));
323
+ worldRef.current = world;
324
+ }
325
+
326
+ return worldRef.current;
327
+ });
328
+ const [colliderMeshes] = React.useState(() => new Map());
329
+ const [rigidBodyMeshes] = React.useState(() => new Map());
330
+ const [rigidBodyEvents] = React.useState(() => new Map());
331
+ const [eventQueue] = React.useState(() => new rapier3dCompat.EventQueue(false)); // Init world
332
+
333
+ React.useLayoutEffect(() => {
334
+ const world = getWorldRef.current();
335
+ return () => {
336
+ if (world) {
337
+ world.free();
338
+ worldRef.current = undefined;
339
+ }
340
+ };
341
+ }, []);
219
342
  const time = React.useRef(performance.now());
220
343
  fiber.useFrame(context => {
221
- // Set timestep to current delta, to allow for variable frame rates
344
+ const world = worldRef.current;
345
+ if (!world) return; // Set timestep to current delta, to allow for variable frame rates
222
346
  // We cap the delta at 100, so that the physics simulation doesn't get wild
347
+
223
348
  const now = performance.now();
224
349
  const delta = Math.min(100, now - time.current);
225
350
  world.timestep = delta / 1000;
226
- world.step(); // Run all step funcs
351
+ world.step(eventQueue); // Update meshes
352
+
353
+ rigidBodyMeshes.forEach((mesh, handle) => {
354
+ const rigidBody = world.getRigidBody(handle);
355
+ const events = rigidBodyEvents.get(handle);
356
+
357
+ if (events !== null && events !== void 0 && events.onSleep || events !== null && events !== void 0 && events.onWake) {
358
+ if (rigidBody.isSleeping() && !mesh.userData.isSleeping) {
359
+ var _events$onSleep;
360
+
361
+ events === null || events === void 0 ? void 0 : (_events$onSleep = events.onSleep) === null || _events$onSleep === void 0 ? void 0 : _events$onSleep.call(events);
362
+ }
363
+
364
+ if (!rigidBody.isSleeping() && mesh.userData.isSleeping) {
365
+ var _events$onWake;
227
366
 
228
- stepFuncs.current.forEach(func => func());
367
+ events === null || events === void 0 ? void 0 : (_events$onWake = events.onWake) === null || _events$onWake === void 0 ? void 0 : _events$onWake.call(events);
368
+ }
369
+
370
+ mesh.userData.isSleeping = rigidBody.isSleeping();
371
+ }
372
+
373
+ if (!rigidBody || rigidBody.isSleeping() || rigidBody.isFixed() || !mesh.parent) {
374
+ return;
375
+ }
376
+
377
+ const {
378
+ x,
379
+ y,
380
+ z
381
+ } = rigidBody.translation();
382
+ const {
383
+ x: rx,
384
+ y: ry,
385
+ z: rz,
386
+ w: rw
387
+ } = rigidBody.rotation();
388
+ const scale = mesh.getWorldScale(new three.Vector3()); // haha matrixes I have no idea what I'm doing :)
389
+
390
+ const o = new three.Object3D();
391
+ o.position.set(x, y, z);
392
+ o.rotation.setFromQuaternion(new three.Quaternion(rx, ry, rz, rw));
393
+ o.scale.set(scale.x, scale.y, scale.z);
394
+ o.updateMatrix();
395
+ o.applyMatrix4(mesh.parent.matrixWorld.clone().invert());
396
+ o.updateMatrix();
397
+ mesh.position.setFromMatrixPosition(o.matrix);
398
+ mesh.rotation.setFromRotationMatrix(o.matrix);
399
+ }); // Collision events
400
+
401
+ eventQueue.drainCollisionEvents((handle1, handle2, started) => {
402
+ const collider1 = world.getCollider(handle1);
403
+ const collider2 = world.getCollider(handle2);
404
+ const rigidBodyHandle1 = collider1.parent();
405
+ const rigidBodyHandle2 = collider2.parent();
406
+
407
+ if (!collider1 || !collider2 || !rigidBodyHandle1 || !rigidBodyHandle2) {
408
+ return;
409
+ }
410
+
411
+ const rigidBody1 = world.getRigidBody(rigidBodyHandle1);
412
+ const rigidBody2 = world.getRigidBody(rigidBodyHandle2);
413
+ const events1 = rigidBodyEvents.get(rigidBodyHandle1);
414
+ const events2 = rigidBodyEvents.get(rigidBodyHandle2);
415
+
416
+ if (started) {
417
+ world.contactPair(handle1, handle2, (manifold, flipped) => {
418
+ var _events1$onCollisionE, _events2$onCollisionE;
419
+
420
+ events1 === null || events1 === void 0 ? void 0 : (_events1$onCollisionE = events1.onCollisionEnter) === null || _events1$onCollisionE === void 0 ? void 0 : _events1$onCollisionE.call(events1, {
421
+ target: rigidBody2,
422
+ manifold,
423
+ flipped
424
+ });
425
+ events2 === null || events2 === void 0 ? void 0 : (_events2$onCollisionE = events2.onCollisionEnter) === null || _events2$onCollisionE === void 0 ? void 0 : _events2$onCollisionE.call(events2, {
426
+ target: rigidBody1,
427
+ manifold,
428
+ flipped
429
+ });
430
+ });
431
+ } else {
432
+ var _events1$onCollisionE2, _events2$onCollisionE2;
433
+
434
+ events1 === null || events1 === void 0 ? void 0 : (_events1$onCollisionE2 = events1.onCollisionExit) === null || _events1$onCollisionE2 === void 0 ? void 0 : _events1$onCollisionE2.call(events1, {
435
+ target: rigidBody2
436
+ });
437
+ events2 === null || events2 === void 0 ? void 0 : (_events2$onCollisionE2 = events2.onCollisionExit) === null || _events2$onCollisionE2 === void 0 ? void 0 : _events2$onCollisionE2.call(events2, {
438
+ target: rigidBody1
439
+ });
440
+ }
441
+ });
229
442
  time.current = now;
230
443
  });
444
+ const api = React.useMemo(() => createWorldApi(getWorldRef), []);
231
445
  const context = React.useMemo(() => ({
232
- RAPIER: rapier,
233
- world,
234
- colliders: _colliders,
235
- stepFuncs: stepFuncs.current
236
- }), [rapier]);
446
+ rapier,
447
+ world: api,
448
+ physicsOptions: {
449
+ colliders: _colliders,
450
+ gravity: _gravity
451
+ },
452
+ colliderMeshes,
453
+ rigidBodyMeshes,
454
+ rigidBodyEvents
455
+ }), []);
237
456
  return /*#__PURE__*/React__default["default"].createElement(RapierContext.Provider, {
238
457
  value: context
239
458
  }, children);
@@ -282,70 +501,52 @@ function _objectSpread2(target) {
282
501
 
283
502
  const useRapier = () => {
284
503
  return React.useContext(RapierContext);
285
- }; // Private hook for updating the simulations on objects
286
-
287
- const useRapierStep = callback => {
288
- const {
289
- stepFuncs
290
- } = useRapier();
291
- React.useEffect(() => {
292
- stepFuncs.push(callback);
293
- return () => {
294
- const index = stepFuncs.indexOf(callback);
295
- stepFuncs.splice(index, 1);
296
- };
297
- }, [callback]);
298
504
  };
299
- const useCollider = (body, options = {}) => {
505
+ const useRigidBody = (options = {}) => {
300
506
  const {
301
- RAPIER,
302
- world
303
- } = useRapier();
304
- const collider = React.useMemo(() => {
305
- return createColliderFromOptions(options, world, body);
306
- }, []);
307
- React.useEffect(() => {
308
- return () => {
309
- world.removeCollider(collider, false);
310
- };
311
- }, []);
312
- return [collider];
313
- };
314
- const useRigidBody = options => {
315
- const {
316
- RAPIER,
507
+ rapier,
317
508
  world,
318
- colliders
509
+ rigidBodyMeshes,
510
+ physicsOptions,
511
+ rigidBodyEvents
319
512
  } = useRapier();
320
513
  const ref = React.useRef(); // Create rigidbody
321
514
 
322
- const rigidBody = React.useMemo(() => {
323
- var _options$linearVeloci, _options$angularVeloc, _options$gravityScale, _options$canSleep, _options$ccd;
324
-
325
- const [lvx, lvy, lvz] = (_options$linearVeloci = options === null || options === void 0 ? void 0 : options.linearVelocity) !== null && _options$linearVeloci !== void 0 ? _options$linearVeloci : [0, 0, 0];
326
- const [avx, avy, avz] = (_options$angularVeloc = options === null || options === void 0 ? void 0 : options.angularVelocity) !== null && _options$angularVeloc !== void 0 ? _options$angularVeloc : [0, 0, 0];
327
- const gravityScale = (_options$gravityScale = options === null || options === void 0 ? void 0 : options.gravityScale) !== null && _options$gravityScale !== void 0 ? _options$gravityScale : 1;
328
- const canSleep = (_options$canSleep = options === null || options === void 0 ? void 0 : options.canSleep) !== null && _options$canSleep !== void 0 ? _options$canSleep : true;
329
- const ccdEnabled = (_options$ccd = options === null || options === void 0 ? void 0 : options.ccd) !== null && _options$ccd !== void 0 ? _options$ccd : false;
330
- const type = rigidBodyTypeFromString((options === null || options === void 0 ? void 0 : options.type) || "dynamic");
331
- (options === null || options === void 0 ? void 0 : options.position) || [0, 0, 0];
332
- (options === null || options === void 0 ? void 0 : options.rotation) || [0, 0, 0];
333
- const rigidBodyDesc = new RAPIER.RigidBodyDesc(type).setLinvel(lvx, lvy, lvz).setAngvel({
334
- x: avx,
335
- y: avy,
336
- z: avz
337
- }).setGravityScale(gravityScale).setCanSleep(canSleep).setCcdEnabled(ccdEnabled).setTranslation(0, 0, 0);
338
- const body = world.createRigidBody(rigidBodyDesc);
339
- return body;
340
- }, []); // Setup
515
+ const rigidBodyRef = React.useRef();
516
+ const getRigidBodyRef = React.useRef(() => {
517
+ if (!rigidBodyRef.current) {
518
+ var _options$linearVeloci, _options$angularVeloc, _options$gravityScale, _options$canSleep, _options$ccd;
519
+
520
+ const type = rigidBodyTypeFromString((options === null || options === void 0 ? void 0 : options.type) || "dynamic");
521
+ const [lvx, lvy, lvz] = (_options$linearVeloci = options === null || options === void 0 ? void 0 : options.linearVelocity) !== null && _options$linearVeloci !== void 0 ? _options$linearVeloci : [0, 0, 0];
522
+ const [avx, avy, avz] = (_options$angularVeloc = options === null || options === void 0 ? void 0 : options.angularVelocity) !== null && _options$angularVeloc !== void 0 ? _options$angularVeloc : [0, 0, 0];
523
+ const gravityScale = (_options$gravityScale = options === null || options === void 0 ? void 0 : options.gravityScale) !== null && _options$gravityScale !== void 0 ? _options$gravityScale : 1;
524
+ const canSleep = (_options$canSleep = options === null || options === void 0 ? void 0 : options.canSleep) !== null && _options$canSleep !== void 0 ? _options$canSleep : true;
525
+ const ccdEnabled = (_options$ccd = options === null || options === void 0 ? void 0 : options.ccd) !== null && _options$ccd !== void 0 ? _options$ccd : false;
526
+ const desc = new rapier.RigidBodyDesc(type).setLinvel(lvx, lvy, lvz).setAngvel({
527
+ x: avx,
528
+ y: avy,
529
+ z: avz
530
+ }).setGravityScale(gravityScale).setCanSleep(canSleep).setCcdEnabled(ccdEnabled);
531
+ const rigidBody = world.createRigidBody(desc);
532
+ rigidBodyRef.current = rigidBody;
533
+ }
534
+
535
+ return rigidBodyRef.current;
536
+ }); // Setup
341
537
 
342
538
  React.useEffect(() => {
343
539
  var _ref$current$parent, _ref, _options$colliders;
344
540
 
541
+ const rigidBody = getRigidBodyRef.current();
542
+ rigidBodyRef.current = rigidBody;
543
+
345
544
  if (!ref.current) {
346
545
  ref.current = new three.Object3D();
347
- } // Get intitial world transforms
546
+ } // isSleeping used for onSleep and onWake events
547
+
348
548
 
549
+ ref.current.userData.isSleeping = false; // Get intitial world transforms
349
550
 
350
551
  const worldPosition = ref.current.getWorldPosition(new three.Vector3());
351
552
  const worldRotation = ref.current.getWorldQuaternion(new three.Quaternion());
@@ -373,43 +574,56 @@ const useRigidBody = options => {
373
574
  }, false);
374
575
  rigidBody.resetForces(false);
375
576
  rigidBody.resetTorques(false);
376
- const colliderSetting = (_ref = (_options$colliders = options === null || options === void 0 ? void 0 : options.colliders) !== null && _options$colliders !== void 0 ? _options$colliders : colliders) !== null && _ref !== void 0 ? _ref : false;
377
- const autoColliders = colliderSetting !== false ? createCollidersFromChildren(ref.current, rigidBody, colliderSetting, world) : [];
577
+ 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;
578
+ const hasCollisionEvents = !!(options.onCollisionEnter || options.onCollisionExit);
579
+ const autoColliders = colliderSetting !== false ? createCollidersFromChildren(ref.current, rigidBody, colliderSetting, world, hasCollisionEvents) : [];
580
+ rigidBody.wakeUp();
581
+ rigidBodyMeshes.set(rigidBody.handle, ref.current);
378
582
  return () => {
583
+ autoColliders.forEach(collider => world.removeCollider(collider));
379
584
  world.removeRigidBody(rigidBody);
380
- autoColliders.forEach(collider => world.removeCollider(collider, false));
585
+ rigidBodyRef.current = undefined;
586
+ rigidBodyMeshes.delete(rigidBody.handle);
381
587
  };
382
- }, []);
383
- useRapierStep(() => {
384
- if (rigidBody && ref.current) {
385
- const {
386
- x,
387
- y,
388
- z
389
- } = rigidBody.translation();
390
- const {
391
- x: rx,
392
- y: ry,
393
- z: rz,
394
- w: rw
395
- } = rigidBody.rotation();
396
- const scale = ref.current.getWorldScale(new three.Vector3());
397
-
398
- if (ref.current.parent) {
399
- // haha matrixes I have no idea what I'm doing :)
400
- const o = new three.Object3D();
401
- o.position.set(x, y, z);
402
- o.rotation.setFromQuaternion(new three.Quaternion(rx, ry, rz, rw));
403
- o.scale.set(scale.x, scale.y, scale.z);
404
- o.updateMatrix();
405
- o.applyMatrix4(ref.current.parent.matrixWorld.clone().invert());
406
- o.updateMatrix();
407
- ref.current.position.setFromMatrixPosition(o.matrix);
408
- ref.current.rotation.setFromRotationMatrix(o.matrix);
409
- }
588
+ }, []); // Events
589
+
590
+ React.useEffect(() => {
591
+ const rigidBody = getRigidBodyRef.current();
592
+ rigidBodyEvents.set(rigidBody.handle, {
593
+ onCollisionEnter: options === null || options === void 0 ? void 0 : options.onCollisionEnter,
594
+ onCollisionExit: options === null || options === void 0 ? void 0 : options.onCollisionExit,
595
+ onSleep: options === null || options === void 0 ? void 0 : options.onSleep,
596
+ onWake: options === null || options === void 0 ? void 0 : options.onWake
597
+ });
598
+ return () => {
599
+ rigidBodyEvents.delete(rigidBody.handle);
600
+ };
601
+ }, [options.onCollisionEnter, options.onCollisionExit]);
602
+ const api = React.useMemo(() => createRigidBodyApi(getRigidBodyRef), []);
603
+ return [ref, api];
604
+ };
605
+ const useCollider = (body, options = {}) => {
606
+ const {
607
+ world
608
+ } = useRapier();
609
+ const colliderRef = React.useRef();
610
+ const objectRef = React.useRef();
611
+ const getColliderRef = React.useRef(() => {
612
+ if (!colliderRef.current) {
613
+ colliderRef.current = createColliderFromOptions(options, world, body.handle);
410
614
  }
615
+
616
+ return colliderRef.current;
411
617
  });
412
- return [ref, rigidBody];
618
+ React.useEffect(() => {
619
+ const collider = getColliderRef.current();
620
+ return () => {
621
+ if (collider) world.removeCollider(collider);
622
+ colliderRef.current = undefined;
623
+ };
624
+ }, []);
625
+ const api = React.useMemo(() => createColliderApi(getColliderRef), []);
626
+ return [objectRef, api];
413
627
  };
414
628
  const useRigidBodyWithCollider = (rigidBodyOptions, colliderOptions) => {
415
629
  const {
@@ -422,9 +636,9 @@ const useRigidBodyWithCollider = (rigidBodyOptions, colliderOptions) => {
422
636
  }
423
637
 
424
638
  const scale = ref.current.getWorldScale(new three.Vector3());
425
- const collider = createColliderFromOptions(colliderOptions, world, rigidBody, scale);
639
+ const collider = createColliderFromOptions(colliderOptions, world, rigidBody.handle, scale);
426
640
  return () => {
427
- world.removeCollider(collider, false);
641
+ world.removeCollider(collider);
428
642
  };
429
643
  }, []);
430
644
  return [ref, rigidBody];
@@ -550,20 +764,42 @@ const useRoundConvexMesh = (rigidBodyOptions = {}, colliderOptions = {}) => {
550
764
 
551
765
  const useImpulseJoint = (body1, body2, params) => {
552
766
  const {
553
- world,
554
- RAPIER
767
+ world
555
768
  } = useRapier();
556
- React.useLayoutEffect(() => {
557
- let joint;
769
+ const jointRef = React.useRef();
770
+ const getJointRef = React.useRef(() => {
771
+ if (!jointRef.current) {
772
+ let rb1;
773
+ let rb2;
774
+
775
+ if ('handle' in body1 && 'handle' in body2) {
776
+ rb1 = world.getRigidBody(body1.handle);
777
+ rb2 = world.getRigidBody(body2.handle);
778
+ jointRef.current = world.createImpulseJoint(params, rb1, rb2);
779
+ }
558
780
 
559
- if (body1 && body2 && params) {
560
- joint = world.createImpulseJoint(params, body1.current, body2.current);
781
+ if ('current' in body1 && body1.current && 'current' in body2 && body2.current) {
782
+ rb1 = world.getRigidBody(body1.current.handle);
783
+ rb2 = world.getRigidBody(body2.current.handle);
784
+ const newJoint = world.createImpulseJoint(params, rb1, rb2);
785
+ jointRef.current = newJoint;
786
+ }
561
787
  }
562
788
 
789
+ return jointRef.current;
790
+ });
791
+ React.useEffect(() => {
792
+ const joint = getJointRef.current();
563
793
  return () => {
564
- if (joint) world.removeImpulseJoint(joint, true);
794
+ if (joint) {
795
+ console.log('remove joint', joint);
796
+ world.removeImpulseJoint(joint);
797
+ jointRef.current = undefined;
798
+ }
565
799
  };
566
- }, [body1, body2]);
800
+ }, []);
801
+ const api = React.useMemo(() => createJointApi(getJointRef), []);
802
+ return api;
567
803
  };
568
804
  /**
569
805
  *
@@ -574,9 +810,9 @@ const useImpulseJoint = (body1, body2, params) => {
574
810
 
575
811
  const useFixedJoint = (body1, body2, [body1Anchor, body1LocalFrame, body2Anchor, body2LocalFrame]) => {
576
812
  const {
577
- RAPIER
813
+ rapier
578
814
  } = useRapier();
579
- return useImpulseJoint(body1, body2, RAPIER.JointData.fixed(vectorArrayToObject(body1Anchor), _objectSpread2(_objectSpread2({}, vectorArrayToObject(body1LocalFrame)), {}, {
815
+ return useImpulseJoint(body1, body2, rapier.JointData.fixed(vectorArrayToObject(body1Anchor), _objectSpread2(_objectSpread2({}, vectorArrayToObject(body1LocalFrame)), {}, {
580
816
  w: 1
581
817
  }), vectorArrayToObject(body2Anchor), _objectSpread2(_objectSpread2({}, vectorArrayToObject(body2LocalFrame)), {}, {
582
818
  w: 1
@@ -591,9 +827,9 @@ const useFixedJoint = (body1, body2, [body1Anchor, body1LocalFrame, body2Anchor,
591
827
 
592
828
  const useSphericalJoint = (body1, body2, [body1Anchor, body2Anchor]) => {
593
829
  const {
594
- RAPIER
830
+ rapier
595
831
  } = useRapier();
596
- return useImpulseJoint(body1, body2, RAPIER.JointData.spherical(vectorArrayToObject(body1Anchor), vectorArrayToObject(body2Anchor)));
832
+ return useImpulseJoint(body1, body2, rapier.JointData.spherical(vectorArrayToObject(body1Anchor), vectorArrayToObject(body2Anchor)));
597
833
  };
598
834
  /**
599
835
  * The revolute joint prevents any relative movement between two rigid-bodies, except for relative
@@ -603,9 +839,9 @@ const useSphericalJoint = (body1, body2, [body1Anchor, body2Anchor]) => {
603
839
 
604
840
  const useRevoluteJoint = (body1, body2, [body1Anchor, body2Anchor, axis]) => {
605
841
  const {
606
- RAPIER
842
+ rapier
607
843
  } = useRapier();
608
- return useImpulseJoint(body1, body2, RAPIER.JointData.revolute(vectorArrayToObject(body1Anchor), vectorArrayToObject(body2Anchor), vectorArrayToObject(axis)));
844
+ return useImpulseJoint(body1, body2, rapier.JointData.revolute(vectorArrayToObject(body1Anchor), vectorArrayToObject(body2Anchor), vectorArrayToObject(axis)));
609
845
  };
610
846
  /**
611
847
  * The prismatic joint prevents any relative movement between two rigid-bodies, except for relative translations along one axis.
@@ -615,9 +851,9 @@ const useRevoluteJoint = (body1, body2, [body1Anchor, body2Anchor, axis]) => {
615
851
 
616
852
  const usePrismaticJoint = (body1, body2, [body1Anchor, body2Anchor, axis]) => {
617
853
  const {
618
- RAPIER
854
+ rapier
619
855
  } = useRapier();
620
- return useImpulseJoint(body1, body2, RAPIER.JointData.prismatic(vectorArrayToObject(body1Anchor), vectorArrayToObject(body2Anchor), vectorArrayToObject(axis)));
856
+ return useImpulseJoint(body1, body2, rapier.JointData.prismatic(vectorArrayToObject(body1Anchor), vectorArrayToObject(body2Anchor), vectorArrayToObject(axis)));
621
857
  };
622
858
 
623
859
  function _extends() {
@@ -672,10 +908,11 @@ function _objectWithoutProperties(source, excluded) {
672
908
  return target;
673
909
  }
674
910
 
675
- const _excluded = ["children"];
911
+ const _excluded = ["children"],
912
+ _excluded2 = ["children"];
676
913
  const RigidBodyContext = /*#__PURE__*/React.createContext(undefined);
677
914
 
678
- const useParentRigidBody = () => React.useContext(RigidBodyContext); // RigidBody
915
+ const useRigidBodyContext = () => React.useContext(RigidBodyContext); // RigidBody
679
916
 
680
917
 
681
918
  const RigidBody = /*#__PURE__*/React.forwardRef((_ref, ref) => {
@@ -684,28 +921,36 @@ const RigidBody = /*#__PURE__*/React.forwardRef((_ref, ref) => {
684
921
  } = _ref,
685
922
  props = _objectWithoutProperties(_ref, _excluded);
686
923
 
687
- const [group, rigidBody] = useRigidBody(props);
924
+ const [object, rigidBody] = useRigidBody(props);
688
925
  React.useImperativeHandle(ref, () => rigidBody);
689
926
  return /*#__PURE__*/React__default["default"].createElement(RigidBodyContext.Provider, {
690
- value: [group, rigidBody]
691
- }, /*#__PURE__*/React__default["default"].createElement("group", {
692
- ref: group
927
+ value: [object, rigidBody, !!(props.onCollisionEnter || props.onCollisionExit)]
928
+ }, /*#__PURE__*/React__default["default"].createElement("object3D", {
929
+ ref: object
693
930
  }, children));
694
931
  }); // Colliders
695
932
 
696
- const AnyCollider = props => {
933
+ const AnyCollider = _ref2 => {
934
+ let {
935
+ children
936
+ } = _ref2,
937
+ props = _objectWithoutProperties(_ref2, _excluded2);
938
+
697
939
  const {
698
940
  world
699
941
  } = useRapier();
700
- const [object, rigidBody] = useParentRigidBody();
942
+ const [, rigidBody, hasCollisionEvents] = useRigidBodyContext();
943
+ const ref = React.useRef(null);
701
944
  React.useEffect(() => {
702
- const scale = object.current.getWorldScale(new three.Vector3());
703
- const collider = createColliderFromOptions(props, world, rigidBody, scale);
945
+ const scale = ref.current.getWorldScale(new three.Vector3());
946
+ const collider = createColliderFromOptions(props, world, rigidBody.handle, scale, hasCollisionEvents);
704
947
  return () => {
705
- world.removeCollider(collider, false);
948
+ world.removeCollider(collider);
706
949
  };
707
950
  }, []);
708
- return null;
951
+ return /*#__PURE__*/React__default["default"].createElement("object3D", {
952
+ ref: ref
953
+ }, children);
709
954
  };
710
955
 
711
956
  const CuboidCollider = props => {
@@ -854,7 +1099,7 @@ const Debug = () => {
854
1099
 
855
1100
  fiber.useFrame(() => {
856
1101
  const newColliders = [];
857
- world.colliders.forEachCollider(collider => {
1102
+ world.forEachCollider(collider => {
858
1103
  newColliders.push(collider.handle);
859
1104
  });
860
1105
  setColliders(newColliders);