@react-three/rapier 0.9.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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,1076 @@ 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
+ lockRotations: (rb, value) => {
599
+ rb.lockRotations(value, true);
747
600
  },
748
- restitutionCombineRule: (collider, value) => {
749
- collider.setRestitutionCombineRule(value);
601
+ lockTranslations: (rb, value) => {
602
+ rb.lockTranslations(value, true);
603
+ },
604
+ angularVelocity: (rb, [x, y, z]) => {
605
+ rb.setAngvel({
606
+ x,
607
+ y,
608
+ z
609
+ }, true);
610
+ },
611
+ linearVelocity: (rb, [x, y, z]) => {
612
+ rb.setLinvel({
613
+ x,
614
+ y,
615
+ z
616
+ }, true);
617
+ },
618
+ ccd: (rb, value) => {
619
+ rb.enableCcd(value);
620
+ },
621
+ userData: (rb, value) => {
622
+ rb.userData = value;
750
623
  },
751
- // To make sure the options all mutalbe options are listed
752
- quaternion: () => {},
753
624
  position: () => {},
754
625
  rotation: () => {},
626
+ quaternion: () => {},
755
627
  scale: () => {}
756
628
  };
757
- const mutableColliderOptionKeys = Object.keys(mutableColliderOptions);
758
- const setColliderOptions = (collider, options, states) => {
759
- const state = states.get(collider.handle);
629
+ const mutableRigidBodyOptionKeys = Object.keys(mutableRigidBodyOptions);
630
+ const setRigidBodyOptions = (rigidBody, options, states, updateTranslations = true) => {
631
+ if (!rigidBody) {
632
+ return;
633
+ }
634
+
635
+ const state = states.get(rigidBody.handle);
760
636
 
761
637
  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);
638
+ if (updateTranslations) {
639
+ state.object.updateWorldMatrix(true, false);
765
640
 
766
- _matrix4.copy(state.object.matrixWorld).premultiply(state.worldParent.matrixWorld.clone().invert()).decompose(_position, _rotation, _scale);
641
+ _matrix4.copy(state.object.matrixWorld).decompose(_position, _rotation, _scale);
767
642
 
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);
643
+ rigidBody.setTranslation(_position, false);
644
+ rigidBody.setRotation(_rotation, false);
782
645
  }
783
646
 
784
- mutableColliderOptionKeys.forEach(key => {
647
+ mutableRigidBodyOptionKeys.forEach(key => {
785
648
  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);
649
+ mutableRigidBodyOptions[key](rigidBody, options[key]);
789
650
  }
790
- }); // handle mass separately, because the assignments
791
- // are exclusive.
792
-
793
- setColliderMassOptions(collider, options);
651
+ });
794
652
  }
795
653
  };
