@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.
@@ -1,9 +1,9 @@
1
- import React, { useRef, useMemo, createContext, useContext, useEffect, useLayoutEffect, forwardRef, useImperativeHandle, useState, memo } from 'react';
1
+ import React, { useRef, useState, useLayoutEffect, useMemo, createContext, useContext, useEffect, forwardRef, useImperativeHandle, memo } from 'react';
2
2
  import { useAsset } from 'use-asset';
3
3
  import { useFrame } from '@react-three/fiber';
4
- import { ColliderDesc, CoefficientCombineRule, ShapeType } from '@dimforge/rapier3d-compat';
4
+ import { ColliderDesc, CoefficientCombineRule, ActiveEvents, EventQueue, ShapeType } from '@dimforge/rapier3d-compat';
5
5
  export { CoefficientCombineRule, Collider as RapierCollider, RigidBody as RapierRigidBody } from '@dimforge/rapier3d-compat';
6
- import { Quaternion, Vector3, Object3D, Euler, CylinderBufferGeometry, BufferGeometry, BufferAttribute, SphereBufferGeometry, BoxBufferGeometry } from 'three';
6
+ import { Vector3, Quaternion, Object3D, Euler, CylinderBufferGeometry, BufferGeometry, BufferAttribute, SphereBufferGeometry, BoxBufferGeometry } from 'three';
7
7
 
8
8
  const vectorArrayToObject = arr => {
9
9
  const [x, y, z] = arr;
@@ -38,11 +38,11 @@ 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, body, scale = {
41
+ const createColliderFromOptions = (options, world, rigidBodyHandle, scale = {
42
42
  x: 1,
43
43
  y: 1,
44
44
  z: 1
45
- }) => {
45
+ }, hasCollisionEvents = false) => {
46
46
  var _options$shape, _options$args, _options$restitution, _options$restitutionC, _options$friction, _options$frictionComb;
47
47
 
48
48
  const mass = (options === null || options === void 0 ? void 0 : options.mass) || 1;
@@ -60,7 +60,12 @@ const createColliderFromOptions = (options, world, body, scale = {
60
60
  y: ry,
61
61
  z: rz,
62
62
  w: 1
63
- }).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 : 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 : CoefficientCombineRule.Average); // If any of the mass properties are specified, add mass properties
63
+ }).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 : 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 : CoefficientCombineRule.Average);
64
+
65
+ if (hasCollisionEvents) {
66
+ colliderDesc = colliderDesc.setActiveEvents(ActiveEvents.COLLISION_EVENTS);
67
+ } // If any of the mass properties are specified, add mass properties
68
+
64
69
 
65
70
  if (options !== null && options !== void 0 && options.mass || options !== null && options !== void 0 && options.centerOfMass || options !== null && options !== void 0 && options.principalAngularInertia) {
66
71
  colliderDesc.setDensity(0);
@@ -80,12 +85,13 @@ const createColliderFromOptions = (options, world, body, scale = {
80
85
  });
81
86
  }
82
87
 
83
- const collider = world.createCollider(colliderDesc, body.handle);
88
+ const collider = world.createCollider(colliderDesc, rigidBodyHandle);
84
89
  return collider;
85
90
  };
