@react-three/rapier 0.9.0 → 0.10.0

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