796
- const useUpdateColliderOptions = (collidersRef, props, states) => {
654
+ const useUpdateRigidBodyOptions = (rigidBodyRef, props, states, updateTranslations = true) => {
797
655
  // TODO: Improve this, split each prop into its own effect
798
- const mutablePropsAsFlatArray = useMemo(() => mutableColliderOptionKeys.flatMap(key => {
656
+ const mutablePropsAsFlatArray = useMemo(() => mutableRigidBodyOptionKeys.flatMap(key => {
799
657
  return vectorToTuple(props[key]);
800
658
  }), [props]);
801
659
  useEffect(() => {
802
- collidersRef.current.forEach(collider => {
803
- setColliderOptions(collider, props, states);
804
- });
660
+ if (Array.isArray(rigidBodyRef.current)) {
661
+ for (const rigidBody of rigidBodyRef.current) {
662
+ setRigidBodyOptions(rigidBody, props, states, updateTranslations);
663
+ }
664
+ } else if (rigidBodyRef.current) {
665
+ setRigidBodyOptions(rigidBodyRef.current, props, states, updateTranslations);
666
+ }
805
667
  }, mutablePropsAsFlatArray);
806
668
  };
669
+ const useRigidBodyEvents = (rigidBodyRef, props, events) => {
670
+ const {
671
+ onWake,
672
+ onSleep,
673
+ onCollisionEnter,
674
+ onCollisionExit,
675
+ onIntersectionEnter,
676
+ onIntersectionExit
677
+ } = props;
678
+ const eventHandlers = {
679
+ onWake,
680
+ onSleep,
681
+ onCollisionEnter,
682
+ onCollisionExit,
683
+ onIntersectionEnter,
684
+ onIntersectionExit
685
+ };
686
+ useEffect(() => {
687
+ if (Array.isArray(rigidBodyRef.current)) {
688
+ for (const rigidBody of rigidBodyRef.current) {
689
+ events.set(rigidBody.handle, eventHandlers);
690
+ }
691
+ } else if (rigidBodyRef.current) {
692
+ events.set(rigidBodyRef.current.handle, eventHandlers);
693
+ }
807
694
 
808
- const isChildOfMeshCollider = child => {
809
- let flag = false;
810
- child.traverseAncestors(a => {
811
- if (a.userData.r3RapierType === "MeshCollider") flag = true;
812
- });
813
- return flag;
695
+ return () => {
696
+ if (Array.isArray(rigidBodyRef.current)) {
697
+ for (const rigidBody of rigidBodyRef.current) {
698
+ events.delete(rigidBody.handle);
699
+ }
700
+ } else if (rigidBodyRef.current) {
701
+ events.delete(rigidBodyRef.current.handle);
702
+ }
703
+ };
704
+ }, [onWake, onSleep, onCollisionEnter, onCollisionExit, onIntersectionEnter, onIntersectionExit]);
814
705
  };
815
706
 
816
- const createColliderState = (collider, object, rigidBodyObject) => {
817
- return {
818
- collider,
819
- worldParent: rigidBodyObject || object.parent,
820
- object
821
- };
822
- };
823
- const autoColliderMap = {
824
- cuboid: "cuboid",
825
- ball: "ball",
826
- hull: "convexHull",
827
- trimesh: "trimesh"
707
+ const useRapier = () => {
708
+ return useContext(RapierContext);
828
709
  };
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();
837
-
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);
844
-
845
- _matrix4.copy(child.matrixWorld).premultiply(invertedParentMatrixWorld).decompose(_position, _rotation, _scale);
710
+ const useChildColliderProps = (ref, options, ignoreMeshColliders = true) => {
711
+ const [colliderProps, setColliderProps] = useState([]);
712
+ useEffect(() => {
713
+ const object = ref.current;
846
714
 
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]
715
+ if (object && options.colliders !== false) {
716
+ setColliderProps(createColliderPropsFromChildren({
717
+ object: ref.current,
718
+ options,
719
+ ignoreMeshColliders
861
720
  }));
862
721
  }
863
- };
864
-
865
- if (options.includeInvisible) {
866
- object.traverse(colliderFromChild);
867
- } else {
868
- object.traverseVisible(colliderFromChild);
869
- }
870
-
722
+ }, [options.colliders]);
871
723
  return colliderProps;
872
724
  };
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
- }
725
+ const useRigidBody = (options = {}) => {
726
+ const {
727
+ world,
728
+ rigidBodyStates,
729
+ physicsOptions,
730
+ rigidBodyEvents
731
+ } = useRapier();
732
+ const ref = useRef();
733
+ const mergedOptions = useMemo(() => {
734
+ return _objectSpread2(_objectSpread2(_objectSpread2({}, physicsOptions), options), {}, {
735
+ children: undefined
736
+ });
737
+ }, [physicsOptions, options]);
738
+ const childColliderProps = useChildColliderProps(ref, mergedOptions); // Create rigidbody
887
739
 
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
- }
740
+ const rigidBodyRef = useRef();
741
+ const getRigidBodyRef = useRef(() => {
742
+ if (!rigidBodyRef.current) {
743
+ const desc = rigidBodyDescFromOptions(options);
744
+ const rigidBody = world.createRigidBody(desc);
745
+ rigidBodyRef.current = world.getRigidBody(rigidBody.handle);
746
+ }
900
747
 
901
- case "trimesh":
902
- {
903
- var _clonedGeometry$index;
748
+ return rigidBodyRef.current;
749
+ }); // Setup
904
750
 
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
- }
751
+ useEffect(() => {
752
+ const rigidBody = getRigidBodyRef.current();
753
+ rigidBodyRef.current = rigidBody;
911
754
 
912
- case "hull":
913
- {
914
- const g = geometry.clone();
915
- return {
916
- args: [g.attributes.position.array],
917
- offset: new Vector3()
918
- };
919
- }
920
- }
755
+ if (!ref.current) {
756
+ ref.current = new Object3D();
757
+ }
921
758
 
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;
759
+ rigidBodyStates.set(rigidBody.handle, createRigidBodyState({
760
+ rigidBody,
761
+ object: ref.current
762
+ }));
763
+ return () => {
764
+ world.removeRigidBody(rigidBody);
765
+ rigidBodyStates.delete(rigidBody.handle);
766
+ rigidBodyRef.current = undefined;
767
+ };
768
+ }, []);
769
+ useUpdateRigidBodyOptions(rigidBodyRef, mergedOptions, rigidBodyStates);
770
+ useRigidBodyEvents(rigidBodyRef, mergedOptions, rigidBodyEvents);
771
+ const api = useMemo(() => createRigidBodyApi(getRigidBodyRef), []);
772
+ return [ref, api, childColliderProps];
773
+ }; // Joints
937
774
 
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;
775
+ const useImpulseJoint = (body1, body2, params) => {
776
+ const {
777
+ world
778
+ } = useRapier();
779
+ const jointRef = useRef();
780
+ const getJointRef = useRef(() => {
781
+ if (!jointRef.current) {
782
+ let rb1;
783
+ let rb2;
941
784
 
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);
785
+ if ("current" in body1 && body1.current && "current" in body2 && body2.current) {
786
+ rb1 = world.getRigidBody(body1.current.handle);
787
+ rb2 = world.getRigidBody(body2.current.handle);
788
+ const newJoint = world.createImpulseJoint(params, rb1, rb2);
789
+ jointRef.current = newJoint;
948
790
  }
791
+ }
949
792
 
950
- events.set(collider.handle, {
951
- onCollisionEnter,
952
- onCollisionExit,
953
- onIntersectionEnter,
954
- onIntersectionExit,
955
- onContactForce
956
- });
957
- });
793
+ return jointRef.current;
794
+ });
795
+ useEffect(() => {
796
+ const joint = getJointRef.current();
958
797
  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));
798
+ if (joint) {
799
+ world.removeImpulseJoint(joint);
800
+ jointRef.current = undefined;
801
+ }
962
802
  };
963
- }, [onCollisionEnter, onCollisionExit, onIntersectionEnter, onIntersectionExit, onContactForce]);
803
+ }, []);
804
+ const api = useMemo(() => createJointApi(getJointRef), []);
805
+ return api;
964
806
  };
