@react-three/rapier 0.8.2 → 0.10.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.
@@ -3,10 +3,10 @@
3
3
  Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var rapier3dCompat = require('@dimforge/rapier3d-compat');
6
- var React = require('react');
7
- var useAsset = require('use-asset');
8
6
  var fiber = require('@react-three/fiber');
7
+ var React = require('react');
9
8
  var three = require('three');
9
+ var useAsset = require('use-asset');
10
10
  var threeStdlib = require('three-stdlib');
11
11
 
12
12
  function _interopDefault (e) { return e && e.__esModule ? e : { 'default': e }; }
@@ -31,6 +31,47 @@ function _interopNamespace(e) {
31
31
 
32
32
  var React__default = /*#__PURE__*/_interopDefault(React);
33
33
 
34
+ function _defineProperty(obj, key, value) {
35
+ if (key in obj) {
36
+ Object.defineProperty(obj, key, {
37
+ value: value,
38
+ enumerable: true,
39
+ configurable: true,
40
+ writable: true
41
+ });
42
+ } else {
43
+ obj[key] = value;
44
+ }
45
+
46
+ return obj;
47
+ }
48
+
49
+ function ownKeys(object, enumerableOnly) {
50
+ var keys = Object.keys(object);
51
+
52
+ if (Object.getOwnPropertySymbols) {
53
+ var symbols = Object.getOwnPropertySymbols(object);
54
+ enumerableOnly && (symbols = symbols.filter(function (sym) {
55
+ return Object.getOwnPropertyDescriptor(object, sym).enumerable;
56
+ })), keys.push.apply(keys, symbols);
57
+ }
58
+
59
+ return keys;
60
+ }
61
+
62
+ function _objectSpread2(target) {
63
+ for (var i = 1; i < arguments.length; i++) {
64
+ var source = null != arguments[i] ? arguments[i] : {};
65
+ i % 2 ? ownKeys(Object(source), !0).forEach(function (key) {
66
+ _defineProperty(target, key, source[key]);
67
+ }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) {
68
+ Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
69
+ });
70
+ }
71
+
72
+ return target;
73
+ }
74
+
34
75
  const _quaternion = new three.Quaternion();
35
76
  new three.Euler();
36
77
  const _vector3 = new three.Vector3();
@@ -238,375 +279,304 @@ const createJointApi = ref => {
238
279
  };
239
280
  };
240
281
 
