@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.
@@ -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
+ }
202
338
 
203
- stepFuncs.current.forEach(func => func());
339
+ if (!rigidBody.isSleeping() && mesh.userData.isSleeping) {
340
+ var _events$onWake;
341
+
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,69 +476,52 @@ 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,
292
- world
482
+ rapier,
483
+ world,
484
+ rigidBodyMeshes,
485
+ physicsOptions,
486
+ rigidBodyEvents
293
487
  } = useRapier();
294
488
  const ref = useRef(); // Create rigidbody
295
489
 
296
- const rigidBody = useMemo(() => {
297
- var _options$linearVeloci, _options$angularVeloc, _options$gravityScale, _options$canSleep, _options$ccd;
298
-
299
- 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];
300
- 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];
301
- const gravityScale = (_options$gravityScale = options === null || options === void 0 ? void 0 : options.gravityScale) !== null && _options$gravityScale !== void 0 ? _options$gravityScale : 1;
302
- const canSleep = (_options$canSleep = options === null || options === void 0 ? void 0 : options.canSleep) !== null && _options$canSleep !== void 0 ? _options$canSleep : true;
303
- const ccdEnabled = (_options$ccd = options === null || options === void 0 ? void 0 : options.ccd) !== null && _options$ccd !== void 0 ? _options$ccd : false;
304
- const type = rigidBodyTypeFromString((options === null || options === void 0 ? void 0 : options.type) || "dynamic");
305
- (options === null || options === void 0 ? void 0 : options.position) || [0, 0, 0];
306
- (options === null || options === void 0 ? void 0 : options.rotation) || [0, 0, 0];
307
- const rigidBodyDesc = new RAPIER.RigidBodyDesc(type).setLinvel(lvx, lvy, lvz).setAngvel({
308
- x: avx,
309
- y: avy,
310
- z: avz
311
- }).setGravityScale(gravityScale).setCanSleep(canSleep).setCcdEnabled(ccdEnabled).setTranslation(0, 0, 0);
312
- const body = world.createRigidBody(rigidBodyDesc);
313
- return body;
314
- }, []); // 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
315
512
 
316
513
  useEffect(() => {
317
- var _ref$current$parent, _options$colliders;
514
+ var _ref$current$parent, _ref, _options$colliders;
515
+
516
+ const rigidBody = getRigidBodyRef.current();
517
+ rigidBodyRef.current = rigidBody;
318
518
 
319
519
  if (!ref.current) {
320
520
  ref.current = new Object3D();
321
- } // Get intitial world transforms
521
+ } // isSleeping used for onSleep and onWake events
522
+
322
523
 
524
+ ref.current.userData.isSleeping = false; // Get intitial world transforms
323
525
 
324
526
  const worldPosition = ref.current.getWorldPosition(new Vector3());
325
527
  const worldRotation = ref.current.getWorldQuaternion(new Quaternion());
@@ -347,43 +549,56 @@ const useRigidBody = options => {
347
549
  }, false);
348
550
  rigidBody.resetForces(false);
349
551
  rigidBody.resetTorques(false);
350
- const colliderSetting = (_options$colliders = options === null || options === void 0 ? void 0 : options.colliders) !== null && _options$colliders !== void 0 ? _options$colliders : false;
351
- 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);
352
557
  return () => {
558
+ autoColliders.forEach(collider => world.removeCollider(collider));
353
559
  world.removeRigidBody(rigidBody);
354
- autoColliders.forEach(collider => world.removeCollider(collider, false));
560
+ rigidBodyRef.current = undefined;
561
+ rigidBodyMeshes.delete(rigidBody.handle);
355
562
  };