965
-
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;
807
+ /**
808
+ *
809
+ * A fixed joint ensures that two rigid-bodies don't move relative to each other.
810
+ * Fixed joints are characterized by one local frame (represented by an isometry) on each rigid-body.
811
+ * The fixed-joint makes these frames coincide in world-space.
812
+ */
813
+
814
+ const useFixedJoint = (body1, body2, [body1Anchor, body1LocalFrame, body2Anchor, body2LocalFrame]) => {
815
+ const {
816
+ rapier
817
+ } = useRapier();
818
+ return useImpulseJoint(body1, body2, rapier.JointData.fixed(vectorArrayToVector3(body1Anchor), _objectSpread2(_objectSpread2({}, vectorArrayToVector3(body1LocalFrame)), {}, {
819
+ w: 1
820
+ }), vectorArrayToVector3(body2Anchor), _objectSpread2(_objectSpread2({}, vectorArrayToVector3(body2LocalFrame)), {}, {
821
+ w: 1
822
+ })));
970
823
  };
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
- };
824
+ /**
825
+ * The spherical joint ensures that two points on the local-spaces of two rigid-bodies always coincide (it prevents any relative
826
+ * translational motion at this points). This is typically used to simulate ragdolls arms, pendulums, etc.
827
+ * They are characterized by one local anchor on each rigid-body. Each anchor represents the location of the
828
+ * points that need to coincide on the local-space of each rigid-body.
829
+ */
830
+
831
+ const useSphericalJoint = (body1, body2, [body1Anchor, body2Anchor]) => {
832
+ const {
833
+ rapier
834
+ } = useRapier();
835
+ return useImpulseJoint(body1, body2, rapier.JointData.spherical(vectorArrayToVector3(body1Anchor), vectorArrayToVector3(body2Anchor)));
991
836
  };
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: () => {}
837
+ /**
838
+ * The revolute joint prevents any relative movement between two rigid-bodies, except for relative
839
+ * rotations along one axis. This is typically used to simulate wheels, fans, etc.
840
+ * They are characterized by one local anchor as well as one local axis on each rigid-body.
841
+ */
842
+
843
+ const useRevoluteJoint = (body1, body2, [body1Anchor, body2Anchor, axis]) => {
844
+ const {
845
+ rapier
846
+ } = useRapier();
847
+ return useImpulseJoint(body1, body2, rapier.JointData.revolute(vectorArrayToVector3(body1Anchor), vectorArrayToVector3(body2Anchor), vectorArrayToVector3(axis)));
1032
848
  };
1033
- const mutableRigidBodyOptionKeys = Object.keys(mutableRigidBodyOptions);
1034
- const setRigidBodyOptions = (rigidBody, options, states, updateTranslations = true) => {
1035
- if (!rigidBody) {
1036
- return;
1037
- }
849
+ /**
850
+ * The prismatic joint prevents any relative movement between two rigid-bodies, except for relative translations along one axis.
851
+ * It is characterized by one local anchor as well as one local axis on each rigid-body. In 3D, an optional
852
+ * local tangent axis can be specified for each rigid-body.
853
+ */
1038
854
 
1039
- const state = states.get(rigidBody.handle);
855
+ const usePrismaticJoint = (body1, body2, [body1Anchor, body2Anchor, axis]) => {
856
+ const {
857
+ rapier
858
+ } = useRapier();
859
+ return useImpulseJoint(body1, body2, rapier.JointData.prismatic(vectorArrayToVector3(body1Anchor), vectorArrayToVector3(body2Anchor), vectorArrayToVector3(axis)));
860
+ };
1040
861
 
1041
- if (state) {
1042
- if (updateTranslations) {
1043
- state.object.updateWorldMatrix(true, false);
862
+ const calcForceByType = {
863
+ static: (s, m2, r, d, G) => s,
864
+ linear: (s, m2, r, d, G) => s * (d / r),
865
+ newtonian: (s, m2, r, d, G) => G * s * m2 / Math.pow(d, 2)
866
+ };
867
+ const applyAttractorForceOnRigidBody = (rigidBody, {
868
+ object,
869
+ strength,
870
+ range,
871
+ gravitationalConstant,
872
+ collisionGroups,
873
+ type
874
+ }) => {
875
+ const rbPosition = rigidBody.translation();
1044
876
 
1045
- _matrix4.copy(state.object.matrixWorld).decompose(_position, _rotation, _scale);
877
+ _position.set(rbPosition.x, rbPosition.y, rbPosition.z);
1046
878
 
1047
- rigidBody.setTranslation(_position, false);
1048
- rigidBody.setRotation(_rotation, false);
1049
- }
879
+ const worldPosition = object.getWorldPosition(new Vector3());
880
+ const distance = worldPosition.distanceTo(_position);
1050
881
 
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);
882
+ if (distance < range) {
883
+ let force = calcForceByType[type](strength, rigidBody.mass(), range, distance, gravitationalConstant); // Prevent wild forces when Attractors collide
884
+
885
+ force = force === Infinity ? strength : force; // Naively test if the rigidBody contains a collider in one of the collision groups
886
+
887
+ let isRigidBodyInCollisionGroup = collisionGroups === undefined ? true : false;
888
+
889
+ if (collisionGroups !== undefined) {
890
+ for (let i = 0; i < rigidBody.numColliders(); i++) {
891
+ const collider = rigidBody.collider(i);
892
+ const colliderCollisionGroups = collider.collisionGroups();
893
+
894
+ if ((collisionGroups >> 16 & colliderCollisionGroups) != 0 && (colliderCollisionGroups >> 16 & collisionGroups) != 0) {
895
+ isRigidBodyInCollisionGroup = true;
896
+ break;
897
+ }
1067
898
  }
1068
- } else if (rigidBodyRef.current) {
1069
- setRigidBodyOptions(rigidBodyRef.current, props, states, updateTranslations);
1070
899
  }
1071
- }, mutablePropsAsFlatArray);
900
+
901
+ if (isRigidBodyInCollisionGroup) {
902
+ _vector3.set(0, 0, 0).subVectors(worldPosition, _position).normalize().multiplyScalar(force);
903
+
904
+ rigidBody.applyImpulse(_vector3, true);
905
+ }
906
+ }
1072
907
  };