241
- const RapierContext = /*#__PURE__*/React.createContext(undefined);
242
-
243
- const importRapier = async () => {
244
- let r = await Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require('@dimforge/rapier3d-compat')); });
245
- await r.init();
246
- return r;
247
- };
248
-
249
- const Physics = ({
250
- colliders: _colliders = "cuboid",
251
- gravity: _gravity = [0, -9.81, 0],
252
- children,
253
- timeStep: _timeStep = 1 / 60,
254
- paused: _paused = false,
255
- updatePriority
256
- }) => {
257
- const rapier = useAsset.useAsset(importRapier);
258
- const worldRef = React.useRef();
259
- const getWorldRef = React.useRef(() => {
260
- if (!worldRef.current) {
261
- const world = new rapier.World(vectorArrayToVector3(_gravity));
262
- worldRef.current = world;
263
- }
282
+ const scaleColliderArgs = (shape, args, scale) => {
283
+ const newArgs = args.slice(); // Heightfield uses a vector
264
284
 
265
- return worldRef.current;
266
- });
267
- const [rigidBodyStates] = React.useState(() => new Map());
268
- const [colliderStates] = React.useState(() => new Map());
269
- const [rigidBodyEvents] = React.useState(() => new Map());
270
- const [colliderEvents] = React.useState(() => new Map());
271
- const [eventQueue] = React.useState(() => new rapier3dCompat.EventQueue(false)); // Init world
285
+ if (shape === "heightfield") {
286
+ const s = newArgs[3];
287
+ s.x *= scale.x;
288
+ s.x *= scale.y;
289
+ s.x *= scale.z;
290
+ return newArgs;
291
+ } // Trimesh and convex scale the vertices
272
292
 
273
- React.useEffect(() => {
274
- const world = getWorldRef.current();
275
- return () => {
276
- if (world) {
277
- world.free();
278
- worldRef.current = undefined;
279
- }
280
- };
281
- }, []); // Update gravity
282
293
 
283
- React.useEffect(() => {
284
- const world = worldRef.current;
294
+ if (shape === "trimesh" || shape === "convexHull") {
295
+ newArgs[0] = scaleVertices(newArgs[0], scale);
296
+ return newArgs;
297
+ } // Prepfill with some extra
285
298
 
286
- if (world) {
287
- world.gravity = vectorArrayToVector3(_gravity);
288
- }
289
- }, [_gravity]);
290
- const [steppingState] = React.useState({
291
- accumulator: 0
292
- });
293
- /* Check if the timestep is supposed to be variable. We'll do this here
294
- once so we don't have to string-check every frame. */
295
299
 
296
- const timeStepVariable = _timeStep === "vary";
297
- fiber.useFrame((_, dt) => {
298
- const world = worldRef.current;
299
- if (!world) return;
300
- /**
301
- * Fixed timeStep simulation progression
302
- * @see https://gafferongames.com/post/fix_your_timestep/
303
- */
300
+ const scaleArray = [scale.x, scale.y, scale.z, scale.x, scale.x];
301
+ return newArgs.map((arg, index) => scaleArray[index] * arg);
302
+ };
303
+ const createColliderFromOptions = (options, world, scale, rigidBody) => {
304
+ const scaledArgs = scaleColliderArgs(options.shape, options.args, scale); // @ts-ignore
304
305
 
305
- const clampedDelta = three.MathUtils.clamp(dt, 0, 0.2);
306
+ const desc = rapier3dCompat.ColliderDesc[options.shape](...scaledArgs);
307
+ return world.createCollider(desc, rigidBody);
308
+ };
309
+ const massPropertiesConflictError = "Please pick ONLY ONE of the `density`, `mass` and `massProperties` options.";
306
310
 
307
- if (timeStepVariable) {
308
- world.timestep = clampedDelta;
309
- if (!_paused) world.step(eventQueue);
310
- } else {
311
- world.timestep = _timeStep; // don't step time forwards if paused
312
- // Increase accumulator
311
+ const setColliderMassOptions = (collider, options) => {
312
+ if (options.density !== undefined) {
313
+ if (options.mass !== undefined || options.massProperties !== undefined) {
314
+ throw new Error(massPropertiesConflictError);
315
+ }
313
316
 
314
- steppingState.accumulator += _paused ? 0 : clampedDelta;
317
+ collider.setDensity(options.density);
318
+ return;
319
+ }
315
320
 
316
- if (!_paused) {
317
- while (steppingState.accumulator >= _timeStep) {
318
- world.step(eventQueue);
319
- steppingState.accumulator -= _timeStep;
320
- }
321
- }
321
+ if (options.mass !== undefined) {
322
+ if (options.massProperties !== undefined) {
323
+ throw new Error(massPropertiesConflictError);
322
324
  }
323
325
 
324
- const interpolationAlpha = timeStepVariable ? 1 : steppingState.accumulator % _timeStep / _timeStep; // Update meshes
325
-
326
- rigidBodyStates.forEach((state, handle) => {
327
- const rigidBody = world.getRigidBody(handle);
328
- const events = rigidBodyEvents.get(handle);
326
+ collider.setMass(options.mass);
327
+ return;
328
+ }
329
329
 
330
- if (events !== null && events !== void 0 && events.onSleep || events !== null && events !== void 0 && events.onWake) {
331
- if (rigidBody.isSleeping() && !state.isSleeping) {
332
- var _events$onSleep;
330
+ if (options.massProperties !== undefined) {
331
+ collider.setMassProperties(options.massProperties.mass, options.massProperties.centerOfMass, options.massProperties.principalAngularInertia, options.massProperties.angularInertiaLocalFrame);
332
+ }
333
+ };
333
334
 
334
- events === null || events === void 0 ? void 0 : (_events$onSleep = events.onSleep) === null || _events$onSleep === void 0 ? void 0 : _events$onSleep.call(events);
335
- }
335
+ const mutableColliderOptions = {
336
+ sensor: (collider, value) => {
337
+ collider.setSensor(value);
338
+ },
339
+ collisionGroups: (collider, value) => {
340
+ collider.setCollisionGroups(value);
341
+ },
342
+ solverGroups: (collider, value) => {
343
+ collider.setSolverGroups(value);
344
+ },
345
+ friction: (collider, value) => {
346
+ collider.setFriction(value);
347
+ },
348
+ frictionCombineRule: (collider, value) => {
349
+ collider.setFrictionCombineRule(value);
350
+ },
351
+ restitution: (collider, value) => {
352
+ collider.setRestitution(value);
353
+ },
354
+ restitutionCombineRule: (collider, value) => {
355
+ collider.setRestitutionCombineRule(value);
356
+ },
357
+ // To make sure the options all mutalbe options are listed
358
+ quaternion: () => {},
359
+ position: () => {},
360
+ rotation: () => {},
361
+ scale: () => {}
362
+ };
363
+ const mutableColliderOptionKeys = Object.keys(mutableColliderOptions);
364
+ const setColliderOptions = (collider, options, states) => {
365
+ const state = states.get(collider.handle);
336
366
 
337
- if (!rigidBody.isSleeping() && state.isSleeping) {
338
- var _events$onWake;
367
+ if (state) {
368
+ var _state$worldParent;
339
369
 
340
- events === null || events === void 0 ? void 0 : (_events$onWake = events.onWake) === null || _events$onWake === void 0 ? void 0 : _events$onWake.call(events);
341
- }
370
+ // Update collider position based on the object's position
371
+ const parentWorldScale = state.object.parent.getWorldScale(_vector3);
372
+ const parentInvertedWorldMatrix = (_state$worldParent = state.worldParent) === null || _state$worldParent === void 0 ? void 0 : _state$worldParent.matrixWorld.clone().invert();
373
+ state.object.updateWorldMatrix(true, false);
342
374
 
343
- state.isSleeping = rigidBody.isSleeping();
344
- }
375
+ _matrix4.copy(state.object.matrixWorld);
345
376
 
346
- if (!rigidBody || rigidBody.isSleeping() || !state.setMatrix) {
347
- return;
348
- }
377
+ if (parentInvertedWorldMatrix) {
378
+ _matrix4.premultiply(parentInvertedWorldMatrix);
379
+ }
349
380
 
350
- let t = rigidBody.translation();
351
- let r = rigidBody.rotation(); // Get new position
381
+ _matrix4.decompose(_position, _rotation, _scale);
352
382
 
353
- _matrix4.compose(t, rapierQuaternionToQuaternion(r), state.scale).premultiply(state.invertedWorldMatrix).decompose(_position, _rotation, _scale);
383
+ if (collider.parent()) {
384
+ collider.setTranslationWrtParent({
385
+ x: _position.x * parentWorldScale.x,
386
+ y: _position.y * parentWorldScale.y,
387
+ z: _position.z * parentWorldScale.z
388
+ });
389
+ collider.setRotationWrtParent(_rotation);
390
+ } else {
391
+ collider.setTranslation({
392
+ x: _position.x * parentWorldScale.x,
393
+ y: _position.y * parentWorldScale.y,
394
+ z: _position.z * parentWorldScale.z
395
+ });
396
+ collider.setRotation(_rotation);
397
+ }
354
398
 
355
- if (state.object instanceof three.InstancedMesh) {
356
- state.setMatrix(_matrix4);
357
- state.object.instanceMatrix.needsUpdate = true;
358
- } else {
359
- // Interpolate from last position
360
- state.object.position.lerp(_position, interpolationAlpha);
361
- state.object.quaternion.slerp(_rotation, interpolationAlpha);
399
+ mutableColliderOptionKeys.forEach(key => {
400
+ if (key in options) {
401
+ const option = options[key];
402
+ mutableColliderOptions[key](collider, // @ts-ignore Option does not want to fit into the function, but it will
403
+ option, options);
362
404
  }
363
- });
364
- eventQueue.drainCollisionEvents((handle1, handle2, started) => {
365
- var _collider1$parent, _collider2$parent;
366
-
367
- const collider1 = world.getCollider(handle1);
368
- const collider2 = world.getCollider(handle2);
369
- const rigidBodyHandle1 = (_collider1$parent = collider1.parent()) === null || _collider1$parent === void 0 ? void 0 : _collider1$parent.handle;
370
- const rigidBodyHandle2 = (_collider2$parent = collider2.parent()) === null || _collider2$parent === void 0 ? void 0 : _collider2$parent.handle; // Collision Events
405
+ }); // handle mass separately, because the assignments
406
+ // are exclusive.
371
407
 
372
- if (!collider1 || !collider2) {
373
- return;
374
- }
408
+ setColliderMassOptions(collider, options);
409
+ }
410
+ };
411
+ const useUpdateColliderOptions = (collidersRef, props, states) => {
412
+ // TODO: Improve this, split each prop into its own effect
413
+ const mutablePropsAsFlatArray = React.useMemo(() => mutableColliderOptionKeys.flatMap(key => {
414
+ return vectorToTuple(props[key]);
415
+ }), [props]);
416
+ React.useEffect(() => {
417
+ collidersRef.current.forEach(collider => {
418
+ setColliderOptions(collider, props, states);
419
+ });
420
+ }, mutablePropsAsFlatArray);
421
+ };
375
422
 
376
- const collider1Events = colliderEvents.get(collider1.handle);
377
- const collider2Events = colliderEvents.get(collider2.handle);
378
- const rigidBody1 = rigidBodyHandle1 ? world.getRigidBody(rigidBodyHandle1) : undefined;
379
- const rigidBody2 = rigidBodyHandle2 ? world.getRigidBody(rigidBodyHandle2) : undefined;
380
- const rigidBody1Events = rigidBodyHandle1 ? rigidBodyEvents.get(rigidBodyHandle1) : undefined;
381
- const rigidBody2Events = rigidBodyHandle2 ? rigidBodyEvents.get(rigidBodyHandle2) : undefined;
382
- const collider1State = colliderStates.get(collider1.handle);
383
- const collider2State = colliderStates.get(collider2.handle);
384
- const rigidBody1State = rigidBodyHandle1 ? rigidBodyStates.get(rigidBodyHandle1) : undefined;
385
- const rigidBody2State = rigidBodyHandle2 ? rigidBodyStates.get(rigidBodyHandle2) : undefined;
423
+ const isChildOfMeshCollider = child => {
424
+ let flag = false;
425
+ child.traverseAncestors(a => {
426
+ if (a.userData.r3RapierType === "MeshCollider") flag = true;
427
+ });
428
+ return flag;
429
+ };
386
430
 
387
- if (started) {
388
- world.contactPair(collider1, collider2, (manifold, flipped) => {
389
- var _rigidBody1Events$onC, _rigidBody2Events$onC, _collider1Events$onCo, _collider2Events$onCo;
390
-
391
- /* RigidBody events */
392
- rigidBody1Events === null || rigidBody1Events === void 0 ? void 0 : (_rigidBody1Events$onC = rigidBody1Events.onCollisionEnter) === null || _rigidBody1Events$onC === void 0 ? void 0 : _rigidBody1Events$onC.call(rigidBody1Events, {
393
- rigidBody: rigidBody2,
394
- collider: collider2,
395
- colliderObject: collider2State === null || collider2State === void 0 ? void 0 : collider2State.object,
396
- rigidBodyObject: rigidBody2State === null || rigidBody2State === void 0 ? void 0 : rigidBody2State.object,
397
- manifold,
398
- flipped
399
- });
400
- rigidBody2Events === null || rigidBody2Events === void 0 ? void 0 : (_rigidBody2Events$onC = rigidBody2Events.onCollisionEnter) === null || _rigidBody2Events$onC === void 0 ? void 0 : _rigidBody2Events$onC.call(rigidBody2Events, {
401
- rigidBody: rigidBody1,
402
- collider: collider1,
403
- colliderObject: collider1State === null || collider1State === void 0 ? void 0 : collider1State.object,
404
- rigidBodyObject: rigidBody1State === null || rigidBody1State === void 0 ? void 0 : rigidBody1State.object,
405
- manifold,
406
- flipped
407
- });
408
- /* Collider events */
409
-
410
- collider1Events === null || collider1Events === void 0 ? void 0 : (_collider1Events$onCo = collider1Events.onCollisionEnter) === null || _collider1Events$onCo === void 0 ? void 0 : _collider1Events$onCo.call(collider1Events, {
411
- rigidBody: rigidBody2,
412
- collider: collider2,
413
- colliderObject: collider2State === null || collider2State === void 0 ? void 0 : collider2State.object,
414
- rigidBodyObject: rigidBody2State === null || rigidBody2State === void 0 ? void 0 : rigidBody2State.object,
415
- manifold,
416
- flipped
417
- });
418
- collider2Events === null || collider2Events === void 0 ? void 0 : (_collider2Events$onCo = collider2Events.onCollisionEnter) === null || _collider2Events$onCo === void 0 ? void 0 : _collider2Events$onCo.call(collider2Events, {
419
- rigidBody: rigidBody1,
420
- collider: collider1,
421
- colliderObject: collider1State === null || collider1State === void 0 ? void 0 : collider1State.object,
422
- rigidBodyObject: rigidBody1State === null || rigidBody1State === void 0 ? void 0 : rigidBody1State.object,
423
- manifold,
424
- flipped
425
- });
426
- });
427
- } else {
428
- var _rigidBody1Events$onC2, _rigidBody2Events$onC2, _collider1Events$onCo2, _collider2Events$onCo2;
429
-
430
- rigidBody1Events === null || rigidBody1Events === void 0 ? void 0 : (_rigidBody1Events$onC2 = rigidBody1Events.onCollisionExit) === null || _rigidBody1Events$onC2 === void 0 ? void 0 : _rigidBody1Events$onC2.call(rigidBody1Events, {
431
- rigidBody: rigidBody2,
432
- collider: collider2
433
- });
434
- rigidBody2Events === null || rigidBody2Events === void 0 ? void 0 : (_rigidBody2Events$onC2 = rigidBody2Events.onCollisionExit) === null || _rigidBody2Events$onC2 === void 0 ? void 0 : _rigidBody2Events$onC2.call(rigidBody2Events, {
435
- rigidBody: rigidBody1,
436
- collider: collider1
437
- });
438
- collider1Events === null || collider1Events === void 0 ? void 0 : (_collider1Events$onCo2 = collider1Events.onCollisionExit) === null || _collider1Events$onCo2 === void 0 ? void 0 : _collider1Events$onCo2.call(collider1Events, {
439
- rigidBody: rigidBody2,
440
- collider: collider2
441
- });
442
- collider2Events === null || collider2Events === void 0 ? void 0 : (_collider2Events$onCo2 = collider2Events.onCollisionExit) === null || _collider2Events$onCo2 === void 0 ? void 0 : _collider2Events$onCo2.call(collider2Events, {
443
- rigidBody: rigidBody1,
444
- collider: collider1
445
- });
446
- } // Sensor Intersections
447
-
448
-
449
- if (started) {
450
- if (world.intersectionPair(collider1, collider2)) {
451
- var _rigidBody1Events$onI, _rigidBody2Events$onI, _collider1Events$onIn, _collider2Events$onIn;
452
-
453
- rigidBody1Events === null || rigidBody1Events === void 0 ? void 0 : (_rigidBody1Events$onI = rigidBody1Events.onIntersectionEnter) === null || _rigidBody1Events$onI === void 0 ? void 0 : _rigidBody1Events$onI.call(rigidBody1Events, {
454
- rigidBody: rigidBody2,
455
- collider: collider2,
456
- colliderObject: collider2State === null || collider2State === void 0 ? void 0 : collider2State.object,
457
- rigidBodyObject: rigidBody2State === null || rigidBody2State === void 0 ? void 0 : rigidBody2State.object
458
- });
459
- rigidBody2Events === null || rigidBody2Events === void 0 ? void 0 : (_rigidBody2Events$onI = rigidBody2Events.onIntersectionEnter) === null || _rigidBody2Events$onI === void 0 ? void 0 : _rigidBody2Events$onI.call(rigidBody2Events, {
460
- rigidBody: rigidBody1,
461
- collider: collider1,
462
- colliderObject: collider1State === null || collider1State === void 0 ? void 0 : collider1State.object,
463
- rigidBodyObject: rigidBody1State === null || rigidBody1State === void 0 ? void 0 : rigidBody1State.object
464
- });
465
- collider1Events === null || collider1Events === void 0 ? void 0 : (_collider1Events$onIn = collider1Events.onIntersectionEnter) === null || _collider1Events$onIn === void 0 ? void 0 : _collider1Events$onIn.call(collider1Events, {
466
- rigidBody: rigidBody2,
467
- collider: collider2,
468
- colliderObject: collider2State === null || collider2State === void 0 ? void 0 : collider2State.object,
469
- rigidBodyObject: rigidBody2State === null || rigidBody2State === void 0 ? void 0 : rigidBody2State.object
470
- });
471
- collider2Events === null || collider2Events === void 0 ? void 0 : (_collider2Events$onIn = collider2Events.onIntersectionEnter) === null || _collider2Events$onIn === void 0 ? void 0 : _collider2Events$onIn.call(collider2Events, {
472
- rigidBody: rigidBody1,
473
- collider: collider1,
474
- colliderObject: collider1State === null || collider1State === void 0 ? void 0 : collider1State.object,
475
- rigidBodyObject: rigidBody1State === null || rigidBody1State === void 0 ? void 0 : rigidBody1State.object
476
- });
477
- }
478
- } else {
479
- var _rigidBody1Events$onI2, _rigidBody2Events$onI2, _collider1Events$onIn2, _collider2Events$onIn2;
480
-
481
- rigidBody1Events === null || rigidBody1Events === void 0 ? void 0 : (_rigidBody1Events$onI2 = rigidBody1Events.onIntersectionExit) === null || _rigidBody1Events$onI2 === void 0 ? void 0 : _rigidBody1Events$onI2.call(rigidBody1Events, {
482
- rigidBody: rigidBody2,
483
- collider: collider2
484
- });
485
- rigidBody2Events === null || rigidBody2Events === void 0 ? void 0 : (_rigidBody2Events$onI2 = rigidBody2Events.onIntersectionExit) === null || _rigidBody2Events$onI2 === void 0 ? void 0 : _rigidBody2Events$onI2.call(rigidBody2Events, {
486
- rigidBody: rigidBody1,
487
- collider: collider1
488
- });
489
- collider1Events === null || collider1Events === void 0 ? void 0 : (_collider1Events$onIn2 = collider1Events.onIntersectionExit) === null || _collider1Events$onIn2 === void 0 ? void 0 : _collider1Events$onIn2.call(collider1Events, {
490
- rigidBody: rigidBody2,
491
- collider: collider2
492
- });
493
- collider2Events === null || collider2Events === void 0 ? void 0 : (_collider2Events$onIn2 = collider2Events.onIntersectionExit) === null || _collider2Events$onIn2 === void 0 ? void 0 : _collider2Events$onIn2.call(collider2Events, {
494
- rigidBody: rigidBody1,
495
- collider: collider1
496
- });
497
- }
498
- });
499
- }, updatePriority);
500
- const api = React.useMemo(() => createWorldApi(getWorldRef), []);
501
- const context = React.useMemo(() => ({
502
- rapier,
503
- world: api,
504
- physicsOptions: {
505
- colliders: _colliders,
506
- gravity: _gravity
507
- },
508
- rigidBodyStates,
509
- colliderStates,
510
- rigidBodyEvents,
511
- colliderEvents,
512
- isPaused: _paused
513
- }), [_paused]);
514
- return /*#__PURE__*/React__default["default"].createElement(RapierContext.Provider, {
515
- value: context
516
- }, children);
431
+ const createColliderState = (collider, object, rigidBodyObject) => {
432
+ return {
433
+ collider,
434
+ worldParent: rigidBodyObject || undefined,
435
+ object
436
+ };
437
+ };
438
+ const autoColliderMap = {
439
+ cuboid: "cuboid",
440
+ ball: "ball",
441
+ hull: "convexHull",
442
+ trimesh: "trimesh"
517
443
  };
444
+ const createColliderPropsFromChildren = ({
445
+ object,
446
+ ignoreMeshColliders: _ignoreMeshColliders = true,
447
+ options
448
+ }) => {
449
+ const colliderProps = [];
450
+ object.updateWorldMatrix(true, false);
451
+ const invertedParentMatrixWorld = object.matrixWorld.clone().invert();
518
452
 
519
- function _extends() {
520
- _extends = Object.assign ? Object.assign.bind() : function (target) {
521
- for (var i = 1; i < arguments.length; i++) {
522
- var source = arguments[i];
453
+ const colliderFromChild = child => {
454
+ if ("isMesh" in child) {
455
+ if (_ignoreMeshColliders && isChildOfMeshCollider(child)) return;
456
+ const worldScale = child.getWorldScale(_scale);
457
+ const shape = autoColliderMap[options.colliders || "cuboid"];
458
+ child.updateWorldMatrix(true, false);
523
459
 
524
- for (var key in source) {
525
- if (Object.prototype.hasOwnProperty.call(source, key)) {
526
- target[key] = source[key];
527
- }
528
- }
529
- }
460
+ _matrix4.copy(child.matrixWorld).premultiply(invertedParentMatrixWorld).decompose(_position, _rotation, _scale);
530
461
 
531
- return target;
462
+ const rotationEuler = new three.Euler().setFromQuaternion(_rotation, "XYZ");
463
+ const {
464
+ geometry
465
+ } = child;
466
+ const {
467
+ args,
468
+ offset
469
+ } = getColliderArgsFromGeometry(geometry, options.colliders || "cuboid");
470
+ colliderProps.push(_objectSpread2(_objectSpread2({}, options), {}, {
471
+ args: args,
472
+ shape: shape,
473
+ rotation: [rotationEuler.x, rotationEuler.y, rotationEuler.z],
474
+ position: [_position.x + offset.x * worldScale.x, _position.y + offset.y * worldScale.y, _position.z + offset.z * worldScale.z],
475
+ scale: [worldScale.x, worldScale.y, worldScale.z]
476
+ }));
477
+ }
532
478
  };
533
- return _extends.apply(this, arguments);
534
- }
535
479
 
536
- function _objectWithoutPropertiesLoose(source, excluded) {
537
- if (source == null) return {};
538
- var target = {};
539
- var sourceKeys = Object.keys(source);
540
- var key, i;
541
-
542
- for (i = 0; i < sourceKeys.length; i++) {
543
- key = sourceKeys[i];
544
- if (excluded.indexOf(key) >= 0) continue;
545
- target[key] = source[key];
480
+ if (options.includeInvisible) {
481
+ object.traverse(colliderFromChild);
482
+ } else {
483
+ object.traverseVisible(colliderFromChild);
546
484
  }
547
485
 
548
- return target;
549
- }
550
-
551
- function _objectWithoutProperties(source, excluded) {
552
- if (source == null) return {};
553
- var target = _objectWithoutPropertiesLoose(source, excluded);
554
- var key, i;
486
+ return colliderProps;
487
+ };
488
+ const getColliderArgsFromGeometry = (geometry, colliders) => {
489
+ switch (colliders) {
490
+ case "cuboid":
491
+ {
492
+ geometry.computeBoundingBox();
493
+ const {
494
+ boundingBox
495
+ } = geometry;
496
+ const size = boundingBox.getSize(new three.Vector3());
497
+ return {
498
+ args: [size.x / 2, size.y / 2, size.z / 2],
499
+ offset: boundingBox.getCenter(new three.Vector3())
500
+ };
501
+ }
555
502
 
556
- if (Object.getOwnPropertySymbols) {
557
- var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
503
+ case "ball":
504
+ {
505
+ geometry.computeBoundingSphere();
506
+ const {
507
+ boundingSphere
508
+ } = geometry;
509
+ const radius = boundingSphere.radius;
510
+ return {
511
+ args: [radius],
512
+ offset: boundingSphere.center
513
+ };
514
+ }
558
515
 
559
- for (i = 0; i < sourceSymbolKeys.length; i++) {
560
- key = sourceSymbolKeys[i];
561
- if (excluded.indexOf(key) >= 0) continue;
562
- if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
563
- target[key] = source[key];
564
- }
565
- }
516
+ case "trimesh":
517
+ {
518
+ var _clonedGeometry$index;
566
519
 
567
- return target;
568
- }
520
+ const clonedGeometry = geometry.index ? geometry.clone() : threeStdlib.mergeVertices(geometry);
521
+ return {
522
+ args: [clonedGeometry.attributes.position.array, (_clonedGeometry$index = clonedGeometry.index) === null || _clonedGeometry$index === void 0 ? void 0 : _clonedGeometry$index.array],
523
+ offset: new three.Vector3()
524
+ };
525
+ }
569
526
 
570
- function _defineProperty(obj, key, value) {
571
- if (key in obj) {
572
- Object.defineProperty(obj, key, {
573
- value: value,
574
- enumerable: true,
575
- configurable: true,
576
- writable: true
577
- });
578
- } else {
579
- obj[key] = value;
527
+ case "hull":
528
+ {
529
+ const g = geometry.clone();
530
+ return {
531
+ args: [g.attributes.position.array],
532
+ offset: new three.Vector3()
533
+ };
534
+ }
580
535
  }
581
536
 
582
- return obj;
583
- }
584
-
585
- function ownKeys(object, enumerableOnly) {
586
- var keys = Object.keys(object);
537
+ return {
538
+ args: [],
539
+ offset: new three.Vector3()
540
+ };
541
+ };
542
+ const useColliderEvents = (collidersRef, props, events) => {
543
+ const {
544
+ onCollisionEnter,
545
+ onCollisionExit,
546
+ onIntersectionEnter,
547
+ onIntersectionExit,
548
+ onContactForce
549
+ } = props;
550
+ React.useEffect(() => {
551
+ var _collidersRef$current;
587
552
 
588
- if (Object.getOwnPropertySymbols) {
589
- var symbols = Object.getOwnPropertySymbols(object);
590
- enumerableOnly && (symbols = symbols.filter(function (sym) {
591
- return Object.getOwnPropertyDescriptor(object, sym).enumerable;
592
- })), keys.push.apply(keys, symbols);
593
- }
553
+ (_collidersRef$current = collidersRef.current) === null || _collidersRef$current === void 0 ? void 0 : _collidersRef$current.forEach(collider => {
554
+ const hasCollisionEvent = !!(onCollisionEnter || onCollisionExit || onIntersectionEnter || onIntersectionExit);
555
+ const hasContactForceEvent = !!onContactForce;
594
556
 
595
- return keys;
596
- }
557
+ if (hasCollisionEvent && hasContactForceEvent) {
558
+ collider.setActiveEvents(rapier3dCompat.ActiveEvents.COLLISION_EVENTS | rapier3dCompat.ActiveEvents.CONTACT_FORCE_EVENTS);
559
+ } else if (hasCollisionEvent) {
560
+ collider.setActiveEvents(rapier3dCompat.ActiveEvents.COLLISION_EVENTS);
561
+ } else if (hasContactForceEvent) {
562
+ collider.setActiveEvents(rapier3dCompat.ActiveEvents.CONTACT_FORCE_EVENTS);
563
+ }
597
564
 
598
- function _objectSpread2(target) {
599
- for (var i = 1; i < arguments.length; i++) {
600
- var source = null != arguments[i] ? arguments[i] : {};
601
- i % 2 ? ownKeys(Object(source), !0).forEach(function (key) {
602
- _defineProperty(target, key, source[key]);
603
- }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) {
604
- Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key));
565
+ events.set(collider.handle, {
566
+ onCollisionEnter,
567
+ onCollisionExit,
568
+ onIntersectionEnter,
569
+ onIntersectionExit,
570
+ onContactForce
571
+ });
605
572
  });
606
- }
573
+ return () => {
574
+ var _collidersRef$current2;
607
575
 
608
- return target;
609
- }
576
+ (_collidersRef$current2 = collidersRef.current) === null || _collidersRef$current2 === void 0 ? void 0 : _collidersRef$current2.forEach(collider => events.delete(collider.handle));
577
+ };
578
+ }, [onCollisionEnter, onCollisionExit, onIntersectionEnter, onIntersectionExit, onContactForce]);
579
+ };
610
580
 
611
581
  const rigidBodyDescFromOptions = options => {
612
582
  const type = rigidBodyTypeFromString((options === null || options === void 0 ? void 0 : options.type) || "dynamic");
@@ -667,6 +637,9 @@ const mutableRigidBodyOptions = {
667
637
  ccd: (rb, value) => {
668
638
  rb.enableCcd(value);
669
639
  },
640
+ userData: (rb, value) => {
641
+ rb.userData = value;
642
+ },
670
643
  position: () => {},
671
644
  rotation: () => {},
672
645
  quaternion: () => {},
@@ -750,443 +723,626 @@ const useRigidBodyEvents = (rigidBodyRef, props, events) => {
750
723
  }, [onWake, onSleep, onCollisionEnter, onCollisionExit, onIntersectionEnter, onIntersectionExit]);
751
724
  };
752
725
 
753
- const scaleColliderArgs = (shape, args, scale) => {
754
- const newArgs = args.slice(); // Heightfield uses a vector
755
-
756
- if (shape === "heightfield") {
757
- const s = newArgs[3];
758
- s.x *= scale.x;
759
- s.x *= scale.y;
760
- s.x *= scale.z;
761
- return newArgs;
762
- } // Trimesh and convex scale the vertices
763
-
726
+ const useRapier = () => {
727
+ return React.useContext(RapierContext);
728
+ };
729
+ const useChildColliderProps = (ref, options, ignoreMeshColliders = true) => {
730
+ const [colliderProps, setColliderProps] = React.useState([]);
731
+ React.useEffect(() => {
732
+ const object = ref.current;
764
733
 
765
- if (shape === "trimesh" || shape === "convexHull") {
766
- newArgs[0] = scaleVertices(newArgs[0], scale);
767
- return newArgs;
768
- } // Prepfill with some extra
734
+ if (object && options.colliders !== false) {
735
+ setColliderProps(createColliderPropsFromChildren({
736
+ object: ref.current,
737
+ options,
738
+ ignoreMeshColliders
739
+ }));
740
+ }
741
+ }, [options.colliders]);
742
+ return colliderProps;
743
+ };
744
+ const useRigidBody = (options = {}) => {
745
+ const {
746
+ world,
747
+ rigidBodyStates,
748
+ physicsOptions,
749
+ rigidBodyEvents
750
+ } = useRapier();
751
+ const ref = React.useRef();
752
+ const mergedOptions = React.useMemo(() => {
753
+ return _objectSpread2(_objectSpread2(_objectSpread2({}, physicsOptions), options), {}, {
754
+ children: undefined
755
+ });
756
+ }, [physicsOptions, options]);
757
+ const childColliderProps = useChildColliderProps(ref, mergedOptions); // Create rigidbody
769
758
 
759
+ const rigidBodyRef = React.useRef();
760
+ const getRigidBodyRef = React.useRef(() => {
761
+ if (!rigidBodyRef.current) {
762
+ const desc = rigidBodyDescFromOptions(options);
763
+ const rigidBody = world.createRigidBody(desc);
764
+ rigidBodyRef.current = world.getRigidBody(rigidBody.handle);
765
+ }
770
766
 
771
- const scaleArray = [scale.x, scale.y, scale.z, scale.x, scale.x];
772
- return newArgs.map((arg, index) => scaleArray[index] * arg);
773
- };
774
- const createColliderFromOptions = (options, world, scale, rigidBody) => {
775
- const scaledArgs = scaleColliderArgs(options.shape, options.args, scale); // @ts-ignore
767
+ return rigidBodyRef.current;
768
+ }); // Setup
776
769
 
777
- const desc = rapier3dCompat.ColliderDesc[options.shape](...scaledArgs);
778
- return world.createCollider(desc, rigidBody);
779
- };
780
- const massPropertiesConflictError = "Please pick ONLY ONE of the `density`, `mass` and `massProperties` options.";
770
+ React.useEffect(() => {
771
+ const rigidBody = getRigidBodyRef.current();
772
+ rigidBodyRef.current = rigidBody;
781
773
 
782
- const setColliderMassOptions = (collider, options) => {
783
- if (options.density !== undefined) {
784
- if (options.mass !== undefined || options.massProperties !== undefined) {
785
- throw new Error(massPropertiesConflictError);
774
+ if (!ref.current) {
775
+ ref.current = new three.Object3D();
786
776
  }
787
777
 
788
- collider.setDensity(options.density);
789
- return;
790
- }
778
+ rigidBodyStates.set(rigidBody.handle, createRigidBodyState({
779
+ rigidBody,
780
+ object: ref.current
781
+ }));
782
+ return () => {
783
+ world.removeRigidBody(rigidBody);
784
+ rigidBodyStates.delete(rigidBody.handle);
785
+ rigidBodyRef.current = undefined;
786
+ };
787
+ }, []);
788
+ useUpdateRigidBodyOptions(rigidBodyRef, mergedOptions, rigidBodyStates);
789
+ useRigidBodyEvents(rigidBodyRef, mergedOptions, rigidBodyEvents);
790
+ const api = React.useMemo(() => createRigidBodyApi(getRigidBodyRef), []);
791
+ return [ref, api, childColliderProps];
792
+ }; // Joints
791
793
 
792
- if (options.mass !== undefined) {
793
- if (options.massProperties !== undefined) {
794
- throw new Error(massPropertiesConflictError);
794
+ const useImpulseJoint = (body1, body2, params) => {
795
+ const {
796
+ world
797
+ } = useRapier();
798
+ const jointRef = React.useRef();
799
+ const getJointRef = React.useRef(() => {
800
+ if (!jointRef.current) {
801
+ let rb1;
802
+ let rb2;
803
+
804
+ if ("current" in body1 && body1.current && "current" in body2 && body2.current) {
805
+ rb1 = world.getRigidBody(body1.current.handle);
806
+ rb2 = world.getRigidBody(body2.current.handle);
807
+ const newJoint = world.createImpulseJoint(params, rb1, rb2);
808
+ jointRef.current = newJoint;
809
+ }
795
810
  }
796
811
 
797
- collider.setMass(options.mass);
798
- return;
799
- }
812
+ return jointRef.current;
813
+ });
814
+ React.useEffect(() => {
815
+ const joint = getJointRef.current();
816
+ return () => {
817
+ if (joint) {
818
+ world.removeImpulseJoint(joint);
819
+ jointRef.current = undefined;
820
+ }
821
+ };
822
+ }, []);
823
+ const api = React.useMemo(() => createJointApi(getJointRef), []);
824
+ return api;
825
+ };
826
+ /**
827
+ *
828
+ * A fixed joint ensures that two rigid-bodies don't move relative to each other.
829
+ * Fixed joints are characterized by one local frame (represented by an isometry) on each rigid-body.
830
+ * The fixed-joint makes these frames coincide in world-space.
831
+ */
800
832
 
801
- if (options.massProperties !== undefined) {
802
- collider.setMassProperties(options.massProperties.mass, options.massProperties.centerOfMass, options.massProperties.principalAngularInertia, options.massProperties.angularInertiaLocalFrame);
803
- }
833
+ const useFixedJoint = (body1, body2, [body1Anchor, body1LocalFrame, body2Anchor, body2LocalFrame]) => {
834
+ const {
835
+ rapier
836
+ } = useRapier();
837
+ return useImpulseJoint(body1, body2, rapier.JointData.fixed(vectorArrayToVector3(body1Anchor), _objectSpread2(_objectSpread2({}, vectorArrayToVector3(body1LocalFrame)), {}, {
838
+ w: 1
839
+ }), vectorArrayToVector3(body2Anchor), _objectSpread2(_objectSpread2({}, vectorArrayToVector3(body2LocalFrame)), {}, {
840
+ w: 1
841
+ })));
804
842
  };
843
+ /**
844
+ * The spherical joint ensures that two points on the local-spaces of two rigid-bodies always coincide (it prevents any relative
845
+ * translational motion at this points). This is typically used to simulate ragdolls arms, pendulums, etc.
846
+ * They are characterized by one local anchor on each rigid-body. Each anchor represents the location of the
847
+ * points that need to coincide on the local-space of each rigid-body.
848
+ */
805
849
 
806
- const mutableColliderOptions = {
807
- sensor: (collider, value) => {
808
- collider.setSensor(value);
809
- },
810
- collisionGroups: (collider, value) => {
811
- collider.setCollisionGroups(value);
812
- },
813
- solverGroups: (collider, value) => {
814
- collider.setSolverGroups(value);
815
- },
816
- friction: (collider, value) => {
817
- collider.setFriction(value);
818
- },
819
- frictionCombineRule: (collider, value) => {
820
- collider.setFrictionCombineRule(value);
821
- },
822
- restitution: (collider, value) => {
823
- collider.setRestitution(value);
824
- },
825
- restitutionCombineRule: (collider, value) => {
826
- collider.setRestitutionCombineRule(value);
827
- },
828
- // To make sure the options all mutalbe options are listed
829
- quaternion: () => {},
830
- position: () => {},
831
- rotation: () => {},
832
- scale: () => {}
850
+ const useSphericalJoint = (body1, body2, [body1Anchor, body2Anchor]) => {
851
+ const {
852
+ rapier
853
+ } = useRapier();
854
+ return useImpulseJoint(body1, body2, rapier.JointData.spherical(vectorArrayToVector3(body1Anchor), vectorArrayToVector3(body2Anchor)));
833
855
  };
834
- const mutableColliderOptionKeys = Object.keys(mutableColliderOptions);
835
- const setColliderOptions = (collider, options, states) => {
836
- const state = states.get(collider.handle);
856
+ /**
857
+ * The revolute joint prevents any relative movement between two rigid-bodies, except for relative
858
+ * rotations along one axis. This is typically used to simulate wheels, fans, etc.
859
+ * They are characterized by one local anchor as well as one local axis on each rigid-body.
860
+ */
837
861
 
838
- if (state) {
839
- // Update collider position based on the object's position
840
- const parentWorldScale = state.object.parent.getWorldScale(_vector3);
841
- state.object.updateWorldMatrix(true, false);
862
+ const useRevoluteJoint = (body1, body2, [body1Anchor, body2Anchor, axis]) => {
863
+ const {
864
+ rapier
865
+ } = useRapier();
866
+ return useImpulseJoint(body1, body2, rapier.JointData.revolute(vectorArrayToVector3(body1Anchor), vectorArrayToVector3(body2Anchor), vectorArrayToVector3(axis)));
867
+ };
868
+ /**
869
+ * The prismatic joint prevents any relative movement between two rigid-bodies, except for relative translations along one axis.
870
+ * It is characterized by one local anchor as well as one local axis on each rigid-body. In 3D, an optional
871
+ * local tangent axis can be specified for each rigid-body.
872
+ */
842
873
 
843
- _matrix4.copy(state.object.matrixWorld).premultiply(state.worldParent.matrixWorld.clone().invert()).decompose(_position, _rotation, _scale);
874
+ const usePrismaticJoint = (body1, body2, [body1Anchor, body2Anchor, axis]) => {
875
+ const {
876
+ rapier
877
+ } = useRapier();
878
+ return useImpulseJoint(body1, body2, rapier.JointData.prismatic(vectorArrayToVector3(body1Anchor), vectorArrayToVector3(body2Anchor), vectorArrayToVector3(axis)));
879
+ };
844
880
 
845
- if (collider.parent()) {
846
- collider.setTranslationWrtParent({
847
- x: _position.x * parentWorldScale.x,
848
- y: _position.y * parentWorldScale.y,
849
- z: _position.z * parentWorldScale.z
850
- });
851
- collider.setRotationWrtParent(_rotation);
852
- } else {
853
- collider.setTranslation({
854
- x: _position.x * parentWorldScale.x,
855
- y: _position.y * parentWorldScale.y,
856
- z: _position.z * parentWorldScale.z
857
- });
858
- collider.setRotation(_rotation);
859
- }
881
+ const calcForceByType = {
882
+ static: (s, m2, r, d, G) => s,
883
+ linear: (s, m2, r, d, G) => s * (d / r),
884
+ newtonian: (s, m2, r, d, G) => G * s * m2 / Math.pow(d, 2)
885
+ };
886
+ const applyAttractorForceOnRigidBody = (rigidBody, {
887
+ object,
888
+ strength,
889
+ range,
890
+ gravitationalConstant,
891
+ collisionGroups,
892
+ type
893
+ }) => {
894
+ const rbPosition = rigidBody.translation();
860
895
 
861
- mutableColliderOptionKeys.forEach(key => {
862
- if (key in options) {
863
- const option = options[key];
864
- mutableColliderOptions[key](collider, // @ts-ignore Option does not want to fit into the function, but it will
865
- option, options);
896
+ _position.set(rbPosition.x, rbPosition.y, rbPosition.z);
897
+
898
+ const worldPosition = object.getWorldPosition(new three.Vector3());
899
+ const distance = worldPosition.distanceTo(_position);
900
+
901
+ if (distance < range) {
902
+ let force = calcForceByType[type](strength, rigidBody.mass(), range, distance, gravitationalConstant); // Prevent wild forces when Attractors collide
903
+
904
+ force = force === Infinity ? strength : force; // Naively test if the rigidBody contains a collider in one of the collision groups
905
+
906
+ let isRigidBodyInCollisionGroup = collisionGroups === undefined ? true : false;
907
+
908
+ if (collisionGroups !== undefined) {
909
+ for (let i = 0; i < rigidBody.numColliders(); i++) {
910
+ const collider = rigidBody.collider(i);
911
+ const colliderCollisionGroups = collider.collisionGroups();
912
+
913
+ if ((collisionGroups >> 16 & colliderCollisionGroups) != 0 && (colliderCollisionGroups >> 16 & collisionGroups) != 0) {
914
+ isRigidBodyInCollisionGroup = true;
915
+ break;
916
+ }
866
917
  }
867
- }); // handle mass separately, because the assignments
868
- // are exclusive.
918
+ }
869
919
 
870
- setColliderMassOptions(collider, options);
920
+ if (isRigidBodyInCollisionGroup) {
921
+ _vector3.set(0, 0, 0).subVectors(worldPosition, _position).normalize().multiplyScalar(force);
922
+
923
+ rigidBody.applyImpulse(_vector3, true);
924
+ }
871
925
  }
872
926
  };
873
- const useUpdateColliderOptions = (collidersRef, props, states) => {
874
- // TODO: Improve this, split each prop into its own effect
875
- const mutablePropsAsFlatArray = React.useMemo(() => mutableColliderOptionKeys.flatMap(key => {
876
- return vectorToTuple(props[key]);
877
- }), [props]);
927
+ const Attractor = /*#__PURE__*/React.memo(props => {
928
+ const {
929
+ position = [0, 0, 0],
930
+ strength = 1,
931
+ range = 10,
932
+ type = "static",
933
+ gravitationalConstant = 6.673e-11,
934
+ collisionGroups
935
+ } = props;
936
+ const {
937
+ attractorStates
938
+ } = useRapier();
939
+ const object = React.useRef(null);
878
940
  React.useEffect(() => {
879
- collidersRef.current.forEach(collider => {
880
- setColliderOptions(collider, props, states);
881
- });
882
- }, mutablePropsAsFlatArray);
883
- };
941
+ var _object$current;
942
+
943
+ let uuid = ((_object$current = object.current) === null || _object$current === void 0 ? void 0 : _object$current.uuid) || "_";
944
+
945
+ if (object.current) {
946
+ attractorStates.set(uuid, {
947
+ object: object.current,
948
+ strength,
949
+ range,
950
+ type,
951
+ gravitationalConstant,
952
+ collisionGroups
953
+ });
954
+ }
884
955
 
885
- const isChildOfMeshCollider = child => {
886
- let flag = false;
887
- child.traverseAncestors(a => {
888
- if (a.userData.r3RapierType === "MeshCollider") flag = true;
956
+ return () => {
957
+ attractorStates.delete(uuid);
958
+ };
959
+ }, [props]);
960
+ return /*#__PURE__*/React__default["default"].createElement("object3D", {
961
+ ref: object,
962
+ position: position
889
963
  });
890
- return flag;
891
- };
964
+ });
965
+
966
+ const RapierContext = /*#__PURE__*/React.createContext(undefined);
967
+
968
+ const getCollisionPayloadFromSource = (target, other) => {
969
+ var _target$collider$stat, _target$rigidBody$sta, _other$collider$state, _other$rigidBody$stat, _other$collider$state2, _other$rigidBody$stat2;
892
970
 
893
- const createColliderState = (collider, object, rigidBodyObject) => {
894
971
  return {
895
- collider,
896
- worldParent: rigidBodyObject || object.parent,
897
- object
972
+ target: {
973
+ rigidBody: target.rigidBody.object,
974
+ collider: target.collider.object,
975
+ colliderObject: (_target$collider$stat = target.collider.state) === null || _target$collider$stat === void 0 ? void 0 : _target$collider$stat.object,
976
+ rigidBodyObject: (_target$rigidBody$sta = target.rigidBody.state) === null || _target$rigidBody$sta === void 0 ? void 0 : _target$rigidBody$sta.object
977
+ },
978
+ other: {
979
+ rigidBody: other.rigidBody.object,
980
+ collider: other.collider.object,
981
+ colliderObject: (_other$collider$state = other.collider.state) === null || _other$collider$state === void 0 ? void 0 : _other$collider$state.object,
982
+ rigidBodyObject: (_other$rigidBody$stat = other.rigidBody.state) === null || _other$rigidBody$stat === void 0 ? void 0 : _other$rigidBody$stat.object
983
+ },
984
+ rigidBody: other.rigidBody.object,
985
+ collider: other.collider.object,
986
+ colliderObject: (_other$collider$state2 = other.collider.state) === null || _other$collider$state2 === void 0 ? void 0 : _other$collider$state2.object,
987
+ rigidBodyObject: (_other$rigidBody$stat2 = other.rigidBody.state) === null || _other$rigidBody$stat2 === void 0 ? void 0 : _other$rigidBody$stat2.object
898
988
  };
899
989
  };
900
- const autoColliderMap = {
901
- cuboid: "cuboid",
902
- ball: "ball",
903
- hull: "convexHull",
904
- trimesh: "trimesh"
990
+
991
+ const importRapier = async () => {
992
+ let r = await Promise.resolve().then(function () { return /*#__PURE__*/_interopNamespace(require('@dimforge/rapier3d-compat')); });
993
+ await r.init();
994
+ return r;
905
995
  };
906
- const createColliderPropsFromChildren = ({
907
- object,
908
- ignoreMeshColliders: _ignoreMeshColliders = true,
909
- options
996
+
997
+ const Physics = ({
998
+ colliders: _colliders = "cuboid",
999
+ gravity: _gravity = [0, -9.81, 0],
1000
+ children,
1001
+ timeStep: _timeStep = 1 / 60,
1002
+ paused: _paused = false,
1003
+ updatePriority,
1004
+ interpolate: _interpolate = true
910
1005
  }) => {
911
- const colliderProps = [];
912
- object.updateWorldMatrix(true, false);
913
- const invertedParentMatrixWorld = object.matrixWorld.clone().invert();
1006
+ const rapier = useAsset.useAsset(importRapier);
1007
+ const worldRef = React.useRef();
1008
+ const getWorldRef = React.useRef(() => {
1009
+ if (!worldRef.current) {
1010
+ const world = new rapier.World(vectorArrayToVector3(_gravity));
1011
+ worldRef.current = world;
1012
+ }
914
1013
 
915
- const colliderFromChild = child => {
916
- if ("isMesh" in child) {
917
- if (_ignoreMeshColliders && isChildOfMeshCollider(child)) return;
918
- const worldScale = child.getWorldScale(_scale);
919
- const shape = autoColliderMap[options.colliders || "cuboid"];
920
- child.updateWorldMatrix(true, false);
1014
+ return worldRef.current;
1015
+ });
1016
+ const [rigidBodyStates] = React.useState(() => new Map());
1017
+ const [colliderStates] = React.useState(() => new Map());
1018
+ const [rigidBodyEvents] = React.useState(() => new Map());
1019
+ const [colliderEvents] = React.useState(() => new Map());
1020
+ const [eventQueue] = React.useState(() => new rapier3dCompat.EventQueue(false));
1021
+ const [attractorStates] = React.useState(() => new Map()); // Init world
921
1022
 
922
- _matrix4.copy(child.matrixWorld).premultiply(invertedParentMatrixWorld).decompose(_position, _rotation, _scale);
1023
+ React.useEffect(() => {
1024
+ const world = getWorldRef.current();
1025
+ return () => {
1026
+ if (world) {
1027
+ world.free();
1028
+ worldRef.current = undefined;
1029
+ }
1030
+ };
1031
+ }, []); // Update gravity
923
1032
 
924
- const rotationEuler = new three.Euler().setFromQuaternion(_rotation, "XYZ");
925
- const {
926
- geometry
927
- } = child;
928
- const {
929
- args,
930
- offset
931
- } = getColliderArgsFromGeometry(geometry, options.colliders || "cuboid");
932
- colliderProps.push(_objectSpread2(_objectSpread2({}, options), {}, {
933
- args: args,
934
- shape: shape,
935
- rotation: [rotationEuler.x, rotationEuler.y, rotationEuler.z],
936
- position: [_position.x + offset.x * worldScale.x, _position.y + offset.y * worldScale.y, _position.z + offset.z * worldScale.z],
937
- scale: [worldScale.x, worldScale.y, worldScale.z]
938
- }));
1033
+ React.useEffect(() => {
1034
+ const world = worldRef.current;
1035
+
1036
+ if (world) {
1037
+ world.gravity = vectorArrayToVector3(_gravity);
939
1038
  }
940
- };
1039
+ }, [_gravity]);
1040
+ const getSourceFromColliderHandle = React.useCallback(handle => {
1041
+ const world = worldRef.current;
941
1042
 
942
- if (options.includeInvisible) {
943
- object.traverse(colliderFromChild);
944
- } else {
945
- object.traverseVisible(colliderFromChild);
946
- }
1043
+ if (world) {
1044
+ var _collider$parent;
1045
+
1046
+ const collider = world.getCollider(handle);
1047
+ const colEvents = colliderEvents.get(handle);
1048
+ const colliderState = colliderStates.get(handle);
1049
+ const rigidBodyHandle = collider === null || collider === void 0 ? void 0 : (_collider$parent = collider.parent()) === null || _collider$parent === void 0 ? void 0 : _collider$parent.handle;
1050
+ const rigidBody = rigidBodyHandle !== undefined ? world.getRigidBody(rigidBodyHandle) : undefined;
1051
+ const rbEvents = rigidBody && rigidBodyHandle !== undefined ? rigidBodyEvents.get(rigidBodyHandle) : undefined;
1052
+ const rigidBodyState = rigidBodyHandle !== undefined ? rigidBodyStates.get(rigidBodyHandle) : undefined;
1053
+ const source = {
1054
+ collider: {
1055
+ object: collider,
1056
+ events: colEvents,
1057
+ state: colliderState
1058
+ },
1059
+ rigidBody: {
1060
+ object: rigidBody,
1061
+ events: rbEvents,
1062
+ state: rigidBodyState
1063
+ }
1064
+ };
1065
+ return source;
1066
+ }
1067
+ }, []);
1068
+ const [steppingState] = React.useState({
1069
+ previousState: {},
1070
+ accumulator: 0
1071
+ });
1072
+ const step = React.useCallback(dt => {
1073
+ const world = worldRef.current;
1074
+ if (!world) return;
1075
+ /* Check if the timestep is supposed to be variable. We'll do this here
1076
+ once so we don't have to string-check every frame. */
947
1077
 
948
- return colliderProps;
949
- };
950
- const getColliderArgsFromGeometry = (geometry, colliders) => {
951
- switch (colliders) {
952
- case "cuboid":
953
- {
954
- geometry.computeBoundingBox();
955
- const {
956
- boundingBox
957
- } = geometry;
958
- const size = boundingBox.getSize(new three.Vector3());
959
- return {
960
- args: [size.x / 2, size.y / 2, size.z / 2],
961
- offset: boundingBox.getCenter(new three.Vector3())
962
- };
1078
+ const timeStepVariable = _timeStep === "vary";
1079
+ /**
1080
+ * Fixed timeStep simulation progression
1081
+ * @see https://gafferongames.com/post/fix_your_timestep/
1082
+ */
1083
+
1084
+ const clampedDelta = three.MathUtils.clamp(dt, 0, 0.2);
1085
+
1086
+ if (timeStepVariable) {
1087
+ world.timestep = clampedDelta;
1088
+ world.step(eventQueue);
1089
+ } else {
1090
+ world.timestep = _timeStep; // don't step time forwards if paused
1091
+ // Increase accumulator
1092
+
1093
+ steppingState.accumulator += clampedDelta;
1094
+
1095
+ while (steppingState.accumulator >= _timeStep) {
1096
+ world.forEachRigidBody(body => {
1097
+ // Set up previous state
1098
+ // needed for accurate interpolations if the world steps more than once
1099
+ if (_interpolate) {
1100
+ steppingState.previousState = {};
1101
+ steppingState.previousState[body.handle] = {
1102
+ position: body.translation(),
1103
+ rotation: body.rotation()
1104
+ };
1105
+ } // Apply attractors
1106
+
1107
+
1108
+ attractorStates.forEach(attractorState => {
1109
+ applyAttractorForceOnRigidBody(body, attractorState);
1110
+ });
1111
+ });
1112
+ world.step(eventQueue);
1113
+ steppingState.accumulator -= _timeStep;
963
1114
  }
1115
+ }
964
1116
 
965
- case "ball":
966
- {
967
- geometry.computeBoundingSphere();
968
- const {
969
- boundingSphere
970
- } = geometry;
971
- const radius = boundingSphere.radius;
972
- return {
973
- args: [radius],
974
- offset: boundingSphere.center
975
- };
1117
+ const interpolationAlpha = timeStepVariable || !_interpolate || _paused ? 1 : steppingState.accumulator / _timeStep; // Update meshes
1118
+
1119
+ rigidBodyStates.forEach((state, handle) => {
1120
+ const rigidBody = world.getRigidBody(handle);
1121
+ const events = rigidBodyEvents.get(handle);
1122
+
1123
+ if (events !== null && events !== void 0 && events.onSleep || events !== null && events !== void 0 && events.onWake) {
1124
+ if (rigidBody.isSleeping() && !state.isSleeping) {
1125
+ var _events$onSleep;
1126
+
1127
+ events === null || events === void 0 ? void 0 : (_events$onSleep = events.onSleep) === null || _events$onSleep === void 0 ? void 0 : _events$onSleep.call(events);
1128
+ }
1129
+
1130
+ if (!rigidBody.isSleeping() && state.isSleeping) {
1131
+ var _events$onWake;
1132
+
1133
+ events === null || events === void 0 ? void 0 : (_events$onWake = events.onWake) === null || _events$onWake === void 0 ? void 0 : _events$onWake.call(events);
1134
+ }
1135
+
1136
+ state.isSleeping = rigidBody.isSleeping();
976
1137
  }
977
1138
 
978
- case "trimesh":
979
- {
980
- var _clonedGeometry$index;
1139
+ if (!rigidBody || rigidBody.isSleeping() || !state.setMatrix) {
1140
+ return;
1141
+ } // New states
981
1142
 
982
- const clonedGeometry = geometry.index ? geometry.clone() : threeStdlib.mergeVertices(geometry);
983
- return {
984
- args: [clonedGeometry.attributes.position.array, (_clonedGeometry$index = clonedGeometry.index) === null || _clonedGeometry$index === void 0 ? void 0 : _clonedGeometry$index.array],
985
- offset: new three.Vector3()
986
- };
1143
+
1144
+ let t = rigidBody.translation();
1145
+ let r = rigidBody.rotation();
1146
+ let previousState = steppingState.previousState[handle];
1147
+
1148
+ if (previousState) {
1149
+ // Get previous simulated world position
1150
+ _matrix4.compose(previousState.position, rapierQuaternionToQuaternion(previousState.rotation), state.scale).premultiply(state.invertedWorldMatrix).decompose(_position, _rotation, _scale); // Apply previous tick position
1151
+
1152
+
1153
+ if (!(state.object instanceof three.InstancedMesh)) {
1154
+ state.object.position.copy(_position);
1155
+ state.object.quaternion.copy(_rotation);
1156
+ }
1157
+ } // Get new position
1158
+
1159
+
1160
+ _matrix4.compose(t, rapierQuaternionToQuaternion(r), state.scale).premultiply(state.invertedWorldMatrix).decompose(_position, _rotation, _scale);
1161
+
1162
+ if (state.object instanceof three.InstancedMesh) {
1163
+ state.setMatrix(_matrix4);
1164
+ state.object.instanceMatrix.needsUpdate = true;
1165
+ } else {
1166
+ // Interpolate to new position
1167
+ state.object.position.lerp(_position, interpolationAlpha);
1168
+ state.object.quaternion.slerp(_rotation, interpolationAlpha);
987
1169
  }
1170
+ });
1171
+ eventQueue.drainCollisionEvents((handle1, handle2, started) => {
1172
+ const source1 = getSourceFromColliderHandle(handle1);
1173
+ const source2 = getSourceFromColliderHandle(handle2); // Collision Events
988
1174
 
989
- case "hull":
990
- {
991
- const g = geometry.clone();
992
- return {
993
- args: [g.attributes.position.array],
994
- offset: new three.Vector3()
995
- };
1175
+ if (!(source1 !== null && source1 !== void 0 && source1.collider.object) || !(source2 !== null && source2 !== void 0 && source2.collider.object)) {
1176
+ return;
996
1177
  }
997
- }
998
1178
 
999
- return {
1000
- args: [],
1001
- offset: new three.Vector3()
1002
- };
1003
- };
1004
- const useColliderEvents = (collidersRef, props, events) => {
1005
- const {
1006
- onCollisionEnter,
1007
- onCollisionExit,
1008
- onIntersectionEnter,
1009
- onIntersectionExit
1010
- } = props;
1011
- React.useEffect(() => {
1012
- var _collidersRef$current;
1179
+ const collisionPayload1 = getCollisionPayloadFromSource(source1, source2);
1180
+ const collisionPayload2 = getCollisionPayloadFromSource(source2, source1);
1181
+
1182
+ if (started) {
1183
+ world.contactPair(source1.collider.object, source2.collider.object, (manifold, flipped) => {
1184
+ var _source1$rigidBody$ev, _source1$rigidBody$ev2, _source2$rigidBody$ev, _source2$rigidBody$ev2, _source1$collider$eve, _source1$collider$eve2, _source2$collider$eve, _source2$collider$eve2;
1185
+
1186
+ /* RigidBody events */
1187
+ (_source1$rigidBody$ev = source1.rigidBody.events) === null || _source1$rigidBody$ev === void 0 ? void 0 : (_source1$rigidBody$ev2 = _source1$rigidBody$ev.onCollisionEnter) === null || _source1$rigidBody$ev2 === void 0 ? void 0 : _source1$rigidBody$ev2.call(_source1$rigidBody$ev, _objectSpread2(_objectSpread2({}, collisionPayload1), {}, {
1188
+ manifold,
1189
+ flipped
1190
+ }));
1191
+ (_source2$rigidBody$ev = source2.rigidBody.events) === null || _source2$rigidBody$ev === void 0 ? void 0 : (_source2$rigidBody$ev2 = _source2$rigidBody$ev.onCollisionEnter) === null || _source2$rigidBody$ev2 === void 0 ? void 0 : _source2$rigidBody$ev2.call(_source2$rigidBody$ev, _objectSpread2(_objectSpread2({}, collisionPayload2), {}, {
1192
+ manifold,
1193
+ flipped
1194
+ }));
1195
+ /* Collider events */
1196
+
1197
+ (_source1$collider$eve = source1.collider.events) === null || _source1$collider$eve === void 0 ? void 0 : (_source1$collider$eve2 = _source1$collider$eve.onCollisionEnter) === null || _source1$collider$eve2 === void 0 ? void 0 : _source1$collider$eve2.call(_source1$collider$eve, _objectSpread2(_objectSpread2({}, collisionPayload1), {}, {
1198
+ manifold,
1199
+ flipped
1200
+ }));
1201
+ (_source2$collider$eve = source2.collider.events) === null || _source2$collider$eve === void 0 ? void 0 : (_source2$collider$eve2 = _source2$collider$eve.onCollisionEnter) === null || _source2$collider$eve2 === void 0 ? void 0 : _source2$collider$eve2.call(_source2$collider$eve, _objectSpread2(_objectSpread2({}, collisionPayload2), {}, {
1202
+ manifold,
1203
+ flipped
1204
+ }));
1205
+ });
1206
+ } else {
1207
+ var _source1$rigidBody$ev3, _source1$rigidBody$ev4, _source2$rigidBody$ev3, _source2$rigidBody$ev4, _source1$collider$eve3, _source1$collider$eve4, _source2$collider$eve3, _source2$collider$eve4;
1208
+
1209
+ (_source1$rigidBody$ev3 = source1.rigidBody.events) === null || _source1$rigidBody$ev3 === void 0 ? void 0 : (_source1$rigidBody$ev4 = _source1$rigidBody$ev3.onCollisionExit) === null || _source1$rigidBody$ev4 === void 0 ? void 0 : _source1$rigidBody$ev4.call(_source1$rigidBody$ev3, collisionPayload1);
1210
+ (_source2$rigidBody$ev3 = source2.rigidBody.events) === null || _source2$rigidBody$ev3 === void 0 ? void 0 : (_source2$rigidBody$ev4 = _source2$rigidBody$ev3.onCollisionExit) === null || _source2$rigidBody$ev4 === void 0 ? void 0 : _source2$rigidBody$ev4.call(_source2$rigidBody$ev3, collisionPayload2);
1211
+ (_source1$collider$eve3 = source1.collider.events) === null || _source1$collider$eve3 === void 0 ? void 0 : (_source1$collider$eve4 = _source1$collider$eve3.onCollisionExit) === null || _source1$collider$eve4 === void 0 ? void 0 : _source1$collider$eve4.call(_source1$collider$eve3, collisionPayload1);
1212
+ (_source2$collider$eve3 = source2.collider.events) === null || _source2$collider$eve3 === void 0 ? void 0 : (_source2$collider$eve4 = _source2$collider$eve3.onCollisionExit) === null || _source2$collider$eve4 === void 0 ? void 0 : _source2$collider$eve4.call(_source2$collider$eve3, collisionPayload2);
1213
+ } // Sensor Intersections
1013
1214
 
1014
- (_collidersRef$current = collidersRef.current) === null || _collidersRef$current === void 0 ? void 0 : _collidersRef$current.forEach(collider => {
1015
- if (onCollisionEnter || onCollisionExit || onIntersectionEnter || onIntersectionExit) {
1016
- collider.setActiveEvents(rapier3dCompat.ActiveEvents.COLLISION_EVENTS);
1017
- }
1018
1215
 
1019
- events.set(collider.handle, {
1020
- onCollisionEnter,
1021
- onCollisionExit,
1022
- onIntersectionEnter,
1023
- onIntersectionExit
1024
- });
1216
+ if (started) {
1217
+ if (world.intersectionPair(source1.collider.object, source2.collider.object)) {
1218
+ var _source1$rigidBody$ev5, _source1$rigidBody$ev6, _source2$rigidBody$ev5, _source2$rigidBody$ev6, _source1$collider$eve5, _source1$collider$eve6, _source2$collider$eve5, _source2$collider$eve6;
1219
+
1220
+ (_source1$rigidBody$ev5 = source1.rigidBody.events) === null || _source1$rigidBody$ev5 === void 0 ? void 0 : (_source1$rigidBody$ev6 = _source1$rigidBody$ev5.onIntersectionEnter) === null || _source1$rigidBody$ev6 === void 0 ? void 0 : _source1$rigidBody$ev6.call(_source1$rigidBody$ev5, collisionPayload1);
1221
+ (_source2$rigidBody$ev5 = source2.rigidBody.events) === null || _source2$rigidBody$ev5 === void 0 ? void 0 : (_source2$rigidBody$ev6 = _source2$rigidBody$ev5.onIntersectionEnter) === null || _source2$rigidBody$ev6 === void 0 ? void 0 : _source2$rigidBody$ev6.call(_source2$rigidBody$ev5, collisionPayload2);
1222
+ (_source1$collider$eve5 = source1.collider.events) === null || _source1$collider$eve5 === void 0 ? void 0 : (_source1$collider$eve6 = _source1$collider$eve5.onIntersectionEnter) === null || _source1$collider$eve6 === void 0 ? void 0 : _source1$collider$eve6.call(_source1$collider$eve5, collisionPayload1);
1223
+ (_source2$collider$eve5 = source2.collider.events) === null || _source2$collider$eve5 === void 0 ? void 0 : (_source2$collider$eve6 = _source2$collider$eve5.onIntersectionEnter) === null || _source2$collider$eve6 === void 0 ? void 0 : _source2$collider$eve6.call(_source2$collider$eve5, collisionPayload2);
1224
+ }
1225
+ } else {
1226
+ var _source1$rigidBody$ev7, _source1$rigidBody$ev8, _source2$rigidBody$ev7, _source2$rigidBody$ev8, _source1$collider$eve7, _source1$collider$eve8, _source2$collider$eve7, _source2$collider$eve8;
1227
+
1228
+ (_source1$rigidBody$ev7 = source1.rigidBody.events) === null || _source1$rigidBody$ev7 === void 0 ? void 0 : (_source1$rigidBody$ev8 = _source1$rigidBody$ev7.onIntersectionExit) === null || _source1$rigidBody$ev8 === void 0 ? void 0 : _source1$rigidBody$ev8.call(_source1$rigidBody$ev7, collisionPayload1);
1229
+ (_source2$rigidBody$ev7 = source2.rigidBody.events) === null || _source2$rigidBody$ev7 === void 0 ? void 0 : (_source2$rigidBody$ev8 = _source2$rigidBody$ev7.onIntersectionExit) === null || _source2$rigidBody$ev8 === void 0 ? void 0 : _source2$rigidBody$ev8.call(_source2$rigidBody$ev7, collisionPayload2);
1230
+ (_source1$collider$eve7 = source1.collider.events) === null || _source1$collider$eve7 === void 0 ? void 0 : (_source1$collider$eve8 = _source1$collider$eve7.onIntersectionExit) === null || _source1$collider$eve8 === void 0 ? void 0 : _source1$collider$eve8.call(_source1$collider$eve7, collisionPayload1);
1231
+ (_source2$collider$eve7 = source2.collider.events) === null || _source2$collider$eve7 === void 0 ? void 0 : (_source2$collider$eve8 = _source2$collider$eve7.onIntersectionExit) === null || _source2$collider$eve8 === void 0 ? void 0 : _source2$collider$eve8.call(_source2$collider$eve7, collisionPayload2);
1232
+ }
1025
1233
  });
1026
- return () => {
1027
- var _collidersRef$current2;
1234
+ eventQueue.drainContactForceEvents(event => {
1235
+ var _source1$rigidBody$ev9, _source1$rigidBody$ev10, _source2$rigidBody$ev9, _source2$rigidBody$ev10, _source1$collider$eve9, _source1$collider$eve10, _source2$collider$eve9, _source2$collider$eve10;
1028
1236
 
1029
- (_collidersRef$current2 = collidersRef.current) === null || _collidersRef$current2 === void 0 ? void 0 : _collidersRef$current2.forEach(collider => events.delete(collider.handle));
1030
- };
1031
- }, [onCollisionEnter, onCollisionExit, onIntersectionEnter, onIntersectionExit]);
1032
- };
1237
+ const source1 = getSourceFromColliderHandle(event.collider1());
1238
+ const source2 = getSourceFromColliderHandle(event.collider2()); // Collision Events
1033
1239
 
1034
- const useRapier = () => {
1035
- return React.useContext(RapierContext);
1036
- };
1037
- const useChildColliderProps = (ref, options, ignoreMeshColliders = true) => {
1038
- const [colliderProps, setColliderProps] = React.useState([]);
1039
- React.useEffect(() => {
1040
- const object = ref.current;
1240
+ if (!(source1 !== null && source1 !== void 0 && source1.collider.object) || !(source2 !== null && source2 !== void 0 && source2.collider.object)) {
1241
+ return;
1242
+ }
1041
1243
 
1042
- if (object && options.colliders !== false) {
1043
- setColliderProps(createColliderPropsFromChildren({
1044
- object: ref.current,
1045
- options,
1046
- ignoreMeshColliders
1244
+ const collisionPayload1 = getCollisionPayloadFromSource(source1, source2);
1245
+ const collisionPayload2 = getCollisionPayloadFromSource(source2, source1);
1246
+ (_source1$rigidBody$ev9 = source1.rigidBody.events) === null || _source1$rigidBody$ev9 === void 0 ? void 0 : (_source1$rigidBody$ev10 = _source1$rigidBody$ev9.onContactForce) === null || _source1$rigidBody$ev10 === void 0 ? void 0 : _source1$rigidBody$ev10.call(_source1$rigidBody$ev9, _objectSpread2(_objectSpread2({}, collisionPayload1), {}, {
1247
+ totalForce: event.totalForce(),
1248
+ totalForceMagnitude: event.totalForceMagnitude(),
1249
+ maxForceDirection: event.maxForceDirection(),
1250
+ maxForceMagnitude: event.maxForceMagnitude()
1251
+ }));
1252
+ (_source2$rigidBody$ev9 = source2.rigidBody.events) === null || _source2$rigidBody$ev9 === void 0 ? void 0 : (_source2$rigidBody$ev10 = _source2$rigidBody$ev9.onContactForce) === null || _source2$rigidBody$ev10 === void 0 ? void 0 : _source2$rigidBody$ev10.call(_source2$rigidBody$ev9, _objectSpread2(_objectSpread2({}, collisionPayload2), {}, {
1253
+ totalForce: event.totalForce(),
1254
+ totalForceMagnitude: event.totalForceMagnitude(),
1255
+ maxForceDirection: event.maxForceDirection(),
1256
+ maxForceMagnitude: event.maxForceMagnitude()
1257
+ }));
1258
+ (_source1$collider$eve9 = source1.collider.events) === null || _source1$collider$eve9 === void 0 ? void 0 : (_source1$collider$eve10 = _source1$collider$eve9.onContactForce) === null || _source1$collider$eve10 === void 0 ? void 0 : _source1$collider$eve10.call(_source1$collider$eve9, _objectSpread2(_objectSpread2({}, collisionPayload1), {}, {
1259
+ totalForce: event.totalForce(),
1260
+ totalForceMagnitude: event.totalForceMagnitude(),
1261
+ maxForceDirection: event.maxForceDirection(),
1262
+ maxForceMagnitude: event.maxForceMagnitude()
1263
+ }));
1264
+ (_source2$collider$eve9 = source2.collider.events) === null || _source2$collider$eve9 === void 0 ? void 0 : (_source2$collider$eve10 = _source2$collider$eve9.onContactForce) === null || _source2$collider$eve10 === void 0 ? void 0 : _source2$collider$eve10.call(_source2$collider$eve9, _objectSpread2(_objectSpread2({}, collisionPayload2), {}, {
1265
+ totalForce: event.totalForce(),
1266
+ totalForceMagnitude: event.totalForceMagnitude(),
1267
+ maxForceDirection: event.maxForceDirection(),
1268
+ maxForceMagnitude: event.maxForceMagnitude()
1047
1269
  }));
1048
- }
1049
- }, [options.colliders]);
1050
- return colliderProps;
1051
- };
1052
- const useRigidBody = (options = {}) => {
1053
- const {
1054
- world,
1055
- rigidBodyStates,
1056
- physicsOptions,
1057
- rigidBodyEvents
1058
- } = useRapier();
1059
- const ref = React.useRef();
1060
- const mergedOptions = React.useMemo(() => {
1061
- return _objectSpread2(_objectSpread2(_objectSpread2({}, physicsOptions), options), {}, {
1062
- children: undefined
1063
1270
  });
1064
- }, [physicsOptions, options]);
1065
- const childColliderProps = useChildColliderProps(ref, mergedOptions); // Create rigidbody
1271
+ }, [_paused, _timeStep, _interpolate]);
1272
+ fiber.useFrame((_, dt) => {
1273
+ if (!_paused) step(dt);
1274
+ }, updatePriority);
1275
+ const api = React.useMemo(() => createWorldApi(getWorldRef), []);
1276
+ const context = React.useMemo(() => ({
1277
+ rapier,
1278
+ world: api,
1279
+ physicsOptions: {
1280
+ colliders: _colliders,
1281
+ gravity: _gravity
1282
+ },
1283
+ rigidBodyStates,
1284
+ colliderStates,
1285
+ rigidBodyEvents,
1286
+ colliderEvents,
1287
+ attractorStates,
1288
+ isPaused: _paused,
1289
+ step
1290
+ }), [_paused, step]);
1291
+ return /*#__PURE__*/React__default["default"].createElement(RapierContext.Provider, {
1292
+ value: context
1293
+ }, children);
1294
+ };
1066
1295
 
1067
- const rigidBodyRef = React.useRef();
1068
- const getRigidBodyRef = React.useRef(() => {
1069
- if (!rigidBodyRef.current) {
1070
- const desc = rigidBodyDescFromOptions(options);
1071
- const rigidBody = world.createRigidBody(desc);
1072
- rigidBodyRef.current = world.getRigidBody(rigidBody.handle);
1296
+ function _extends() {
1297
+ _extends = Object.assign ? Object.assign.bind() : function (target) {
1298
+ for (var i = 1; i < arguments.length; i++) {
1299
+ var source = arguments[i];
1300
+
1301
+ for (var key in source) {
1302
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
1303
+ target[key] = source[key];
1304
+ }
1305
+ }
1073
1306
  }
1074
1307
 
1075
- return rigidBodyRef.current;
1076
- }); // Setup
1308
+ return target;
1309
+ };
1310
+ return _extends.apply(this, arguments);
1311
+ }
1077
1312
 
1078
- React.useEffect(() => {
1079
- const rigidBody = getRigidBodyRef.current();
1080
- rigidBodyRef.current = rigidBody;
1313
+ function _objectWithoutPropertiesLoose(source, excluded) {
1314
+ if (source == null) return {};
1315
+ var target = {};
1316
+ var sourceKeys = Object.keys(source);
1317
+ var key, i;
1081
1318
 
1082
- if (!ref.current) {
1083
- ref.current = new three.Object3D();
1084
- } // isSleeping used for onSleep and onWake events
1319
+ for (i = 0; i < sourceKeys.length; i++) {
1320
+ key = sourceKeys[i];
1321
+ if (excluded.indexOf(key) >= 0) continue;
1322
+ target[key] = source[key];
1323
+ }
1085
1324
 
1325
+ return target;
1326
+ }
1086
1327
 
1087
- ref.current.userData.isSleeping = false;
1088
- rigidBodyStates.set(rigidBody.handle, createRigidBodyState({
1089
- rigidBody,
1090
- object: ref.current
1091
- }));
1092
- return () => {
1093
- world.removeRigidBody(rigidBody);
1094
- rigidBodyStates.delete(rigidBody.handle);
1095
- rigidBodyRef.current = undefined;
1096
- };
1097
- }, []);
1098
- useUpdateRigidBodyOptions(rigidBodyRef, mergedOptions, rigidBodyStates);
1099
- useRigidBodyEvents(rigidBodyRef, mergedOptions, rigidBodyEvents);
1100
- const api = React.useMemo(() => createRigidBodyApi(getRigidBodyRef), []);
1101
- return [ref, api, childColliderProps];
1102
- }; // Joints
1328
+ function _objectWithoutProperties(source, excluded) {
1329
+ if (source == null) return {};
1330
+ var target = _objectWithoutPropertiesLoose(source, excluded);
1331
+ var key, i;
1103
1332
 
1104
- const useImpulseJoint = (body1, body2, params) => {
1105
- const {
1106
- world
1107
- } = useRapier();
1108
- const jointRef = React.useRef();
1109
- const getJointRef = React.useRef(() => {
1110
- if (!jointRef.current) {
1111
- let rb1;
1112
- let rb2;
1333
+ if (Object.getOwnPropertySymbols) {
1334
+ var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
1113
1335
 
1114
- if ("current" in body1 && body1.current && "current" in body2 && body2.current) {
1115
- rb1 = world.getRigidBody(body1.current.handle);
1116
- rb2 = world.getRigidBody(body2.current.handle);
1117
- const newJoint = world.createImpulseJoint(params, rb1, rb2);
1118
- jointRef.current = newJoint;
1119
- }
1336
+ for (i = 0; i < sourceSymbolKeys.length; i++) {
1337
+ key = sourceSymbolKeys[i];
1338
+ if (excluded.indexOf(key) >= 0) continue;
1339
+ if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
1340
+ target[key] = source[key];
1120
1341
  }
1342
+ }
1121
1343
 
1122
- return jointRef.current;
1123
- });
1124
- React.useEffect(() => {
1125
- const joint = getJointRef.current();
1126
- return () => {
1127
- if (joint) {
1128
- world.removeImpulseJoint(joint);
1129
- jointRef.current = undefined;
1130
- }
1131
- };
1132
- }, []);
1133
- const api = React.useMemo(() => createJointApi(getJointRef), []);
1134
- return api;
1135
- };
1136
- /**
1137
- *
1138
- * A fixed joint ensures that two rigid-bodies don't move relative to each other.
1139
- * Fixed joints are characterized by one local frame (represented by an isometry) on each rigid-body.
1140
- * The fixed-joint makes these frames coincide in world-space.
1141
- */
1142
-
1143
- const useFixedJoint = (body1, body2, [body1Anchor, body1LocalFrame, body2Anchor, body2LocalFrame]) => {
1144
- const {
1145
- rapier
1146
- } = useRapier();
1147
- return useImpulseJoint(body1, body2, rapier.JointData.fixed(vectorArrayToVector3(body1Anchor), _objectSpread2(_objectSpread2({}, vectorArrayToVector3(body1LocalFrame)), {}, {
1148
- w: 1
1149
- }), vectorArrayToVector3(body2Anchor), _objectSpread2(_objectSpread2({}, vectorArrayToVector3(body2LocalFrame)), {}, {
1150
- w: 1
1151
- })));
1152
- };
1153
- /**
1154
- * The spherical joint ensures that two points on the local-spaces of two rigid-bodies always coincide (it prevents any relative
1155
- * translational motion at this points). This is typically used to simulate ragdolls arms, pendulums, etc.
1156
- * They are characterized by one local anchor on each rigid-body. Each anchor represents the location of the
1157
- * points that need to coincide on the local-space of each rigid-body.
1158
- */
1159
-
1160
- const useSphericalJoint = (body1, body2, [body1Anchor, body2Anchor]) => {
1161
- const {
1162
- rapier
1163
- } = useRapier();
1164
- return useImpulseJoint(body1, body2, rapier.JointData.spherical(vectorArrayToVector3(body1Anchor), vectorArrayToVector3(body2Anchor)));
1165
- };
1166
- /**
1167
- * The revolute joint prevents any relative movement between two rigid-bodies, except for relative
1168
- * rotations along one axis. This is typically used to simulate wheels, fans, etc.
1169
- * They are characterized by one local anchor as well as one local axis on each rigid-body.
1170
- */
1171
-
1172
- const useRevoluteJoint = (body1, body2, [body1Anchor, body2Anchor, axis]) => {
1173
- const {
1174
- rapier
1175
- } = useRapier();
1176
- return useImpulseJoint(body1, body2, rapier.JointData.revolute(vectorArrayToVector3(body1Anchor), vectorArrayToVector3(body2Anchor), vectorArrayToVector3(axis)));
1177
- };
1178
- /**
1179
- * The prismatic joint prevents any relative movement between two rigid-bodies, except for relative translations along one axis.
1180
- * It is characterized by one local anchor as well as one local axis on each rigid-body. In 3D, an optional
1181
- * local tangent axis can be specified for each rigid-body.
1182
- */
1183
-
1184
- const usePrismaticJoint = (body1, body2, [body1Anchor, body2Anchor, axis]) => {
1185
- const {
1186
- rapier
1187
- } = useRapier();
1188
- return useImpulseJoint(body1, body2, rapier.JointData.prismatic(vectorArrayToVector3(body1Anchor), vectorArrayToVector3(body2Anchor), vectorArrayToVector3(axis)));
1189
- };
1344
+ return target;
1345
+ }
1190
1346
 
1191
1347
  // Colliders
1192
1348
  const AnyCollider = /*#__PURE__*/React.memo( /*#__PURE__*/React__default["default"].forwardRef((props, forwardedRef) => {
@@ -1195,7 +1351,8 @@ const AnyCollider = /*#__PURE__*/React.memo( /*#__PURE__*/React__default["defaul
1195
1351
  position,
1196
1352
  rotation,
1197
1353
  quaternion,
1198
- scale
1354
+ scale,
1355
+ name
1199
1356
  } = props;
1200
1357
  const {
1201
1358
  world,
@@ -1255,7 +1412,8 @@ const AnyCollider = /*#__PURE__*/React.memo( /*#__PURE__*/React__default["defaul
1255
1412
  rotation: rotation,
1256
1413
  quaternion: quaternion,
1257
1414
  scale: scale,
1258
- ref: ref
1415
+ ref: ref,
1416
+ name: name
1259
1417
  }, children);
1260
1418
  }));
1261
1419
  const CuboidCollider = /*#__PURE__*/React__default["default"].forwardRef((props, ref) => {
@@ -1312,6 +1470,15 @@ const ConvexHullCollider = /*#__PURE__*/React__default["default"].forwardRef((pr
1312
1470
  ref: ref
1313
1471
  }));
1314
1472
  });
1473
+ CuboidCollider.displayName = "CuboidCollider";
1474
+ RoundCuboidCollider.displayName = "RoundCuboidCollider";
1475
+ BallCollider.displayName = "BallCollider";
1476
+ CapsuleCollider.displayName = "CapsuleCollider";
1477
+ HeightfieldCollider.displayName = "HeightfieldCollider";
1478
+ TrimeshCollider.displayName = "TrimeshCollider";
1479
+ ConeCollider.displayName = "ConeCollider";
1480
+ CylinderCollider.displayName = "CylinderCollider";
1481
+ ConvexHullCollider.displayName = "ConvexHullCollider";
1315
1482
 
1316
1483
  const _excluded$1 = ["children", "type", "position", "rotation", "scale", "quaternion"];
1317
1484
  const RigidBodyContext = /*#__PURE__*/React.createContext(undefined);
@@ -1347,6 +1514,7 @@ const RigidBody = /*#__PURE__*/React.memo( /*#__PURE__*/React.forwardRef((props,
1347
1514
  key: index
1348
1515
  }, colliderProps)))));
1349
1516
  }));
1517
+ RigidBody.displayName = "RigidBody";
1350
1518
 
1351
1519
  const MeshCollider = props => {
1352
1520
  const {
@@ -1377,26 +1545,96 @@ const MeshCollider = props => {
1377
1545
  key: index
1378
1546
  }, colliderProps))));
1379
1547
  };
1548
+ MeshCollider.displayName = "MeshCollider";
1549
+
1550
+ function mapsEqual(map1, map2) {
1551
+ var testVal;
1552
+
1553
+ if (map1.size !== map2.size) {
1554
+ return false;
1555
+ }
1556
+
1557
+ for (var [key, val] of map1) {
1558
+ testVal = map2.get(key);
1559
+
1560
+ if (testVal !== val || testVal === undefined && !map2.has(key)) {
1561
+ return false;
1562
+ }
1563
+ }
1564
+
1565
+ return true;
1566
+ }
1567
+
1568
+ const AttractorHelper = props => {
1569
+ const {
1570
+ scene
1571
+ } = fiber.useThree();
1572
+ const ref = React.useRef(null);
1573
+ const normalsHelper = React.useRef();
1574
+ const color = props.strength > 0 ? 0x0000ff : 0xff0000;
1575
+ React.useEffect(() => {
1576
+ if (ref.current) {
1577
+ normalsHelper.current = new threeStdlib.VertexNormalsHelper(ref.current, props.range, color);
1578
+ normalsHelper.current.frustumCulled = false;
1579
+ scene.add(normalsHelper.current);
1580
+ }
1581
+
1582
+ return () => {
1583
+ if (normalsHelper.current) {
1584
+ scene.remove(normalsHelper.current);
1585
+ }
1586
+ };
1587
+ }, [props]);
1588
+ fiber.useFrame(() => {
1589
+ if (ref.current) {
1590
+ var _normalsHelper$curren;
1591
+
1592
+ const worldPosition = props.object.getWorldPosition(_vector3);
1593
+ ref.current.position.copy(worldPosition);
1594
+ (_normalsHelper$curren = normalsHelper.current) === null || _normalsHelper$curren === void 0 ? void 0 : _normalsHelper$curren.update();
1595
+ }
1596
+ });
1597
+ return /*#__PURE__*/React__default["default"].createElement("mesh", {
1598
+ ref: ref,
1599
+ position: props.object.position,
1600
+ frustumCulled: false
1601
+ }, /*#__PURE__*/React__default["default"].createElement("sphereGeometry", {
1602
+ args: [0.2, 6, 6]
1603
+ }), /*#__PURE__*/React__default["default"].createElement("meshBasicMaterial", {
1604
+ color: color,
1605
+ wireframe: true
1606
+ }));
1607
+ };
1380
1608
 
1381
1609
  const Debug = () => {
1382
1610
  const {
1383
- world
1611
+ world,
1612
+ attractorStates
1384
1613
  } = useRapier();
1385
1614
  const ref = React.useRef(null);
1615
+ const [attractors, setAttractors] = React.useState([]);
1616
+ const currMap = React.useRef(new Map());
1386
1617
  fiber.useFrame(() => {
1387
1618
  const mesh = ref.current;
1388
1619
  if (!mesh) return;
1389
1620
  const buffers = world.debugRender();
1390
1621
  mesh.geometry.setAttribute("position", new three.BufferAttribute(buffers.vertices, 3));
1391
- mesh.geometry.setAttribute("color", new three.BufferAttribute(buffers.colors, 4));
1622
+ mesh.geometry.setAttribute("color", new three.BufferAttribute(buffers.colors, 4)); // Update attractors
1623
+
1624
+ if (!mapsEqual(currMap.current, attractorStates)) {
1625
+ setAttractors([...attractorStates.values()]);
1626
+ currMap.current = new Map(attractorStates);
1627
+ }
1392
1628
  });
1393
- return /*#__PURE__*/React__default["default"].createElement("lineSegments", {
1629
+ return /*#__PURE__*/React__default["default"].createElement("group", null, /*#__PURE__*/React__default["default"].createElement("lineSegments", {
1394
1630
  ref: ref,
1395
1631
  frustumCulled: false
1396
1632
  }, /*#__PURE__*/React__default["default"].createElement("lineBasicMaterial", {
1397
1633
  color: 0xffffff,
1398
1634
  vertexColors: true
1399
- }), /*#__PURE__*/React__default["default"].createElement("bufferGeometry", null));
1635
+ }), /*#__PURE__*/React__default["default"].createElement("bufferGeometry", null)), attractors.map((attractor, i) => /*#__PURE__*/React__default["default"].createElement(AttractorHelper, _extends({
1636
+ key: attractor.object.uuid
1637
+ }, attractor))));
1400
1638
  };
1401
1639
 
1402
1640
  const _excluded = ["positions", "rotations", "children"];
@@ -1509,6 +1747,7 @@ const InstancedRigidBodies = /*#__PURE__*/React.forwardRef((props, ref) => {
1509
1747
  key: index
1510
1748
  }, colliderProps)))));
1511
1749
  });
1750
+ InstancedRigidBodies.displayName = "InstancedRigidBodies";
1512
1751
 
1513
1752
  /**
1514
1753
  * Calculates an InteractionGroup bitmask for use in the `collisionGroups` or `solverGroups`
@@ -1559,6 +1798,7 @@ Object.defineProperty(exports, 'RapierRigidBody', {
1559
1798
  get: function () { return rapier3dCompat.RigidBody; }
1560
1799
  });
1561
1800
  exports.AnyCollider = AnyCollider;
1801
+ exports.Attractor = Attractor;
1562
1802
  exports.BallCollider = BallCollider;
1563
1803
  exports.CapsuleCollider = CapsuleCollider;
1564
1804
  exports.ConeCollider = ConeCollider;