356
- }, []);
357
- useRapierStep(() => {
358
- if (rigidBody && ref.current) {
359
- const {
360
- x,
361
- y,
362
- z
363
- } = rigidBody.translation();
364
- const {
365
- x: rx,
366
- y: ry,
367
- z: rz,
368
- w: rw
369
- } = rigidBody.rotation();
370
- const scale = ref.current.getWorldScale(new Vector3());
371
-
372
- if (ref.current.parent) {
373
- // haha matrixes I have no idea what I'm doing :)
374
- const o = new Object3D();
375
- o.position.set(x, y, z);
376
- o.rotation.setFromQuaternion(new Quaternion(rx, ry, rz, rw));
377
- o.scale.set(scale.x, scale.y, scale.z);
378
- o.updateMatrix();
379
- o.applyMatrix4(ref.current.parent.matrixWorld.clone().invert());
380
- o.updateMatrix();
381
- ref.current.position.setFromMatrixPosition(o.matrix);
382
- ref.current.rotation.setFromRotationMatrix(o.matrix);
383
- }
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);
384
589
  }
590
+
591
+ return colliderRef.current;
385
592
  });
386
- 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];
387
602
  };
388
603
  const useRigidBodyWithCollider = (rigidBodyOptions, colliderOptions) => {
389
604
  const {
@@ -396,9 +611,9 @@ const useRigidBodyWithCollider = (rigidBodyOptions, colliderOptions) => {
396
611
  }
397
612
 
398
613
  const scale = ref.current.getWorldScale(new Vector3());
399
- const collider = createColliderFromOptions(colliderOptions, world, rigidBody, scale);
614
+ const collider = createColliderFromOptions(colliderOptions, world, rigidBody.handle, scale);
400
615
  return () => {
401
- world.removeCollider(collider, false);
616
+ world.removeCollider(collider);
402
617
  };
403
618
  }, []);
404
619
  return [ref, rigidBody];
@@ -524,20 +739,42 @@ const useRoundConvexMesh = (rigidBodyOptions = {}, colliderOptions = {}) => {
524
739
 
525
740
  const useImpulseJoint = (body1, body2, params) => {
526
741
  const {
527
- world,
528
- RAPIER
742
+ world
529
743
  } = useRapier();
530
- useLayoutEffect(() => {
531
- 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
+ }
532
755
 
533
- if (body1 && body2 && params) {
534
- 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
+ }
535
762
  }
536
763
 
764
+ return jointRef.current;
765
+ });
766
+ useEffect(() => {
767
+ const joint = getJointRef.current();
537
768
  return () => {
538
- if (joint) world.removeImpulseJoint(joint, true);
769
+ if (joint) {
770
+ console.log('remove joint', joint);
771
+ world.removeImpulseJoint(joint);
772
+ jointRef.current = undefined;
773
+ }
539
774
  };
540
- }, [body1, body2]);
775
+ }, []);
776
+ const api = useMemo(() => createJointApi(getJointRef), []);
777
+ return api;
541
778
  };