1073
- const useRigidBodyEvents = (rigidBodyRef, props, events) => {
908
+ const Attractor = /*#__PURE__*/memo(props => {
1074
909
  const {
1075
- onWake,
1076
- onSleep,
1077
- onCollisionEnter,
1078
- onCollisionExit,
1079
- onIntersectionEnter,
1080
- onIntersectionExit
910
+ position = [0, 0, 0],
911
+ strength = 1,
912
+ range = 10,
913
+ type = "static",
914
+ gravitationalConstant = 6.673e-11,
915
+ collisionGroups
1081
916
  } = props;
1082
- const eventHandlers = {
1083
- onWake,
1084
- onSleep,
1085
- onCollisionEnter,
1086
- onCollisionExit,
1087
- onIntersectionEnter,
1088
- onIntersectionExit
1089
- };
917
+ const {
918
+ attractorStates
919
+ } = useRapier();
920
+ const object = useRef(null);
1090
921
  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);
922
+ var _object$current;
923
+
924
+ let uuid = ((_object$current = object.current) === null || _object$current === void 0 ? void 0 : _object$current.uuid) || "_";
925
+
926
+ if (object.current) {
927
+ attractorStates.set(uuid, {
928
+ object: object.current,
929
+ strength,
930
+ range,
931
+ type,
932
+ gravitationalConstant,
933
+ collisionGroups
934
+ });
1097
935
  }
1098
936
 
1099
937
  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
- }
938
+ attractorStates.delete(uuid);
1107
939
  };
1108
- }, [onWake, onSleep, onCollisionEnter, onCollisionExit, onIntersectionEnter, onIntersectionExit]);
940
+ }, [props]);
941
+ return /*#__PURE__*/React.createElement("object3D", {
942
+ ref: object,
943
+ position: position
944
+ });
945
+ });
946
+
947
+ const RapierContext = /*#__PURE__*/createContext(undefined);
948
+
949
+ const getCollisionPayloadFromSource = (target, other) => {
950
+ var _target$collider$stat, _target$rigidBody$sta, _other$collider$state, _other$rigidBody$stat, _other$collider$state2, _other$rigidBody$stat2;
951
+
952
+ return {
953
+ target: {
954
+ rigidBody: target.rigidBody.object,
955
+ collider: target.collider.object,
956
+ colliderObject: (_target$collider$stat = target.collider.state) === null || _target$collider$stat === void 0 ? void 0 : _target$collider$stat.object,
957
+ rigidBodyObject: (_target$rigidBody$sta = target.rigidBody.state) === null || _target$rigidBody$sta === void 0 ? void 0 : _target$rigidBody$sta.object
958
+ },
959
+ other: {
960
+ rigidBody: other.rigidBody.object,
961
+ collider: other.collider.object,
962
+ colliderObject: (_other$collider$state = other.collider.state) === null || _other$collider$state === void 0 ? void 0 : _other$collider$state.object,
963
+ rigidBodyObject: (_other$rigidBody$stat = other.rigidBody.state) === null || _other$rigidBody$stat === void 0 ? void 0 : _other$rigidBody$stat.object
964
+ },
965
+ rigidBody: other.rigidBody.object,
966
+ collider: other.collider.object,
967
+ colliderObject: (_other$collider$state2 = other.collider.state) === null || _other$collider$state2 === void 0 ? void 0 : _other$collider$state2.object,
968
+ rigidBodyObject: (_other$rigidBody$stat2 = other.rigidBody.state) === null || _other$rigidBody$stat2 === void 0 ? void 0 : _other$rigidBody$stat2.object
969
+ };
1109
970
  };
1110
971
 
