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