542
779
  /**
543
780
  *
@@ -548,9 +785,9 @@ const useImpulseJoint = (body1, body2, params) => {
548
785
 
549
786
  const useFixedJoint = (body1, body2, [body1Anchor, body1LocalFrame, body2Anchor, body2LocalFrame]) => {
550
787
  const {
551
- RAPIER
788
+ rapier
552
789
  } = useRapier();
553
- 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)), {}, {
554
791
  w: 1
555
792
  }), vectorArrayToObject(body2Anchor), _objectSpread2(_objectSpread2({}, vectorArrayToObject(body2LocalFrame)), {}, {
556
793
  w: 1
@@ -565,9 +802,9 @@ const useFixedJoint = (body1, body2, [body1Anchor, body1LocalFrame, body2Anchor,
565
802
 
566
803
  const useSphericalJoint = (body1, body2, [body1Anchor, body2Anchor]) => {
567
804
  const {
568
- RAPIER
805
+ rapier
569
806
  } = useRapier();
570
- return useImpulseJoint(body1, body2, RAPIER.JointData.spherical(vectorArrayToObject(body1Anchor), vectorArrayToObject(body2Anchor)));
807
+ return useImpulseJoint(body1, body2, rapier.JointData.spherical(vectorArrayToObject(body1Anchor), vectorArrayToObject(body2Anchor)));
571
808
  };
572
809
  /**
573
810
  * The revolute joint prevents any relative movement between two rigid-bodies, except for relative
@@ -577,9 +814,9 @@ const useSphericalJoint = (body1, body2, [body1Anchor, body2Anchor]) => {
577
814
 
578
815
  const useRevoluteJoint = (body1, body2, [body1Anchor, body2Anchor, axis]) => {
579
816
  const {
580
- RAPIER
817
+ rapier
581
818
  } = useRapier();
582
- 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)));
583
820
  };
584
821
  /**
585
822
  * The prismatic joint prevents any relative movement between two rigid-bodies, except for relative translations along one axis.
@@ -589,9 +826,9 @@ const useRevoluteJoint = (body1, body2, [body1Anchor, body2Anchor, axis]) => {
589
826
 
590
827
  const usePrismaticJoint = (body1, body2, [body1Anchor, body2Anchor, axis]) => {
591
828
  const {
592
- RAPIER
829
+ rapier
593
830
  } = useRapier();
594
- 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)));
595
832
  };
596
833
 
597
834
  function _extends() {
@@ -646,10 +883,11 @@ function _objectWithoutProperties(source, excluded) {
646
883
  return target;
647
884
  }
648
885
 
649
- const _excluded = ["children"];
886
+ const _excluded = ["children"],
887
+ _excluded2 = ["children"];
650
888
  const RigidBodyContext = /*#__PURE__*/createContext(undefined);
651
889
 
652
- const useParentRigidBody = () => useContext(RigidBodyContext); // RigidBody
890
+ const useRigidBodyContext = () => useContext(RigidBodyContext); // RigidBody
653
891
 
654
892
 
655
893
  const RigidBody = /*#__PURE__*/forwardRef((_ref, ref) => {
@@ -658,28 +896,36 @@ const RigidBody = /*#__PURE__*/forwardRef((_ref, ref) => {
658
896
  } = _ref,
659
897
  props = _objectWithoutProperties(_ref, _excluded);
660
898
 
661
- const [group, rigidBody] = useRigidBody(props);
899
+ const [object, rigidBody] = useRigidBody(props);
662
900
  useImperativeHandle(ref, () => rigidBody);
663
901
  return /*#__PURE__*/React.createElement(RigidBodyContext.Provider, {
664
- value: [group, rigidBody]
665
- }, /*#__PURE__*/React.createElement("group", {
666
- ref: group
902
+ value: [object, rigidBody, !!(props.onCollisionEnter || props.onCollisionExit)]
903
+ }, /*#__PURE__*/React.createElement("object3D", {
904
+ ref: object
667
905
  }, children));
668
906
  }); // Colliders
669
907
 
670
- const AnyCollider = props => {
908
+ const AnyCollider = _ref2 => {
909
+ let {
910
+ children
911
+ } = _ref2,
912
+ props = _objectWithoutProperties(_ref2, _excluded2);
913
+
671
914
  const {
672
915
  world
673
916
  } = useRapier();
674
- const [object, rigidBody] = useParentRigidBody();
917
+ const [, rigidBody, hasCollisionEvents] = useRigidBodyContext();
918
+ const ref = useRef(null);
675
919
  useEffect(() => {
676
- const scale = object.current.getWorldScale(new Vector3());
677
- 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);
678
922
  return () => {
679
- world.removeCollider(collider, false);
923
+ world.removeCollider(collider);
680
924
  };
681
925
  }, []);
682
- return null;
926
+ return /*#__PURE__*/React.createElement("object3D", {
927
+ ref: ref
928
+ }, children);
683
929
  };
684
930
 
685
931
  const CuboidCollider = props => {
@@ -828,7 +1074,7 @@ const Debug = () => {
828
1074
 
829
1075
  useFrame(() => {
830
1076
  const newColliders = [];
831
- world.colliders.forEachCollider(collider => {
1077
+ world.forEachCollider(collider => {
832
1078
  newColliders.push(collider.handle);
833
1079
  });
834
1080
  setColliders(newColliders);