1111
- const useRapier = () => {
1112
- return useContext(RapierContext);
972
+ const importRapier = async () => {
973
+ let r = await import('@dimforge/rapier3d-compat');
974
+ await r.init();
975
+ return r;
1113
976
  };
1114
- const useChildColliderProps = (ref, options, ignoreMeshColliders = true) => {
1115
- const [colliderProps, setColliderProps] = useState([]);
977
+
978
+ const Physics = ({
979
+ colliders: _colliders = "cuboid",
980
+ gravity: _gravity = [0, -9.81, 0],
981
+ children,
982
+ timeStep: _timeStep = 1 / 60,
983
+ paused: _paused = false,
984
+ updatePriority,
985
+ interpolate: _interpolate = true
986
+ }) => {
987
+ const rapier = useAsset(importRapier);
988
+ const worldRef = useRef();
989
+ const getWorldRef = useRef(() => {
990
+ if (!worldRef.current) {
991
+ const world = new rapier.World(vectorArrayToVector3(_gravity));
992
+ worldRef.current = world;
993
+ }
994
+
995
+ return worldRef.current;
996
+ });
997
+ const [rigidBodyStates] = useState(() => new Map());
998
+ const [colliderStates] = useState(() => new Map());
999
+ const [rigidBodyEvents] = useState(() => new Map());
1000
+ const [colliderEvents] = useState(() => new Map());
1001
+ const [eventQueue] = useState(() => new EventQueue(false));
1002
+ const [attractorStates] = useState(() => new Map()); // Init world
1003
+
1116
1004
  useEffect(() => {
1117
- const object = ref.current;
1005
+ const world = getWorldRef.current();
1006
+ return () => {
1007
+ if (world) {
1008
+ world.free();
1009
+ worldRef.current = undefined;
1010
+ }
1011
+ };
1012
+ }, []); // Update gravity
1118
1013
 
1119
- if (object && options.colliders !== false) {
1120
- setColliderProps(createColliderPropsFromChildren({
1121
- object: ref.current,
1122
- options,
1123
- ignoreMeshColliders
1124
- }));
1014
+ useEffect(() => {
1015
+ const world = worldRef.current;
1016
+
1017
+ if (world) {
1018
+ world.gravity = vectorArrayToVector3(_gravity);
1125
1019
  }
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
1020
+ }, [_gravity]);
1021
+ const getSourceFromColliderHandle = useCallback(handle => {
1022
+ const world = worldRef.current;
1023
+
1024
+ if (world) {
1025
+ var _collider$parent;
1026
+
1027
+ const collider = world.getCollider(handle);
1028
+ const colEvents = colliderEvents.get(handle);
1029
+ const colliderState = colliderStates.get(handle);
1030
+ const rigidBodyHandle = collider === null || collider === void 0 ? void 0 : (_collider$parent = collider.parent()) === null || _collider$parent === void 0 ? void 0 : _collider$parent.handle;
1031
+ const rigidBody = rigidBodyHandle !== undefined ? world.getRigidBody(rigidBodyHandle) : undefined;
1032
+ const rbEvents = rigidBody && rigidBodyHandle !== undefined ? rigidBodyEvents.get(rigidBodyHandle) : undefined;
1033
+ const rigidBodyState = rigidBodyHandle !== undefined ? rigidBodyStates.get(rigidBodyHandle) : undefined;
1034
+ const source = {
1035
+ collider: {
1036
+ object: collider,
1037
+ events: colEvents,
1038
+ state: colliderState
1039
+ },
1040
+ rigidBody: {
1041
+ object: rigidBody,
1042
+ events: rbEvents,
1043
+ state: rigidBodyState
1044
+ }
1045
+ };
1046
+ return source;
1047
+ }
1048
+ }, []);
1049
+ const [steppingState] = useState({
1050
+ previousState: {},
1051
+ accumulator: 0
1052
+ });
1053
+ const step = useCallback(dt => {
1054
+ const world = worldRef.current;
1055
+ if (!world) return;
1056
+ /* Check if the timestep is supposed to be variable. We'll do this here
1057
+ once so we don't have to string-check every frame. */
1058
+
1059
+ const timeStepVariable = _timeStep === "vary";
1060
+ /**
1061
+ * Fixed timeStep simulation progression
1062
+ * @see https://gafferongames.com/post/fix_your_timestep/
1063
+ */
1064
+
1065
+ const clampedDelta = MathUtils.clamp(dt, 0, 0.2);
1066
+
1067
+ if (timeStepVariable) {
1068
+ world.timestep = clampedDelta;
1069
+ world.step(eventQueue);
1070
+ } else {
1071
+ world.timestep = _timeStep; // don't step time forwards if paused
1072
+ // Increase accumulator
1073
+
1074
+ steppingState.accumulator += clampedDelta;
1075
+
1076
+ while (steppingState.accumulator >= _timeStep) {
1077
+ world.forEachRigidBody(body => {
1078
+ // Set up previous state
1079
+ // needed for accurate interpolations if the world steps more than once
1080
+ if (_interpolate) {
1081
+ steppingState.previousState = {};
1082
+ steppingState.previousState[body.handle] = {
1083
+ position: body.translation(),
1084
+ rotation: body.rotation()
1085
+ };
1086
+ } // Apply attractors
1087
+
1088
+
1089
+ attractorStates.forEach(attractorState => {
1090
+ applyAttractorForceOnRigidBody(body, attractorState);
1091
+ });
1092
+ });
1093
+ world.step(eventQueue);
1094
+ steppingState.accumulator -= _timeStep;
1095
+ }
1096
+ }
1097
+
1098
+ const interpolationAlpha = timeStepVariable || !_interpolate || _paused ? 1 : steppingState.accumulator / _timeStep; // Update meshes
1099
+
1100
+ rigidBodyStates.forEach((state, handle) => {
1101
+ const rigidBody = world.getRigidBody(handle);
1102
+ const events = rigidBodyEvents.get(handle);
1103
+
1104
+ if (events !== null && events !== void 0 && events.onSleep || events !== null && events !== void 0 && events.onWake) {
1105
+ if (rigidBody.isSleeping() && !state.isSleeping) {
1106
+ var _events$onSleep;
1107
+
1108
+ events === null || events === void 0 ? void 0 : (_events$onSleep = events.onSleep) === null || _events$onSleep === void 0 ? void 0 : _events$onSleep.call(events);
1109
+ }
1110
+
1111
+ if (!rigidBody.isSleeping() && state.isSleeping) {
1112
+ var _events$onWake;
1113
+
1114
+ events === null || events === void 0 ? void 0 : (_events$onWake = events.onWake) === null || _events$onWake === void 0 ? void 0 : _events$onWake.call(events);
1115
+ }
1116
+
1117
+ state.isSleeping = rigidBody.isSleeping();
1118
+ }
1119
+
1120
+ if (!rigidBody || rigidBody.isSleeping() || !state.setMatrix) {
1121
+ return;
1122
+ } // New states
1123
+
1124
+
1125
+ let t = rigidBody.translation();
1126
+ let r = rigidBody.rotation();
1127
+ let previousState = steppingState.previousState[handle];
1128
+
1129
+ if (previousState) {
1130
+ // Get previous simulated world position
1131
+ _matrix4.compose(previousState.position, rapierQuaternionToQuaternion(previousState.rotation), state.scale).premultiply(state.invertedWorldMatrix).decompose(_position, _rotation, _scale); // Apply previous tick position
1132
+
1133
+
1134
+ if (!(state.object instanceof InstancedMesh)) {
1135
+ state.object.position.copy(_position);
1136
+ state.object.quaternion.copy(_rotation);
1137
+ }
1138
+ } // Get new position
1139
+
1140
+
1141
+ _matrix4.compose(t, rapierQuaternionToQuaternion(r), state.scale).premultiply(state.invertedWorldMatrix).decompose(_position, _rotation, _scale);
1142
+
1143
+ if (state.object instanceof InstancedMesh) {
1144
+ state.setMatrix(_matrix4);
1145
+ state.object.instanceMatrix.needsUpdate = true;
1146
+ } else {
1147
+ // Interpolate to new position
1148
+ state.object.position.lerp(_position, interpolationAlpha);
1149
+ state.object.quaternion.slerp(_rotation, interpolationAlpha);
1150
+ }
1140
1151
  });
1141
- }, [physicsOptions, options]);
1142
- const childColliderProps = useChildColliderProps(ref, mergedOptions); // Create rigidbody
1152
+ eventQueue.drainCollisionEvents((handle1, handle2, started) => {
1153
+ const source1 = getSourceFromColliderHandle(handle1);
1154
+ const source2 = getSourceFromColliderHandle(handle2); // Collision Events
1155
+
1156
+ if (!(source1 !== null && source1 !== void 0 && source1.collider.object) || !(source2 !== null && source2 !== void 0 && source2.collider.object)) {
1157
+ return;
1158
+ }
1159
+
1160
+ const collisionPayload1 = getCollisionPayloadFromSource(source1, source2);
1161
+ const collisionPayload2 = getCollisionPayloadFromSource(source2, source1);
1143
1162
 
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
- }
1163
+ if (started) {
1164
+ world.contactPair(source1.collider.object, source2.collider.object, (manifold, flipped) => {
1165
+ 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
1166
 
1152
- return rigidBodyRef.current;
1153
- }); // Setup
1167
+ /* RigidBody events */
1168
+ (_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), {}, {
1169
+ manifold,
1170
+ flipped
1171
+ }));
1172
+ (_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), {}, {
1173
+ manifold,
1174
+ flipped
1175
+ }));
1176
+ /* Collider events */
1154
1177
 
1155
- useEffect(() => {
1156
- const rigidBody = getRigidBodyRef.current();
1157
- rigidBodyRef.current = rigidBody;
1178
+ (_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), {}, {
1179
+ manifold,
1180
+ flipped
1181
+ }));
1182
+ (_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), {}, {
1183
+ manifold,
1184
+ flipped
1185
+ }));
1186
+ });
1187
+ } else {
1188
+ 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
1189
 
1159
- if (!ref.current) {
1160
- ref.current = new Object3D();
1161
- }
1190
+ (_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);
1191
+ (_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);
1192
+ (_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);
1193
+ (_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);
1194
+ } // Sensor Intersections
1162
1195
 
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
1196
 
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;
1197
+ if (started) {
1198
+ if (world.intersectionPair(source1.collider.object, source2.collider.object)) {
1199
+ 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
1200
 
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;
1201
+ (_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);
1202
+ (_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);
1203
+ (_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);
1204
+ (_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);
1205
+ }
1206
+ } else {
1207
+ 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;
1208
+
1209
+ (_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);
1210
+ (_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);
1211
+ (_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);
1212
+ (_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
1213
  }
1195
- }
1214
+ });
1215
+ eventQueue.drainContactForceEvents(event => {
1216
+ 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
1217
 
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;
1218
+ const source1 = getSourceFromColliderHandle(event.collider1());
1219
+ const source2 = getSourceFromColliderHandle(event.collider2()); // Collision Events
1220
+
1221
+ if (!(source1 !== null && source1 !== void 0 && source1.collider.object) || !(source2 !== null && source2 !== void 0 && source2.collider.object)) {
1222
+ return;
1205
1223
  }
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
1224
 
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
- })));
1225
+ const collisionPayload1 = getCollisionPayloadFromSource(source1, source2);
1226
+ const collisionPayload2 = getCollisionPayloadFromSource(source2, source1);
1227
+ (_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), {}, {
1228
+ totalForce: event.totalForce(),
1229
+ totalForceMagnitude: event.totalForceMagnitude(),
1230
+ maxForceDirection: event.maxForceDirection(),
1231
+ maxForceMagnitude: event.maxForceMagnitude()
1232
+ }));
1233
+ (_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), {}, {
1234
+ totalForce: event.totalForce(),
1235
+ totalForceMagnitude: event.totalForceMagnitude(),
1236
+ maxForceDirection: event.maxForceDirection(),
1237
+ maxForceMagnitude: event.maxForceMagnitude()
1238
+ }));
1239
+ (_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), {}, {
1240
+ totalForce: event.totalForce(),
1241
+ totalForceMagnitude: event.totalForceMagnitude(),
1242
+ maxForceDirection: event.maxForceDirection(),
1243
+ maxForceMagnitude: event.maxForceMagnitude()
1244
+ }));
1245
+ (_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), {}, {
1246
+ totalForce: event.totalForce(),
1247
+ totalForceMagnitude: event.totalForceMagnitude(),
1248
+ maxForceDirection: event.maxForceDirection(),
1249
+ maxForceMagnitude: event.maxForceMagnitude()
1250
+ }));
1251
+ });
1252
+ }, [_paused, _timeStep, _interpolate]);
1253
+ useFrame((_, dt) => {
1254
+ if (!_paused) step(dt);
1255
+ }, updatePriority);
1256
+ const api = useMemo(() => createWorldApi(getWorldRef), []);
1257
+ const context = useMemo(() => ({
1258
+ rapier,
1259
+ world: api,
1260
+ physicsOptions: {
1261
+ colliders: _colliders,
1262
+ gravity: _gravity
1263
+ },
1264
+ rigidBodyStates,
1265
+ colliderStates,
1266
+ rigidBodyEvents,
1267
+ colliderEvents,
1268
+ attractorStates,
1269
+ isPaused: _paused,
1270
+ step
1271
+ }), [_paused, step]);
1272
+ return /*#__PURE__*/React.createElement(RapierContext.Provider, {
1273
+ value: context
1274
+ }, children);
1227
1275
  };
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
1276
 
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
- */
1277
+ function _extends() {
1278
+ _extends = Object.assign ? Object.assign.bind() : function (target) {
1279
+ for (var i = 1; i < arguments.length; i++) {
1280
+ var source = arguments[i];
1246
1281
 
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
- */
1282
+ for (var key in source) {
1283
+ if (Object.prototype.hasOwnProperty.call(source, key)) {
1284
+ target[key] = source[key];
1285
+ }
1286
+ }
1287
+ }
1258
1288
 
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
- };
1289
+ return target;
1290
+ };
1291
+ return _extends.apply(this, arguments);
1292
+ }
1293
+
1294
+ function _objectWithoutPropertiesLoose(source, excluded) {
1295
+ if (source == null) return {};
1296
+ var target = {};
1297
+ var sourceKeys = Object.keys(source);
1298
+ var key, i;
1299
+
1300
+ for (i = 0; i < sourceKeys.length; i++) {
1301
+ key = sourceKeys[i];
1302
+ if (excluded.indexOf(key) >= 0) continue;
1303
+ target[key] = source[key];
1304
+ }
1305
+
1306
+ return target;
1307
+ }
1308
+
1309
+ function _objectWithoutProperties(source, excluded) {
1310
+ if (source == null) return {};
1311
+ var target = _objectWithoutPropertiesLoose(source, excluded);
1312
+ var key, i;
1313
+
1314
+ if (Object.getOwnPropertySymbols) {
1315
+ var sourceSymbolKeys = Object.getOwnPropertySymbols(source);
1316
+
1317
+ for (i = 0; i < sourceSymbolKeys.length; i++) {
1318
+ key = sourceSymbolKeys[i];
1319
+ if (excluded.indexOf(key) >= 0) continue;
1320
+ if (!Object.prototype.propertyIsEnumerable.call(source, key)) continue;
1321
+ target[key] = source[key];
1322
+ }
1323
+ }
1324
+
1325
+ return target;
1326
+ }
1265
1327
 
