@react-three/rapier 0.16.0-canary.0 → 1.0.0-canary.2

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.
@@ -72,40 +72,6 @@ function _objectSpread2(target) {
72
72
  return target;
73
73
  }
74
74
 
75
- const createWorldApi = getWorld => {
76
- return {
77
- raw: () => getWorld(),
78
- getCollider: handle => getWorld().getCollider(handle),
79
- getRigidBody: handle => getWorld().getRigidBody(handle),
80
- createRigidBody: desc => getWorld().createRigidBody(desc),
81
- createCollider: (desc, rigidBody) => getWorld().createCollider(desc, rigidBody),
82
- removeRigidBody: rigidBody => {
83
- if (!getWorld().bodies.contains(rigidBody.handle)) return;
84
- getWorld().removeRigidBody(rigidBody);
85
- },
86
- removeCollider: (collider, wakeUp = true) => {
87
- if (!getWorld().colliders.contains(collider.handle)) return;
88
- getWorld().removeCollider(collider, wakeUp);
89
- },
90
- createImpulseJoint: (params, rigidBodyA, rigidBodyB, wakeUp = true) => getWorld().createImpulseJoint(params, rigidBodyA, rigidBodyB, wakeUp),
91
- removeImpulseJoint: (joint, wakeUp = true) => {
92
- if (!getWorld().impulseJoints.contains(joint.handle)) return;
93
- getWorld().removeImpulseJoint(joint, wakeUp);
94
- },
95
- forEachCollider: callback => getWorld().forEachCollider(callback),
96
- setGravity: ({
97
- x,
98
- y,
99
- z
100
- }) => getWorld().gravity = {
101
- x,
102
- y,
103
- z
104
- },
105
- debugRender: () => getWorld().debugRender()
106
- };
107
- };
108
-
109
75
  const _quaternion = new three.Quaternion();
110
76
  new three.Euler();
111
77
  const _vector3 = new three.Vector3();
@@ -684,30 +650,37 @@ const Debug = /*#__PURE__*/React.memo(() => {
684
650
  });
685
651
 
686
652
  /**
687
- * Initiate an instance and return a safe getter
653
+ * Creates a proxy that will create a singleton instance of the given class
654
+ * when a property is accessed, and not before.
655
+ *
656
+ * @returns A proxy and a reset function, so that the instance can created again
688
657
  */
