@react-three/rapier 0.1.1 → 0.3.0

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;
366
+
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
+ }
227
410
 
228
- stepFuncs.current.forEach(func => func());
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,53 @@ 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,
317
- world
507
+ rapier,
508
+ world,
509
+ rigidBodyMeshes,
510
+ physicsOptions,
511
+ rigidBodyEvents
318
512
  } = useRapier();
319
513
  const ref = React.useRef(); // Create rigidbody
320
514
 
321
- const rigidBody = React.useMemo(() => {
322
- var _options$linearVeloci, _options$angularVeloc, _options$gravityScale, _options$canSleep, _options$ccd;
323
-
324
- 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];
325
- 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];
326
- const gravityScale = (_options$gravityScale = options === null || options === void 0 ? void 0 : options.gravityScale) !== null && _options$gravityScale !== void 0 ? _options$gravityScale : 1;
327
- const canSleep = (_options$canSleep = options === null || options === void 0 ? void 0 : options.canSleep) !== null && _options$canSleep !== void 0 ? _options$canSleep : true;
328
- const ccdEnabled = (_options$ccd = options === null || options === void 0 ? void 0 : options.ccd) !== null && _options$ccd !== void 0 ? _options$ccd : false;
329
- const type = rigidBodyTypeFromString((options === null || options === void 0 ? void 0 : options.type) || "dynamic");
330
- (options === null || options === void 0 ? void 0 : options.position) || [0, 0, 0];
331
- (options === null || options === void 0 ? void 0 : options.rotation) || [0, 0, 0];
332
- const rigidBodyDesc = new RAPIER.RigidBodyDesc(type).setLinvel(lvx, lvy, lvz).setAngvel({
333
- x: avx,
334
- y: avy,
335
- z: avz
336
- }).setGravityScale(gravityScale).setCanSleep(canSleep).setCcdEnabled(ccdEnabled).setTranslation(0, 0, 0);
337
- const body = world.createRigidBody(rigidBodyDesc);
338
- return body;
339
- }, []); // 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
340
537
 
341
538
  React.useEffect(() => {
342
- var _ref$current$parent, _options$colliders;
539
+ var _ref$current$parent, _ref, _options$colliders;
540
+
541
+ const rigidBody = getRigidBodyRef.current();
542
+ rigidBodyRef.current = rigidBody;
343
543
 
344
544
  if (!ref.current) {
345
545
  ref.current = new three.Object3D();
346
- } // Get intitial world transforms
546
+ } // isSleeping used for onSleep and onWake events
347
547
 
348
548
 
549
+ ref.current.userData.isSleeping = false; // Get intitial world transforms
550
+
349
551
  const worldPosition = ref.current.getWorldPosition(new three.Vector3());
350
552
  const worldRotation = ref.current.getWorldQuaternion(new three.Quaternion());
351
553
  const scale = ((_ref$current$parent = ref.current.parent) === null || _ref$current$parent === void 0 ? void 0 : _ref$current$parent.getWorldScale(new three.Vector3())) || {
@@ -372,43 +574,56 @@ const useRigidBody = options => {
372
574
  }, false);
373
575
  rigidBody.resetForces(false);
374
576
  rigidBody.resetTorques(false);
375
- const colliderSetting = (_options$colliders = options === null || options === void 0 ? void 0 : options.colliders) !== null && _options$colliders !== void 0 ? _options$colliders : false;
376
- 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);
377
582
  return () => {
583
+ autoColliders.forEach(collider => world.removeCollider(collider));
378
584
  world.removeRigidBody(rigidBody);
379
- autoColliders.forEach(collider => world.removeCollider(collider, false));
585
+ rigidBodyRef.current = undefined;
586
+ rigidBodyMeshes.delete(rigidBody.handle);
380
587
  };