1266
1328
  // Colliders
1267
1329
  const AnyCollider = /*#__PURE__*/memo( /*#__PURE__*/React.forwardRef((props, forwardedRef) => {
@@ -1389,6 +1451,15 @@ const ConvexHullCollider = /*#__PURE__*/React.forwardRef((props, ref) => {
1389
1451
  ref: ref
1390
1452
  }));
1391
1453
  });
1454
+ CuboidCollider.displayName = "CuboidCollider";
1455
+ RoundCuboidCollider.displayName = "RoundCuboidCollider";
1456
+ BallCollider.displayName = "BallCollider";
1457
+ CapsuleCollider.displayName = "CapsuleCollider";
1458
+ HeightfieldCollider.displayName = "HeightfieldCollider";
1459
+ TrimeshCollider.displayName = "TrimeshCollider";
1460
+ ConeCollider.displayName = "ConeCollider";
1461
+ CylinderCollider.displayName = "CylinderCollider";
1462
+ ConvexHullCollider.displayName = "ConvexHullCollider";
1392
1463
 
1393
1464
  const _excluded$1 = ["children", "type", "position", "rotation", "scale", "quaternion"];
1394
1465
  const RigidBodyContext = /*#__PURE__*/createContext(undefined);
@@ -1424,6 +1495,7 @@ const RigidBody = /*#__PURE__*/memo( /*#__PURE__*/forwardRef((props, ref) => {
1424
1495
  key: index
1425
1496
  }, colliderProps)))));