86
- const createCollidersFromChildren = (object, rigidBody, type, world) => {
91
+ const createCollidersFromChildren = (object, rigidBody, type, world, hasCollisionEvents = false) => {
87
92
  const colliders = [];
88
93
  let desc;
94
+ let offset = new Vector3();
89
95
  object.traverse(child => {
90
96
  if ("isMesh" in child) {
91
97
  const {
@@ -112,6 +118,7 @@ const createCollidersFromChildren = (object, rigidBody, type, world) => {
112
118
  boundingBox
113
119
  } = geometry;
114
120
  const size = boundingBox.getSize(new Vector3());
121
+ boundingBox.getCenter(offset);
115
122
  desc = ColliderDesc.cuboid(size.x / 2 * scale.x, size.y / 2 * scale.y, size.z / 2 * scale.z);
116
123
  }
117
124
  break;
@@ -123,6 +130,7 @@ const createCollidersFromChildren = (object, rigidBody, type, world) => {
123
130
  boundingSphere
124
131
  } = geometry;
125
132
  const radius = boundingSphere.radius * scale.x;
133
+ offset.copy(boundingSphere.center);
126
134
  desc = ColliderDesc.ball(radius);
127
135
  }
128
136
  break;
@@ -147,12 +155,17 @@ const createCollidersFromChildren = (object, rigidBody, type, world) => {
147
155
 
148
156
 
149
157
  const parentWorldScale = child.parent.getWorldScale(new Vector3());
150
- desc.setTranslation(x * parentWorldScale.x, y * parentWorldScale.y, z * parentWorldScale.z).setRotation({
158
+ desc.setTranslation((x + offset.x) * parentWorldScale.x, (y + offset.y) * parentWorldScale.y, (z + offset.z) * parentWorldScale.z).setRotation({
151
159
  x: rx,
152
160
  y: ry,
153
161
  z: rz,
154
162
  w: rw
155
163
  });
164
+
165
+ if (hasCollisionEvents) {
166
+ desc.setActiveEvents(ActiveEvents.COLLISION_EVENTS);
167
+ }
168
+
156
169
  const collider = world.createCollider(desc, rigidBody.handle);
157
170
  colliders.push(collider);
158
171
  }
@@ -171,6 +184,99 @@ const scaleVertices = (vertices, scale) => {
171
184
  return scaledVerts;
172
185
  };
173
186
 
187
+ // TODO: Flesh this out
188
+ const createRigidBodyApi = ref => {
189
+ return {
190
+ raw: () => ref.current(),
191
+
192
+ get handle() {
193
+ return ref.current().handle;
194
+ },
195
+
196
+ applyImpulse({
197
+ x,
198
+ y,
199
+ z
200
+ }) {
201
+ ref.current().applyImpulse({
202
+ x,
203
+ y,
204
+ z
205
+ }, true);
206
+ },
207
+
208
+ applyTorqueImpulse({
209
+ x,
210
+ y,
211
+ z
212
+ }) {
213
+ ref.current().applyTorqueImpulse({
214
+ x,
215
+ y,
216
+ z
217
+ }, true);
218
+ },
219
+
220
+ translation() {
221
+ const {
222
+ x,
223
+ y,
224
+ z
225
+ } = ref.current().translation();
226
+ return new Vector3(x, y, z);
227
+ },
228
+
229
+ rotation() {
230
+ const {
231
+ x,
232
+ y,
233
+ z,
234
+ w
235
+ } = ref.current().rotation();
236
+ return new Quaternion(x, y, z, w);
237
+ }
238
+
239
+ };
240
+ }; // TODO: Flesh this out
241
+
242
+ const createColliderApi = ref => {
243
+ return {
244
+ raw: () => ref.current(),
245
+
246
+ get handle() {
247
+ return ref.current().handle;
248
+ }
249
+
250
+ };
251
+ };
252
+ const createWorldApi = ref => {
253
+ return {
254
+ raw: () => ref.current(),
255
+ getCollider: handle => ref.current().getCollider(handle),
256
+ getRigidBody: handle => ref.current().getRigidBody(handle),
257
+ createRigidBody: desc => ref.current().createRigidBody(desc),
258
+ createCollider: (desc, rigidBodyHandle) => ref.current().createCollider(desc, rigidBodyHandle),
259
+ removeRigidBody: rigidBody => ref.current().removeRigidBody(rigidBody),
260
+ removeCollider: collider => ref.current().removeCollider(collider, true),
261
+ createImpulseJoint: (params, rigidBodyA, rigidBodyB) => ref.current().createImpulseJoint(params, rigidBodyA, rigidBodyB),
262
+ removeImpulseJoint: joint => ref.current().removeImpulseJoint(joint, true),
263
+ forEachCollider: callback => ref.current().forEachCollider(callback)
264
+ };
265
+ }; // TODO: Broken currently, waiting for Rapier3D to fix
266
+
267
+ const createJointApi = ref => {
268
+ return {
269
+ raw: () => ref.current(),
270
+
271
+ get handle() {
272
+ return ref.current().handle;
273
+ },
274
+
275
+ configureMotorPosition: (targetPos, stiffness, damping) => ref.current().configureMotorPosition(targetPos, stiffness, damping),
276
+ configureMotorVelocity: (targetVel, damping) => ref.current().configureMotorVelocity(targetVel, damping)
277
+ };
278
+ };
279
+
174
280
  const RapierContext = /*#__PURE__*/createContext(undefined);
175
281
 
176
282
  const importRapier = async () => {
@@ -185,30 +291,143 @@ const Physics = ({
185
291
  children
186
292
  }) => {
187
293
  const rapier = useAsset(importRapier);
188
- const stepFuncs = useRef([]);
189
- const world = useMemo(() => {
190
- if (!rapier.World) return null;
191
- let world = new rapier.World(vectorArrayToObject(_gravity));
192
- return world;
193
- }, [rapier]);
294
+ const worldRef = useRef();
295
+ const getWorldRef = useRef(() => {
296
+ if (!worldRef.current) {
297
+ const world = new rapier.World(vectorArrayToObject(_gravity));
298
+ worldRef.current = world;
299
+ }
300
+
301
+ return worldRef.current;
302
+ });
303
+ const [colliderMeshes] = useState(() => new Map());
304
+ const [rigidBodyMeshes] = useState(() => new Map());
305
+ const [rigidBodyEvents] = useState(() => new Map());
306
+ const [eventQueue] = useState(() => new EventQueue(false)); // Init world
307
+
308
+ useLayoutEffect(() => {
309
+ const world = getWorldRef.current();
310
+ return () => {
311
+ if (world) {
312
+ world.free();
313
+ worldRef.current = undefined;
314
+ }
315
+ };
316
+ }, []);
194
317
  const time = useRef(performance.now());
195
318
  useFrame(context => {
196
- // Set timestep to current delta, to allow for variable frame rates
319
+ const world = worldRef.current;
320
+ if (!world) return; // Set timestep to current delta, to allow for variable frame rates
197
321
  // We cap the delta at 100, so that the physics simulation doesn't get wild
322
+
198
323
  const now = performance.now();
199
324
  const delta = Math.min(100, now - time.current);
200
325
  world.timestep = delta / 1000;
201
- world.step(); // Run all step funcs
326
+ world.step(eventQueue); // Update meshes
327
+
328
+ rigidBodyMeshes.forEach((mesh, handle) => {
329
+ const rigidBody = world.getRigidBody(handle);
330
+ const events = rigidBodyEvents.get(handle);
331
+
332
+ if (events !== null && events !== void 0 && events.onSleep || events !== null && events !== void 0 && events.onWake) {
333
+ if (rigidBody.isSleeping() && !mesh.userData.isSleeping) {
334
+ var _events$onSleep;
335
+
336
+ events === null || events === void 0 ? void 0 : (_events$onSleep = events.onSleep) === null || _events$onSleep === void 0 ? void 0 : _events$onSleep.call(events);
337
+ }
338
+
339
+ if (!rigidBody.isSleeping() && mesh.userData.isSleeping) {
340
+ var _events$onWake;
202
341
 
203
- stepFuncs.current.forEach(func => func());
342
+ events === null || events === void 0 ? void 0 : (_events$onWake = events.onWake) === null || _events$onWake === void 0 ? void 0 : _events$onWake.call(events);
343
+ }
344
+
345
+ mesh.userData.isSleeping = rigidBody.isSleeping();
346
+ }
347
+
348
+ if (!rigidBody || rigidBody.isSleeping() || rigidBody.isFixed() || !mesh.parent) {
349
+ return;
350
+ }
351
+
352
+ const {
353
+ x,
354
+ y,
355
+ z
356
+ } = rigidBody.translation();
357
+ const {
358
+ x: rx,
359
+ y: ry,
360
+ z: rz,
361
+ w: rw
362
+ } = rigidBody.rotation();
363
+ const scale = mesh.getWorldScale(new Vector3()); // haha matrixes I have no idea what I'm doing :)
364
+
365
+ const o = new Object3D();
366
+ o.position.set(x, y, z);
367
+ o.rotation.setFromQuaternion(new Quaternion(rx, ry, rz, rw));
368
+ o.scale.set(scale.x, scale.y, scale.z);
369
+ o.updateMatrix();
370
+ o.applyMatrix4(mesh.parent.matrixWorld.clone().invert());
371
+ o.updateMatrix();
372
+ mesh.position.setFromMatrixPosition(o.matrix);
373
+ mesh.rotation.setFromRotationMatrix(o.matrix);
374
+ }); // Collision events
375
+
376
+ eventQueue.drainCollisionEvents((handle1, handle2, started) => {
377
+ const collider1 = world.getCollider(handle1);
378
+ const collider2 = world.getCollider(handle2);
379
+ const rigidBodyHandle1 = collider1.parent();
380
+ const rigidBodyHandle2 = collider2.parent();
381
+
382
+ if (!collider1 || !collider2 || !rigidBodyHandle1 || !rigidBodyHandle2) {
383
+ return;
384
+ }
385
+
386
+ const rigidBody1 = world.getRigidBody(rigidBodyHandle1);
387
+ const rigidBody2 = world.getRigidBody(rigidBodyHandle2);
388
+ const events1 = rigidBodyEvents.get(rigidBodyHandle1);
389
+ const events2 = rigidBodyEvents.get(rigidBodyHandle2);
390
+
391
+ if (started) {
392
+ world.contactPair(handle1, handle2, (manifold, flipped) => {
393
+ var _events1$onCollisionE, _events2$onCollisionE;
394
+
395
+ events1 === null || events1 === void 0 ? void 0 : (_events1$onCollisionE = events1.onCollisionEnter) === null || _events1$onCollisionE === void 0 ? void 0 : _events1$onCollisionE.call(events1, {
396
+ target: rigidBody2,
397
+ manifold,
398
+ flipped
399
+ });
400
+ events2 === null || events2 === void 0 ? void 0 : (_events2$onCollisionE = events2.onCollisionEnter) === null || _events2$onCollisionE === void 0 ? void 0 : _events2$onCollisionE.call(events2, {
401
+ target: rigidBody1,
402
+ manifold,
403
+ flipped
404
+ });
405
+ });
406
+ } else {
407
+ var _events1$onCollisionE2, _events2$onCollisionE2;
408
+
409
+ events1 === null || events1 === void 0 ? void 0 : (_events1$onCollisionE2 = events1.onCollisionExit) === null || _events1$onCollisionE2 === void 0 ? void 0 : _events1$onCollisionE2.call(events1, {
410
+ target: rigidBody2
411
+ });
412
+ events2 === null || events2 === void 0 ? void 0 : (_events2$onCollisionE2 = events2.onCollisionExit) === null || _events2$onCollisionE2 === void 0 ? void 0 : _events2$onCollisionE2.call(events2, {
413
+ target: rigidBody1
414
+ });
415
+ }
416
+ });
204
417
  time.current = now;
205
418
  });
419
+ const api = useMemo(() => createWorldApi(getWorldRef), []);
206
420
  const context = useMemo(() => ({
207
- RAPIER: rapier,
208
- world,
209
- colliders: _colliders,
210
- stepFuncs: stepFuncs.current
211
- }), [rapier]);
421
+ rapier,
422
+ world: api,
423
+ physicsOptions: {
424
+ colliders: _colliders,
425
+ gravity: _gravity
426
+ },
427
+ colliderMeshes,
428
+ rigidBodyMeshes,
429
+ rigidBodyEvents
430
+ }), []);
212
431
  return /*#__PURE__*/React.createElement(RapierContext.Provider, {
213
432
  value: context
214
433
  }, children);
@@ -257,71 +476,53 @@ function _objectSpread2(target) {
257
476
 
258
477
  const useRapier = () => {
259
478
  return useContext(RapierContext);
260
- }; // Private hook for updating the simulations on objects
261
-
262
- const useRapierStep = callback => {
263
- const {
264
- stepFuncs
265
- } = useRapier();
266
- useEffect(() => {
267
- stepFuncs.push(callback);
268
- return () => {
269
- const index = stepFuncs.indexOf(callback);
270
- stepFuncs.splice(index, 1);
271
- };
272
- }, [callback]);
273
- };
274
- const useCollider = (body, options = {}) => {
275
- const {
276
- RAPIER,
277
- world
278
- } = useRapier();
279
- const collider = useMemo(() => {
280
- return createColliderFromOptions(options, world, body);
281
- }, []);
282
- useEffect(() => {
283
- return () => {
284
- world.removeCollider(collider, false);
285
- };
286
- }, []);
287
- return [collider];
288
479
  };
289
- const useRigidBody = options => {
480
+ const useRigidBody = (options = {}) => {
290
481
  const {
291
- RAPIER,
482
+ rapier,
292
483
  world,
293
- colliders
484
+ rigidBodyMeshes,
485
+ physicsOptions,
486
+ rigidBodyEvents
294
487
  } = useRapier();
295
488
  const ref = useRef(); // Create rigidbody
296
489
 
297
- const rigidBody = useMemo(() => {
298
- var _options$linearVeloci, _options$angularVeloc, _options$gravityScale, _options$canSleep, _options$ccd;
299
-
300
- 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];
301
- 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];
302
- const gravityScale = (_options$gravityScale = options === null || options === void 0 ? void 0 : options.gravityScale) !== null && _options$gravityScale !== void 0 ? _options$gravityScale : 1;
303
- const canSleep = (_options$canSleep = options === null || options === void 0 ? void 0 : options.canSleep) !== null && _options$canSleep !== void 0 ? _options$canSleep : true;
304
- const ccdEnabled = (_options$ccd = options === null || options === void 0 ? void 0 : options.ccd) !== null && _options$ccd !== void 0 ? _options$ccd : false;
305
- const type = rigidBodyTypeFromString((options === null || options === void 0 ? void 0 : options.type) || "dynamic");
306
- (options === null || options === void 0 ? void 0 : options.position) || [0, 0, 0];
307
- (options === null || options === void 0 ? void 0 : options.rotation) || [0, 0, 0];
308
- const rigidBodyDesc = new RAPIER.RigidBodyDesc(type).setLinvel(lvx, lvy, lvz).setAngvel({
309
- x: avx,
310
- y: avy,
311
- z: avz
312
- }).setGravityScale(gravityScale).setCanSleep(canSleep).setCcdEnabled(ccdEnabled).setTranslation(0, 0, 0);
313
- const body = world.createRigidBody(rigidBodyDesc);
314
- return body;
315
- }, []); // Setup
490
+ const rigidBodyRef = useRef();
491
+ const getRigidBodyRef = useRef(() => {
492
+ if (!rigidBodyRef.current) {
493
+ var _options$linearVeloci, _options$angularVeloc, _options$gravityScale, _options$canSleep, _options$ccd;
494
+
495
+ const type = rigidBodyTypeFromString((options === null || options === void 0 ? void 0 : options.type) || "dynamic");
496
+ 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];
497
+ 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];
498
+ const gravityScale = (_options$gravityScale = options === null || options === void 0 ? void 0 : options.gravityScale) !== null && _options$gravityScale !== void 0 ? _options$gravityScale : 1;
499
+ const canSleep = (_options$canSleep = options === null || options === void 0 ? void 0 : options.canSleep) !== null && _options$canSleep !== void 0 ? _options$canSleep : true;
500
+ const ccdEnabled = (_options$ccd = options === null || options === void 0 ? void 0 : options.ccd) !== null && _options$ccd !== void 0 ? _options$ccd : false;
501
+ const desc = new rapier.RigidBodyDesc(type).setLinvel(lvx, lvy, lvz).setAngvel({
502
+ x: avx,
503
+ y: avy,
504
+ z: avz
505
+ }).setGravityScale(gravityScale).setCanSleep(canSleep).setCcdEnabled(ccdEnabled);
506
+ const rigidBody = world.createRigidBody(desc);
507
+ rigidBodyRef.current = rigidBody;
508
+ }
509
+
510
+ return rigidBodyRef.current;
511
+ }); // Setup
316
512
 
317
513
  useEffect(() => {
318
514
  var _ref$current$parent, _ref, _options$colliders;
319
515
 
516
+ const rigidBody = getRigidBodyRef.current();
517
+ rigidBodyRef.current = rigidBody;
518
+
320
519
  if (!ref.current) {
321
520
  ref.current = new Object3D();
322
- } // Get intitial world transforms
521
+ } // isSleeping used for onSleep and onWake events
323
522
 
324
523
 
524
+ ref.current.userData.isSleeping = false; // Get intitial world transforms
525
+
325
526
  const worldPosition = ref.current.getWorldPosition(new Vector3());
326
527
  const worldRotation = ref.current.getWorldQuaternion(new Quaternion());
327
528
  const scale = ((_ref$current$parent = ref.current.parent) === null || _ref$current$parent === void 0 ? void 0 : _ref$current$parent.getWorldScale(new Vector3())) || {
@@ -348,43 +549,56 @@ const useRigidBody = options => {
348
549
  }, false);
349
550
  rigidBody.resetForces(false);
350
551
  rigidBody.resetTorques(false);
351
- 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;
352
- const autoColliders = colliderSetting !== false ? createCollidersFromChildren(ref.current, rigidBody, colliderSetting, world) : [];
552
+ 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();
556
+ rigidBodyMeshes.set(rigidBody.handle, ref.current);
353
557
  return () => {
558
+ autoColliders.forEach(collider => world.removeCollider(collider));
354
559
  world.removeRigidBody(rigidBody);
355
- autoColliders.forEach(collider => world.removeCollider(collider, false));
560
+ rigidBodyRef.current = undefined;
561
+ rigidBodyMeshes.delete(rigidBody.handle);
356
562
  };
357
- }, []);
358
- useRapierStep(() => {
359
- if (rigidBody && ref.current) {
360
- const {
361
- x,
362
- y,
363
- z
364
- } = rigidBody.translation();
365
- const {
366
- x: rx,
367
- y: ry,
368
- z: rz,
369
- w: rw
370
- } = rigidBody.rotation();
371
- const scale = ref.current.getWorldScale(new Vector3());
372
-
373
- if (ref.current.parent) {
374
- // haha matrixes I have no idea what I'm doing :)
375
- const o = new Object3D();
376
- o.position.set(x, y, z);
377
- o.rotation.setFromQuaternion(new Quaternion(rx, ry, rz, rw));
378
- o.scale.set(scale.x, scale.y, scale.z);
379
- o.updateMatrix();
380
- o.applyMatrix4(ref.current.parent.matrixWorld.clone().invert());
381
- o.updateMatrix();
382
- ref.current.position.setFromMatrixPosition(o.matrix);
383
- ref.current.rotation.setFromRotationMatrix(o.matrix);
384
- }
563
+ }, []); // Events
564
+
565
+ useEffect(() => {
566
+ const rigidBody = getRigidBodyRef.current();
567
+ rigidBodyEvents.set(rigidBody.handle, {
568
+ onCollisionEnter: options === null || options === void 0 ? void 0 : options.onCollisionEnter,
569
+ onCollisionExit: options === null || options === void 0 ? void 0 : options.onCollisionExit,
570
+ onSleep: options === null || options === void 0 ? void 0 : options.onSleep,
571
+ onWake: options === null || options === void 0 ? void 0 : options.onWake
572
+ });
573
+ return () => {
574
+ rigidBodyEvents.delete(rigidBody.handle);
575
+ };
576
+ }, [options.onCollisionEnter, options.onCollisionExit]);
577
+ const api = useMemo(() => createRigidBodyApi(getRigidBodyRef), []);
578
+ return [ref, api];
579
+ };
580
+ const useCollider = (body, options = {}) => {
581
+ const {
582
+ world
583
+ } = useRapier();
584
+ const colliderRef = useRef();
585
+ const objectRef = useRef();
586
+ const getColliderRef = useRef(() => {
587
+ if (!colliderRef.current) {
588
+ colliderRef.current = createColliderFromOptions(options, world, body.handle);
385
589
  }
590
+
591
+ return colliderRef.current;
386
592
  });
387
- return [ref, rigidBody];
593
+ useEffect(() => {
594
+ const collider = getColliderRef.current();
595
+ return () => {
596
+ if (collider) world.removeCollider(collider);
597
+ colliderRef.current = undefined;
598
+ };
599
+ }, []);
600
+ const api = useMemo(() => createColliderApi(getColliderRef), []);
601
+ return [objectRef, api];
388
602
  };
389
603
  const useRigidBodyWithCollider = (rigidBodyOptions, colliderOptions) => {
390
604
  const {
@@ -397,9 +611,9 @@ const useRigidBodyWithCollider = (rigidBodyOptions, colliderOptions) => {
397
611
  }
398
612
 
399
613
  const scale = ref.current.getWorldScale(new Vector3());
400
- const collider = createColliderFromOptions(colliderOptions, world, rigidBody, scale);
614
+ const collider = createColliderFromOptions(colliderOptions, world, rigidBody.handle, scale);
401
615
  return () => {
402
- world.removeCollider(collider, false);
616
+ world.removeCollider(collider);
403
617
  };
404
618
  }, []);
405
619
  return [ref, rigidBody];
@@ -525,20 +739,42 @@ const useRoundConvexMesh = (rigidBodyOptions = {}, colliderOptions = {}) => {
525
739
 
526
740
  const useImpulseJoint = (body1, body2, params) => {
527
741
  const {
528
- world,
529
- RAPIER
742
+ world
530
743
  } = useRapier();
531
- useLayoutEffect(() => {
532
- let joint;
744
+ const jointRef = useRef();
745
+ const getJointRef = useRef(() => {
746
+ if (!jointRef.current) {
747
+ let rb1;
748
+ let rb2;
749
+
750
+ if ('handle' in body1 && 'handle' in body2) {
751
+ rb1 = world.getRigidBody(body1.handle);
752
+ rb2 = world.getRigidBody(body2.handle);
753
+ jointRef.current = world.createImpulseJoint(params, rb1, rb2);
754
+ }
533
755
 
534
- if (body1 && body2 && params) {
535
- joint = world.createImpulseJoint(params, body1.current, body2.current);
756
+ if ('current' in body1 && body1.current && 'current' in body2 && body2.current) {
757
+ rb1 = world.getRigidBody(body1.current.handle);
758
+ rb2 = world.getRigidBody(body2.current.handle);
759
+ const newJoint = world.createImpulseJoint(params, rb1, rb2);
760
+ jointRef.current = newJoint;
761
+ }
536
762
  }
537
763
 
764
+ return jointRef.current;
765
+ });
766
+ useEffect(() => {
767
+ const joint = getJointRef.current();
538
768
  return () => {
539
- if (joint) world.removeImpulseJoint(joint, true);
769
+ if (joint) {
770
+ console.log('remove joint', joint);
771
+ world.removeImpulseJoint(joint);
772
+ jointRef.current = undefined;
773
+ }
540
774
  };
541
- }, [body1, body2]);
775
+ }, []);
776
+ const api = useMemo(() => createJointApi(getJointRef), []);
777
+ return api;
542
778
  };
543
779
  /**
544
780
  *
@@ -549,9 +785,9 @@ const useImpulseJoint = (body1, body2, params) => {
549
785
 
550
786
  const useFixedJoint = (body1, body2, [body1Anchor, body1LocalFrame, body2Anchor, body2LocalFrame]) => {
551
787
  const {
552
- RAPIER
788
+ rapier
553
789
  } = useRapier();
554
- return useImpulseJoint(body1, body2, RAPIER.JointData.fixed(vectorArrayToObject(body1Anchor), _objectSpread2(_objectSpread2({}, vectorArrayToObject(body1LocalFrame)), {}, {
790
+ return useImpulseJoint(body1, body2, rapier.JointData.fixed(vectorArrayToObject(body1Anchor), _objectSpread2(_objectSpread2({}, vectorArrayToObject(body1LocalFrame)), {}, {
555
791
  w: 1
556
792
  }), vectorArrayToObject(body2Anchor), _objectSpread2(_objectSpread2({}, vectorArrayToObject(body2LocalFrame)), {}, {
557
793
  w: 1
@@ -566,9 +802,9 @@ const useFixedJoint = (body1, body2, [body1Anchor, body1LocalFrame, body2Anchor,
566
802
 
567
803
  const useSphericalJoint = (body1, body2, [body1Anchor, body2Anchor]) => {
568
804
  const {
569
- RAPIER
805
+ rapier
570
806
  } = useRapier();
571
- return useImpulseJoint(body1, body2, RAPIER.JointData.spherical(vectorArrayToObject(body1Anchor), vectorArrayToObject(body2Anchor)));
807
+ return useImpulseJoint(body1, body2, rapier.JointData.spherical(vectorArrayToObject(body1Anchor), vectorArrayToObject(body2Anchor)));
572
808
  };
573
809
  /**
574
810
  * The revolute joint prevents any relative movement between two rigid-bodies, except for relative
@@ -578,9 +814,9 @@ const useSphericalJoint = (body1, body2, [body1Anchor, body2Anchor]) => {
578
814
 
579
815
  const useRevoluteJoint = (body1, body2, [body1Anchor, body2Anchor, axis]) => {
580
816
  const {
581
- RAPIER
817
+ rapier
582
818
  } = useRapier();
583
- return useImpulseJoint(body1, body2, RAPIER.JointData.revolute(vectorArrayToObject(body1Anchor), vectorArrayToObject(body2Anchor), vectorArrayToObject(axis)));
819
+ return useImpulseJoint(body1, body2, rapier.JointData.revolute(vectorArrayToObject(body1Anchor), vectorArrayToObject(body2Anchor), vectorArrayToObject(axis)));
584
820
  };
585
821
  /**
586
822
  * The prismatic joint prevents any relative movement between two rigid-bodies, except for relative translations along one axis.
@@ -590,9 +826,9 @@ const useRevoluteJoint = (body1, body2, [body1Anchor, body2Anchor, axis]) => {
590
826
 
591
827
  const usePrismaticJoint = (body1, body2, [body1Anchor, body2Anchor, axis]) => {
592
828
  const {
593
- RAPIER
829
+ rapier
594
830
  } = useRapier();
595
- return useImpulseJoint(body1, body2, RAPIER.JointData.prismatic(vectorArrayToObject(body1Anchor), vectorArrayToObject(body2Anchor), vectorArrayToObject(axis)));
831
+ return useImpulseJoint(body1, body2, rapier.JointData.prismatic(vectorArrayToObject(body1Anchor), vectorArrayToObject(body2Anchor), vectorArrayToObject(axis)));
596
832
  };
597
833
 
598
834
  function _extends() {
@@ -647,10 +883,11 @@ function _objectWithoutProperties(source, excluded) {
647
883
  return target;
648
884
  }
649
885
 
650
- const _excluded = ["children"];
886
+ const _excluded = ["children"],
887
+ _excluded2 = ["children"];
651
888
  const RigidBodyContext = /*#__PURE__*/createContext(undefined);
652
889
 
653
- const useParentRigidBody = () => useContext(RigidBodyContext); // RigidBody
890
+ const useRigidBodyContext = () => useContext(RigidBodyContext); // RigidBody
654
891
 
655
892
 
656
893
  const RigidBody = /*#__PURE__*/forwardRef((_ref, ref) => {
@@ -659,28 +896,36 @@ const RigidBody = /*#__PURE__*/forwardRef((_ref, ref) => {
659
896
  } = _ref,
660
897
  props = _objectWithoutProperties(_ref, _excluded);
661
898
 
662
- const [group, rigidBody] = useRigidBody(props);
899
+ const [object, rigidBody] = useRigidBody(props);
663
900
  useImperativeHandle(ref, () => rigidBody);
664
901
  return /*#__PURE__*/React.createElement(RigidBodyContext.Provider, {
665
- value: [group, rigidBody]
666
- }, /*#__PURE__*/React.createElement("group", {
667
- ref: group
902
+ value: [object, rigidBody, !!(props.onCollisionEnter || props.onCollisionExit)]
903
+ }, /*#__PURE__*/React.createElement("object3D", {
904
+ ref: object
668
905
  }, children));
669
906
  }); // Colliders
670
907
 
671
- const AnyCollider = props => {
908
+ const AnyCollider = _ref2 => {
909
+ let {
910
+ children
911
+ } = _ref2,
912
+ props = _objectWithoutProperties(_ref2, _excluded2);
913
+
672
914
  const {
673
915
  world
674
916
  } = useRapier();
675
- const [object, rigidBody] = useParentRigidBody();
917
+ const [, rigidBody, hasCollisionEvents] = useRigidBodyContext();
918
+ const ref = useRef(null);
676
919
  useEffect(() => {
677
- const scale = object.current.getWorldScale(new Vector3());
678
- const collider = createColliderFromOptions(props, world, rigidBody, scale);
920
+ const scale = ref.current.getWorldScale(new Vector3());
921
+ const collider = createColliderFromOptions(props, world, rigidBody.handle, scale, hasCollisionEvents);
679
922
  return () => {
680
- world.removeCollider(collider, false);
923
+ world.removeCollider(collider);
681
924
  };
682
925
  }, []);
683
- return null;
926
+ return /*#__PURE__*/React.createElement("object3D", {
927
+ ref: ref
928
+ }, children);
684
929
  };
685
930
 
686
931
  const CuboidCollider = props => {
@@ -829,7 +1074,7 @@ const Debug = () => {
829
1074
 
830
1075
  useFrame(() => {
831
1076
  const newColliders = [];
832
- world.colliders.forEachCollider(collider => {
1077
+ world.forEachCollider(collider => {
833
1078
  newColliders.push(collider.handle);
834
1079
  });
835
1080
  setColliders(newColliders);