381
- }, []);
382
- useRapierStep(() => {
383
- if (rigidBody && ref.current) {
384
- const {
385
- x,
386
- y,
387
- z
388
- } = rigidBody.translation();
389
- const {
390
- x: rx,
391
- y: ry,
392
- z: rz,
393
- w: rw
394
- } = rigidBody.rotation();
395
- const scale = ref.current.getWorldScale(new three.Vector3());
396
-
397
- if (ref.current.parent) {
398
- // haha matrixes I have no idea what I'm doing :)
399
- const o = new three.Object3D();
400
- o.position.set(x, y, z);
401
- o.rotation.setFromQuaternion(new three.Quaternion(rx, ry, rz, rw));
402
- o.scale.set(scale.x, scale.y, scale.z);
403
- o.updateMatrix();
404
- o.applyMatrix4(ref.current.parent.matrixWorld.clone().invert());
405
- o.updateMatrix();
406
- ref.current.position.setFromMatrixPosition(o.matrix);
407
- ref.current.rotation.setFromRotationMatrix(o.matrix);
408
- }
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);
409
614
  }
615
+
616
+ return colliderRef.current;
410
617
  });
411
- 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];
412
627
  };
413
628
  const useRigidBodyWithCollider = (rigidBodyOptions, colliderOptions) => {
414
629
  const {
@@ -421,9 +636,9 @@ const useRigidBodyWithCollider = (rigidBodyOptions, colliderOptions) => {
421
636
  }
422
637
 
423
638
  const scale = ref.current.getWorldScale(new three.Vector3());
424
- const collider = createColliderFromOptions(colliderOptions, world, rigidBody, scale);
639
+ const collider = createColliderFromOptions(colliderOptions, world, rigidBody.handle, scale);
425
640
  return () => {
426
- world.removeCollider(collider, false);
641
+ world.removeCollider(collider);
427
642
  };
428
643
  }, []);
429
644
  return [ref, rigidBody];
@@ -549,20 +764,42 @@ const useRoundConvexMesh = (rigidBodyOptions = {}, colliderOptions = {}) => {
549
764
 
550
765
  const useImpulseJoint = (body1, body2, params) => {
551
766
  const {
552
- world,
553
- RAPIER
767
+ world
554
768
  } = useRapier();
555
- React.useLayoutEffect(() => {
556
- 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
+ }
557
780
 
558
- if (body1 && body2 && params) {
559
- 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
+ }
560
787
  }
561
788
 
789
+ return jointRef.current;
790
+ });
791
+ React.useEffect(() => {
792
+ const joint = getJointRef.current();
562
793
  return () => {
563
- if (joint) world.removeImpulseJoint(joint, true);
794
+ if (joint) {
795
+ console.log('remove joint', joint);
796
+ world.removeImpulseJoint(joint);
797
+ jointRef.current = undefined;
798
+ }
564
799
  };
565
- }, [body1, body2]);
800
+ }, []);
801
+ const api = React.useMemo(() => createJointApi(getJointRef), []);
802
+ return api;
566
803
  };