1426
1497
  }));
1498
+ RigidBody.displayName = "RigidBody";
1427
1499
 
1428
1500
  const MeshCollider = props => {
1429
1501
  const {
@@ -1454,26 +1526,96 @@ const MeshCollider = props => {
1454
1526
  key: index
1455
1527
  }, colliderProps))));
1456
1528
  };
1529
+ MeshCollider.displayName = "MeshCollider";
1530
+
1531
+ function mapsEqual(map1, map2) {
1532
+ var testVal;
1533
+
1534
+ if (map1.size !== map2.size) {
1535
+ return false;
1536
+ }
1537
+
1538
+ for (var [key, val] of map1) {
1539
+ testVal = map2.get(key);
1540
+
1541
+ if (testVal !== val || testVal === undefined && !map2.has(key)) {
1542
+ return false;
1543
+ }
1544
+ }
1545
+
1546
+ return true;
1547
+ }
1548
+
1549
+ const AttractorHelper = props => {
1550
+ const {
1551
+ scene
1552
+ } = useThree();
1553
+ const ref = useRef(null);
1554
+ const normalsHelper = useRef();
1555
+ const color = props.strength > 0 ? 0x0000ff : 0xff0000;
1556
+ useEffect(() => {
1557
+ if (ref.current) {
1558
+ normalsHelper.current = new VertexNormalsHelper(ref.current, props.range, color);
1559
+ normalsHelper.current.frustumCulled = false;
1560
+ scene.add(normalsHelper.current);
1561
+ }
1562
+
1563
+ return () => {
1564
+ if (normalsHelper.current) {
1565
+ scene.remove(normalsHelper.current);
1566
+ }
1567
+ };
1568
+ }, [props]);
1569
+ useFrame(() => {
1570
+ if (ref.current) {
1571
+ var _normalsHelper$curren;
1572
+
1573
+ const worldPosition = props.object.getWorldPosition(_vector3);
1574
+ ref.current.position.copy(worldPosition);
1575
+ (_normalsHelper$curren = normalsHelper.current) === null || _normalsHelper$curren === void 0 ? void 0 : _normalsHelper$curren.update();
1576
+ }
1577
+ });
1578
+ return /*#__PURE__*/React.createElement("mesh", {
1579
+ ref: ref,
1580
+ position: props.object.position,
1581
+ frustumCulled: false
1582
+ }, /*#__PURE__*/React.createElement("sphereGeometry", {
1583
+ args: [0.2, 6, 6]
1584
+ }), /*#__PURE__*/React.createElement("meshBasicMaterial", {
1585
+ color: color,
1586
+ wireframe: true
1587
+ }));
1588
+ };
1457
1589
 