658
+ const createSingletonProxy = createInstance => {
659
+ let instance;
660
+ const handler = {
661
+ get(target, prop) {
662
+ if (!instance) {
663
+ instance = createInstance();
664
+ }
689
665
 
690
- const useImperativeInstance = (createFn, destroyFn, dependencyList) => {
691
- const ref = React.useRef();
692
- const getInstance = React.useCallback(() => {
693
- if (!ref.current) {
694
- ref.current = createFn();
666
+ return Reflect.get(instance, prop);
695
667
  }
696
668
 
697
- return ref.current;
698
- }, dependencyList);
699
- React.useEffect(() => {
700
- // Save the destroy function and instance
701
- const instance = getInstance();
669
+ };
670
+ const proxy = new Proxy({}, handler);
702
671
 
703
- const destroy = () => destroyFn(instance);
672
+ const reset = () => {
673
+ instance = undefined;
674
+ };
675
+ /**
676
+ * Return the proxy and a reset function
677
+ */
704
678
 
705
- return () => {
706
- destroy();
707
- ref.current = undefined;
708
- };
709
- }, [getInstance]);
710
- return getInstance;
679
+
680
+ return {
681
+ proxy,
682
+ reset
683
+ };
711
684
  };
712
685
 
713
686
  const rapierContext = /*#__PURE__*/React.createContext(undefined);
@@ -759,38 +732,42 @@ const Physics = ({
759
732
  const rapier = useAsset.useAsset(importRapier);
760
733
  const {
761
734
  invalidate
762
- } = fiber.useThree(); // Init World
763
-
764
- const getWorld = useImperativeInstance(() => {
765
- return new rapier.World(vectorArrayToVector3(_gravity));
766
- }, world => {
767
- world.free();
768
- }, []);
735
+ } = fiber.useThree();
769
736
  const rigidBodyStates = useConst(() => new Map());
770
737
  const colliderStates = useConst(() => new Map());
771
738
  const rigidBodyEvents = useConst(() => new Map());
772
739
  const colliderEvents = useConst(() => new Map());
773
740
  const eventQueue = useConst(() => new rapier3dCompat.EventQueue(false));
774
741
  const beforeStepCallbacks = useConst(() => new Set());
775
- const afterStepCallbacks = useConst(() => new Set()); // Update gravity
742
+ const afterStepCallbacks = useConst(() => new Set());
743
+ /**
744
+ * Initiate the world
745
+ * This creates a singleton proxy, so that the world is only created when
746
+ * something within it is accessed.
747
+ */
776
748
 
749
+ const {
750
+ proxy: worldProxy,
751
+ reset: resetWorldProxy
752
+ } = useConst(() => createSingletonProxy(() => new rapier.World(vectorArrayToVector3(_gravity))));
777
753
  React.useEffect(() => {
778
- const world = getWorld();
754
+ return () => {
755
+ worldProxy.free();
756
+ resetWorldProxy();
757
+ };
758
+ }, []); // Update gravity
779
759
 
780
- if (world) {
781
- world.gravity = vectorArrayToVector3(_gravity);
782
- }
760
+ React.useEffect(() => {
761
+ worldProxy.gravity = vectorArrayToVector3(_gravity);
783
762
  }, [_gravity]);
784
- const api = React.useMemo(() => createWorldApi(getWorld), []);
785
763
  const getSourceFromColliderHandle = React.useCallback(handle => {
786
764
  var _collider$parent;
787
765
 
788
- const world = getWorld();
789
- const collider = world.getCollider(handle);
766
+ const collider = worldProxy.getCollider(handle);
790
767
  const colEvents = colliderEvents.get(handle);
791
768
  const colliderState = colliderStates.get(handle);
792
769
  const rigidBodyHandle = collider === null || collider === void 0 ? void 0 : (_collider$parent = collider.parent()) === null || _collider$parent === void 0 ? void 0 : _collider$parent.handle;
793
- const rigidBody = rigidBodyHandle !== undefined ? world.getRigidBody(rigidBodyHandle) : undefined;
770
+ const rigidBody = rigidBodyHandle !== undefined ? worldProxy.getRigidBody(rigidBodyHandle) : undefined;
794
771
  const rbEvents = rigidBody && rigidBodyHandle !== undefined ? rigidBodyEvents.get(rigidBodyHandle) : undefined;
795
772
  const rigidBodyState = rigidBodyHandle !== undefined ? rigidBodyStates.get(rigidBodyHandle) : undefined;
796
773
  const source = {
@@ -812,7 +789,7 @@ const Physics = ({
812
789
  accumulator: 0
813
790
  });
814
791
  const step = React.useCallback(dt => {
815
- const world = getWorld();
792
+ const world = worldProxy;
816
793
  /* Check if the timestep is supposed to be variable. We'll do this here
817
794
  once so we don't have to string-check every frame. */
818
795
 
@@ -827,12 +804,12 @@ const Physics = ({
827
804
  const stepWorld = () => {
828
805
  // Trigger beforeStep callbacks
829
806
  beforeStepCallbacks.forEach(callback => {
830
- callback.current(api);
807
+ callback.current(worldProxy);
831
808
  });
832
809
  world.step(eventQueue); // Trigger afterStep callbacks
833
810
 
834
811
  afterStepCallbacks.forEach(callback => {
835
- callback.current(api);
812
+ callback.current(worldProxy);
836
813
  });
837
814
  };
838
815
 
@@ -1022,7 +999,7 @@ const Physics = ({
1022
999
  }, [_paused, _timeStep, _interpolate]);
1023
1000
  const context = React.useMemo(() => ({
1024
1001
  rapier,
1025
- world: api,
1002
+ world: worldProxy,
1026
1003
  physicsOptions: {
1027
1004
  colliders: _colliders,
1028
1005
  gravity: _gravity
@@ -1068,6 +1045,33 @@ function _extends() {
1068
1045
  return _extends.apply(this, arguments);
1069
1046
  }
1070
1047
 
1048
+ /**
1049
+ * Initiate an instance and return a safe getter
1050
+ */
1051
+
1052
+ const useImperativeInstance = (createFn, destroyFn, dependencyList) => {
1053
+ const ref = React.useRef();
1054
+ const getInstance = React.useCallback(() => {
1055
+ if (!ref.current) {
1056
+ ref.current = createFn();
1057
+ }
1058
+
1059
+ return ref.current;
1060
+ }, dependencyList);
1061
+ React.useEffect(() => {
1062
+ // Save the destroy function and instance
1063
+ const instance = getInstance();
1064
+
1065
+ const destroy = () => destroyFn(instance);
1066
+
1067
+ return () => {
1068
+ destroy();
1069
+ ref.current = undefined;
1070
+ };
1071
+ }, [getInstance]);
1072
+ return getInstance;
1073
+ };
1074
+
1071
1075
  /**
1072
1076
  * Takes an object resembling a Vector3 and returs a Three.Vector3
1073
1077
  * @category Math helpers
@@ -1119,6 +1123,20 @@ const euler = ({
1119
1123
  return new three.Euler(x, y, z);
1120
1124
  };
1121
1125
 
1126
+ const useForwardedRef = (forwardedRef, defaultValue = null) => {
1127
+ const innerRef = React.useRef(defaultValue); // Update the forwarded ref when the inner ref changes
1128
+
1129
+ if (forwardedRef && typeof forwardedRef !== "function") {
1130
+ if (!forwardedRef.current) {
1131
+ forwardedRef.current = innerRef.current;
1132
+ }
1133
+
1134
+ return forwardedRef;
1135
+ }
1136
+
1137
+ return innerRef;
1138
+ };
1139
+
1122
1140
  /**
1123
1141
  * A collider is a shape that can be attached to a rigid body to define its physical properties.
1124
1142
  * @internal
@@ -1138,24 +1156,30 @@ const AnyCollider = /*#__PURE__*/React.memo( /*#__PURE__*/React.forwardRef((prop
1138
1156
  colliderStates
1139
1157
  } = useRapier();
1140
1158
  const rigidBodyContext = useRigidBodyContext();
1141
- const ref = React.useRef(null); // We spread the props out here to make sure that the ref is updated when the props change.
1159
+ const colliderRef = useForwardedRef(forwardedRef);
1160
+ const objectRef = React.useRef(null); // We spread the props out here to make sure that the ref is updated when the props change.
1142
1161
 
1143
1162
  const immutablePropArray = immutableColliderOptions.flatMap(key => Array.isArray(props[key]) ? [...props[key]] : props[key]);
1144
1163
  const getInstance = useImperativeInstance(() => {
1145
- const worldScale = ref.current.getWorldScale(vec3());
1164
+ const worldScale = objectRef.current.getWorldScale(vec3());
1146
1165
  const collider = createColliderFromOptions(props, world, worldScale, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.getRigidBody);
1166
+
1167
+ if (typeof forwardedRef == "function") {
1168
+ forwardedRef(collider);
1169
+ }
1170
+
1171
+ colliderRef.current = collider;
1147
1172
  return collider;
1148
1173
  }, collider => {
1149
- world.removeCollider(collider);
1174
+ world.removeCollider(collider, true);
1150
1175
  }, [...immutablePropArray, rigidBodyContext]);
1151
1176
  React.useEffect(() => {
1152
1177
  const collider = getInstance();
1153
- colliderStates.set(collider.handle, createColliderState(collider, ref.current, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.ref.current));
1178
+ colliderStates.set(collider.handle, createColliderState(collider, objectRef.current, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.ref.current));
1154
1179
  return () => {
1155
1180
  colliderStates.delete(collider.handle);
1156
1181
  };
1157
1182
  }, [getInstance]);
1158
- React.useImperativeHandle(forwardedRef, () => getInstance(), [getInstance]);
1159
1183
  const mergedProps = React.useMemo(() => {
1160
1184
  return _objectSpread2(_objectSpread2({}, cleanRigidBodyPropsForCollider(rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.options)), props);
1161
1185
  }, [props, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.options]);
@@ -1166,7 +1190,7 @@ const AnyCollider = /*#__PURE__*/React.memo( /*#__PURE__*/React.forwardRef((prop
1166
1190
  rotation: rotation,
1167
1191
  quaternion: quaternion,
1168
1192
  scale: scale,
1169
- ref: ref,
1193
+ ref: objectRef,
1170
1194
  name: name
1171
1195
  }, children);
1172
1196
  }));
@@ -1454,7 +1478,8 @@ const RigidBody = /*#__PURE__*/React.memo( /*#__PURE__*/React.forwardRef((props,
1454
1478
  } = props,
1455
1479
  objectProps = _objectWithoutProperties(props, _excluded$1);
1456
1480
 
1457
- const ref = React.useRef(null);
1481
+ const objectRef = React.useRef(null);
1482
+ const rigidBodyRef = useForwardedRef(forwardedRef);
1458
1483
  const {
1459
1484
  world,
1460
1485
  rigidBodyStates,
@@ -1469,11 +1494,17 @@ const RigidBody = /*#__PURE__*/React.memo( /*#__PURE__*/React.forwardRef((props,
1469
1494
  const immutablePropArray = immutableRigidBodyOptions.flatMap(key => {
1470
1495
  return Array.isArray(mergedOptions[key]) ? [...mergedOptions[key]] : mergedOptions[key];
1471
1496
  });
1472
- const childColliderProps = useChildColliderProps(ref, mergedOptions); // Provide a way to eagerly create rigidbody
1497
+ const childColliderProps = useChildColliderProps(objectRef, mergedOptions); // Provide a way to eagerly create rigidbody
1473
1498
 
1474
1499
  const getRigidBody = useImperativeInstance(() => {
1475
1500
  const desc = rigidBodyDescFromOptions(mergedOptions);
1476
1501
  const rigidBody = world.createRigidBody(desc);
1502
+
1503
+ if (typeof forwardedRef === "function") {
1504
+ forwardedRef(rigidBody);
1505
+ }
1506
+
1507
+ rigidBodyRef.current = rigidBody;
1477
1508
  return rigidBody;
1478
1509
  }, rigidBody => {
1479
1510
  world.removeRigidBody(rigidBody);
@@ -1483,7 +1514,7 @@ const RigidBody = /*#__PURE__*/React.memo( /*#__PURE__*/React.forwardRef((props,
1483
1514
  const rigidBody = getRigidBody();
1484
1515
  const state = createRigidBodyState({
1485
1516
  rigidBody,
1486
- object: ref.current
1517
+ object: objectRef.current
1487
1518
  });
1488
1519
  rigidBodyStates.set(rigidBody.handle, props.transformState ? props.transformState(state) : state);
1489
1520
  return () => {
@@ -1492,10 +1523,9 @@ const RigidBody = /*#__PURE__*/React.memo( /*#__PURE__*/React.forwardRef((props,
1492
1523
  }, [getRigidBody]);
1493
1524
  useUpdateRigidBodyOptions(getRigidBody, mergedOptions, rigidBodyStates);
1494
1525
  useRigidBodyEvents(getRigidBody, mergedOptions, rigidBodyEvents);
1495
- React.useImperativeHandle(forwardedRef, () => getRigidBody(), [getRigidBody]);
1496
1526
  const contextValue = React.useMemo(() => {
1497
1527
  return {
1498
- ref,
1528
+ ref: objectRef,
1499
1529
  getRigidBody: getRigidBody,
1500
1530
  options: mergedOptions
1501
1531
  };
@@ -1503,7 +1533,7 @@ const RigidBody = /*#__PURE__*/React.memo( /*#__PURE__*/React.forwardRef((props,
1503
1533
  return /*#__PURE__*/React__default["default"].createElement(RigidBodyContext.Provider, {
1504
1534
  value: contextValue
1505
1535
  }, /*#__PURE__*/React__default["default"].createElement("object3D", _extends({
1506
- ref: ref
1536
+ ref: objectRef
1507
1537
  }, objectProps, {
1508
1538
  position: position,
1509
1539
  rotation: rotation,
@@ -1550,9 +1580,10 @@ const MeshCollider = /*#__PURE__*/React.memo(props => {
1550
1580
  MeshCollider.displayName = "MeshCollider";
1551
1581
 
1552
1582
  const _excluded = ["children", "instances", "colliderNodes", "position", "rotation", "quaternion", "scale"];
1553
- const InstancedRigidBodies = /*#__PURE__*/React.memo( /*#__PURE__*/React.forwardRef((props, ref) => {
1554
- const object = React.useRef(null);
1555
- const instancedWrapper = React.useRef(null);
1583
+ const InstancedRigidBodies = /*#__PURE__*/React.memo( /*#__PURE__*/React.forwardRef((props, forwardedRef) => {
1584
+ const rigidBodiesRef = useForwardedRef(forwardedRef, []);
1585
+ const objectRef = React.useRef(null);
1586
+ const instanceWrapperRef = React.useRef(null);
1556
1587
 
1557
1588
  const {
1558
1589
  // instanced props
@@ -1567,14 +1598,12 @@ const InstancedRigidBodies = /*#__PURE__*/React.memo( /*#__PURE__*/React.forward
1567
1598
  } = props,
1568
1599
  rigidBodyProps = _objectWithoutProperties(props, _excluded);
1569
1600
 
1570
- const rigidBodyApis = React.useRef([]);
1571
- React.useImperativeHandle(ref, () => rigidBodyApis.current, [instances]);
1572
- const childColliderProps = useChildColliderProps(object, _objectSpread2(_objectSpread2({}, props), {}, {
1601
+ const childColliderProps = useChildColliderProps(objectRef, _objectSpread2(_objectSpread2({}, props), {}, {
1573
1602
  children: undefined
1574
1603
  }));
1575
1604
 
1576
1605
  const getInstancedMesh = () => {
1577
- const firstChild = instancedWrapper.current.children[0];
1606
+ const firstChild = instanceWrapperRef.current.children[0];
1578
1607
 
1579
1608
  if (firstChild && "isInstancedMesh" in firstChild) {
1580
1609
  return firstChild;
@@ -1614,16 +1643,16 @@ const InstancedRigidBodies = /*#__PURE__*/React.memo( /*#__PURE__*/React.forward
1614
1643
  };
1615
1644
 
1616
1645
  return /*#__PURE__*/React__default["default"].createElement("object3D", _extends({
1617
- ref: object
1646
+ ref: objectRef
1618
1647
  }, rigidBodyProps, {
1619
1648
  position: position,
1620
1649
  rotation: rotation,
1621
1650
  quaternion: quaternion,
1622
1651
  scale: scale
1623
1652
  }), /*#__PURE__*/React__default["default"].createElement("object3D", {
1624
- ref: instancedWrapper
1653
+ ref: instanceWrapperRef
1625
1654
  }, children), instances === null || instances === void 0 ? void 0 : instances.map((instance, index) => /*#__PURE__*/React__default["default"].createElement(RigidBody, _extends({}, rigidBodyProps, instance, {
1626
- ref: body => rigidBodyApis.current[index] = body,
1655
+ ref: body => rigidBodiesRef.current[index] = body,
1627
1656
  transformState: state => applyInstancedState(state, index)
1628
1657
  }), /*#__PURE__*/React__default["default"].createElement(React__default["default"].Fragment, null, colliderNodes.map((node, index) => /*#__PURE__*/React__default["default"].createElement(React.Fragment, {
1629
1658
  key: index
@@ -1644,14 +1673,15 @@ const useImpulseJoint = (body1, body2, params) => {
1644
1673
  const jointRef = React.useRef();
1645
1674
  useImperativeInstance(() => {
1646
1675
  if (body1.current && body2.current) {
1647
- const newJoint = world.createImpulseJoint(params, body1.current, body2.current);
1648
- jointRef.current = newJoint;
1676
+ const newJoint = world.createImpulseJoint(params, body1.current, body2.current, true);
1677
+ jointRef.current = newJoint; // console.log(body1.current, body2.current, newJoint);
1678
+
1649
1679
  return newJoint;
1650
1680
  }
1651
1681
  }, joint => {
1652
1682
  if (joint) {
1653
1683
  jointRef.current = undefined;
1654
- world.removeImpulseJoint(joint);
1684
+ world.removeImpulseJoint(joint, true);
1655
1685
  }
1656
1686
  }, []);
1657
1687
  return jointRef;