567
804
  /**
568
805
  *
@@ -573,9 +810,9 @@ const useImpulseJoint = (body1, body2, params) => {
573
810
 
574
811
  const useFixedJoint = (body1, body2, [body1Anchor, body1LocalFrame, body2Anchor, body2LocalFrame]) => {
575
812
  const {
576
- RAPIER
813
+ rapier
577
814
  } = useRapier();
578
- 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)), {}, {
579
816
  w: 1
580
817
  }), vectorArrayToObject(body2Anchor), _objectSpread2(_objectSpread2({}, vectorArrayToObject(body2LocalFrame)), {}, {
581
818
  w: 1
@@ -590,9 +827,9 @@ const useFixedJoint = (body1, body2, [body1Anchor, body1LocalFrame, body2Anchor,
590
827
 
591
828
  const useSphericalJoint = (body1, body2, [body1Anchor, body2Anchor]) => {
592
829
  const {
593
- RAPIER
830
+ rapier
594
831
  } = useRapier();
595
- return useImpulseJoint(body1, body2, RAPIER.JointData.spherical(vectorArrayToObject(body1Anchor), vectorArrayToObject(body2Anchor)));
832
+ return useImpulseJoint(body1, body2, rapier.JointData.spherical(vectorArrayToObject(body1Anchor), vectorArrayToObject(body2Anchor)));
596
833
  };
597
834
  /**
598
835
  * The revolute joint prevents any relative movement between two rigid-bodies, except for relative
@@ -602,9 +839,9 @@ const useSphericalJoint = (body1, body2, [body1Anchor, body2Anchor]) => {
602
839
 
603
840
  const useRevoluteJoint = (body1, body2, [body1Anchor, body2Anchor, axis]) => {
604
841
  const {
605
- RAPIER
842
+ rapier
606
843
  } = useRapier();
607
- 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)));
608
845
  };
609
846
  /**
610
847
  * The prismatic joint prevents any relative movement between two rigid-bodies, except for relative translations along one axis.
@@ -614,9 +851,9 @@ const useRevoluteJoint = (body1, body2, [body1Anchor, body2Anchor, axis]) => {
614
851
 
615
852
  const usePrismaticJoint = (body1, body2, [body1Anchor, body2Anchor, axis]) => {
616
853
  const {
617
- RAPIER
854
+ rapier
618
855
  } = useRapier();
619
- 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)));
620
857
  };
621
858
 
622
859
  function _extends() {
@@ -671,10 +908,11 @@ function _objectWithoutProperties(source, excluded) {
671
908
  return target;
672
909
  }
673
910
 
674
- const _excluded = ["children"];
911
+ const _excluded = ["children"],
912
+ _excluded2 = ["children"];
675
913
  const RigidBodyContext = /*#__PURE__*/React.createContext(undefined);
676
914
 
677
- const useParentRigidBody = () => React.useContext(RigidBodyContext); // RigidBody
915
+ const useRigidBodyContext = () => React.useContext(RigidBodyContext); // RigidBody
678
916
 
679
917
 
680
918
  const RigidBody = /*#__PURE__*/React.forwardRef((_ref, ref) => {
@@ -683,28 +921,36 @@ const RigidBody = /*#__PURE__*/React.forwardRef((_ref, ref) => {
683
921
  } = _ref,
684
922
  props = _objectWithoutProperties(_ref, _excluded);
685
923
 
686
- const [group, rigidBody] = useRigidBody(props);
924
+ const [object, rigidBody] = useRigidBody(props);
687
925
  React.useImperativeHandle(ref, () => rigidBody);
688
926
  return /*#__PURE__*/React__default["default"].createElement(RigidBodyContext.Provider, {
689
- value: [group, rigidBody]
690
- }, /*#__PURE__*/React__default["default"].createElement("group", {
691
- ref: group
927
+ value: [object, rigidBody, !!(props.onCollisionEnter || props.onCollisionExit)]
928
+ }, /*#__PURE__*/React__default["default"].createElement("object3D", {
929
+ ref: object
692
930
  }, children));
693
931
  }); // Colliders
694
932
 
695
- const AnyCollider = props => {
933
+ const AnyCollider = _ref2 => {
934
+ let {
935
+ children
936
+ } = _ref2,
937
+ props = _objectWithoutProperties(_ref2, _excluded2);
938
+
696
939
  const {
697
940
  world
698
941
  } = useRapier();
699
- const [object, rigidBody] = useParentRigidBody();
942
+ const [, rigidBody, hasCollisionEvents] = useRigidBodyContext();
943
+ const ref = React.useRef(null);
700
944
  React.useEffect(() => {
701
- const scale = object.current.getWorldScale(new three.Vector3());
702
- 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);
703
947
  return () => {
704
- world.removeCollider(collider, false);
948
+ world.removeCollider(collider);
705
949
  };
706
950
  }, []);
707
- return null;
951
+ return /*#__PURE__*/React__default["default"].createElement("object3D", {
952
+ ref: ref
953
+ }, children);
708
954
  };
709
955
 
710
956
  const CuboidCollider = props => {
@@ -853,7 +1099,7 @@ const Debug = () => {
853
1099
 
854
1100
  fiber.useFrame(() => {
855
1101
  const newColliders = [];
856
- world.colliders.forEachCollider(collider => {
1102
+ world.forEachCollider(collider => {
857
1103
  newColliders.push(collider.handle);
858
1104
  });
859
1105
  setColliders(newColliders);