1458
1590
  const Debug = () => {
1459
1591
  const {
1460
- world
1592
+ world,
1593
+ attractorStates
1461
1594
  } = useRapier();
1462
1595
  const ref = useRef(null);
1596
+ const [attractors, setAttractors] = useState([]);
1597
+ const currMap = useRef(new Map());
1463
1598
  useFrame(() => {
1464
1599
  const mesh = ref.current;
1465
1600
  if (!mesh) return;
1466
1601
  const buffers = world.debugRender();
1467
1602
  mesh.geometry.setAttribute("position", new BufferAttribute(buffers.vertices, 3));
1468
- mesh.geometry.setAttribute("color", new BufferAttribute(buffers.colors, 4));
1603
+ mesh.geometry.setAttribute("color", new BufferAttribute(buffers.colors, 4)); // Update attractors
1604
+
1605
+ if (!mapsEqual(currMap.current, attractorStates)) {
1606
+ setAttractors([...attractorStates.values()]);
1607
+ currMap.current = new Map(attractorStates);
1608
+ }
1469
1609
  });
1470
- return /*#__PURE__*/React.createElement("lineSegments", {
1610
+ return /*#__PURE__*/React.createElement("group", null, /*#__PURE__*/React.createElement("lineSegments", {
1471
1611
  ref: ref,
1472
1612
  frustumCulled: false
1473
1613
  }, /*#__PURE__*/React.createElement("lineBasicMaterial", {
1474
1614
  color: 0xffffff,
1475
1615
  vertexColors: true
1476
- }), /*#__PURE__*/React.createElement("bufferGeometry", null));
1616
+ }), /*#__PURE__*/React.createElement("bufferGeometry", null)), attractors.map((attractor, i) => /*#__PURE__*/React.createElement(AttractorHelper, _extends({
1617
+ key: attractor.object.uuid
1618
+ }, attractor))));
1477
1619
  };
1478
1620
 
1479
1621
  const _excluded = ["positions", "rotations", "children"];
@@ -1586,6 +1728,7 @@ const InstancedRigidBodies = /*#__PURE__*/forwardRef((props, ref) => {
1586
1728
  key: index
1587
1729
  }, colliderProps)))));
1588
1730
  });
1731
+ InstancedRigidBodies.displayName = "InstancedRigidBodies";
1589
1732
 
1590
1733
  /**
1591
1734
  * Calculates an InteractionGroup bitmask for use in the `collisionGroups` or `solverGroups`
@@ -1623,4 +1766,4 @@ const interactionGroups = (memberships, filters) => (bitmask(memberships) << 16)
1623
1766
 
1624
1767
  const bitmask = groups => [groups].flat().reduce((acc, layer) => acc | 1 << layer, 0);
1625
1768
 
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 };
1769
+ 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 };