@react-three/rapier 0.11.3 → 0.12.1

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.
@@ -248,7 +248,7 @@ const createInstancedRigidBodiesApi = bodiesGetter => ({
248
248
  return bodiesGetter.current().length;
249
249
  }
250
250
 
251
- }); // TODO: Flesh this out
251
+ });
252
252
  const createWorldApi = ref => {
253
253
  return {
254
254
  raw: () => ref.current(),
@@ -281,8 +281,7 @@ const createWorldApi = ref => {
281
281
  },
282
282
  debugRender: () => ref.current().debugRender()
283
283
  };
284
- }; // TODO: Broken currently, waiting for Rapier3D to fix
285
-
284
+ };
286
285
  const createJointApi = ref => {
287
286
  return {
288
287
  raw: () => ref.current(),
@@ -756,8 +755,31 @@ const useRigidBodyEvents = (rigidBodyRef, props, events) => {
756
755
  };
757
756
 
758
757
  const useRapier = () => {
759
- return React.useContext(RapierContext);
758
+ return React.useContext(rapierContext);
759
+ };
760
+ const useBeforePhysicsStep = callback => {
761
+ const {
762
+ beforeStepCallbacks
763
+ } = useRapier();
764
+ React.useEffect(() => {
765
+ beforeStepCallbacks.add(callback);
766
+ return () => {
767
+ beforeStepCallbacks.delete(callback);
768
+ };
769
+ }, []);
760
770
  };
771
+ const useAfterPhysicsStep = callback => {
772
+ const {
773
+ afterStepCallbacks
774
+ } = useRapier();
775
+ React.useEffect(() => {
776
+ afterStepCallbacks.add(callback);
777
+ return () => {
778
+ afterStepCallbacks.delete(callback);
779
+ };
780
+ }, []);
781
+ }; // Internal hooks
782
+
761
783
  const useChildColliderProps = (ref, options, ignoreMeshColliders = true) => {
762
784
  const [colliderProps, setColliderProps] = React.useState([]);
763
785
  React.useEffect(() => {
@@ -821,103 +843,6 @@ const useRigidBody = (options = {}) => {
821
843
  useRigidBodyEvents(rigidBodyRef, mergedOptions, rigidBodyEvents);
822
844
  const api = React.useMemo(() => createRigidBodyApi(getRigidBodyRef), []);
823
845
  return [ref, api, childColliderProps];
824
- }; // Joints
825
-
826
- const useImpulseJoint = (body1, body2, params) => {
827
- const {
828
- world
829
- } = useRapier();
830
- const jointRef = React.useRef();
831
- const getJointRef = React.useRef(() => {
832
- if (!jointRef.current) {
833
- let rb1;
834
- let rb2;
835
-
836
- if ("current" in body1 && body1.current && "current" in body2 && body2.current) {
837
- rb1 = world.getRigidBody(body1.current.handle);
838
- rb2 = world.getRigidBody(body2.current.handle);
839
- const newJoint = world.createImpulseJoint(params, rb1, rb2);
840
- jointRef.current = newJoint;
841
- }
842
- }
843
-
844
- return jointRef.current;
845
- });
846
- React.useEffect(() => {
847
- const joint = getJointRef.current();
848
- return () => {
849
- if (joint) {
850
- world.removeImpulseJoint(joint);
851
- jointRef.current = undefined;
852
- }
853
- };
854
- }, []);
855
- const api = React.useMemo(() => createJointApi(getJointRef), []);
856
- return api;
857
- };
858
- /**
859
- *
860
- * A fixed joint ensures that two rigid-bodies don't move relative to each other.
861
- * Fixed joints are characterized by one local frame (represented by an isometry) on each rigid-body.
862
- * The fixed-joint makes these frames coincide in world-space.
863
- */
864
-
865
- const useFixedJoint = (body1, body2, [body1Anchor, body1LocalFrame, body2Anchor, body2LocalFrame]) => {
866
- const {
867
- rapier
868
- } = useRapier();
869
- return useImpulseJoint(body1, body2, rapier.JointData.fixed(vectorArrayToVector3(body1Anchor), tupleToObject(body1LocalFrame, ["x", "y", "z", "w"]), vectorArrayToVector3(body2Anchor), tupleToObject(body2LocalFrame, ["x", "y", "z", "w"])));
870
- };
871
- /**
872
- * The spherical joint ensures that two points on the local-spaces of two rigid-bodies always coincide (it prevents any relative
873
- * translational motion at this points). This is typically used to simulate ragdolls arms, pendulums, etc.
874
- * They are characterized by one local anchor on each rigid-body. Each anchor represents the location of the
875
- * points that need to coincide on the local-space of each rigid-body.
876
- */
877
-
878
- const useSphericalJoint = (body1, body2, [body1Anchor, body2Anchor]) => {
879
- const {
880
- rapier
881
- } = useRapier();
882
- return useImpulseJoint(body1, body2, rapier.JointData.spherical(vectorArrayToVector3(body1Anchor), vectorArrayToVector3(body2Anchor)));
883
- };
884
- /**
885
- * The revolute joint prevents any relative movement between two rigid-bodies, except for relative
886
- * rotations along one axis. This is typically used to simulate wheels, fans, etc.
887
- * They are characterized by one local anchor as well as one local axis on each rigid-body.
888
- */
889
-
890
- const useRevoluteJoint = (body1, body2, [body1Anchor, body2Anchor, axis, limits]) => {
891
- const {
892
- rapier
893
- } = useRapier();
894
- const params = rapier.JointData.revolute(vectorArrayToVector3(body1Anchor), vectorArrayToVector3(body2Anchor), vectorArrayToVector3(axis));
895
-
896
- if (limits) {
897
- params.limitsEnabled = true;
898
- params.limits = limits;
899
- }
900
-
901
- return useImpulseJoint(body1, body2, params);
902
- };
903
- /**
904
- * The prismatic joint prevents any relative movement between two rigid-bodies, except for relative translations along one axis.
905
- * It is characterized by one local anchor as well as one local axis on each rigid-body. In 3D, an optional
906
- * local tangent axis can be specified for each rigid-body.
907
- */
908
-
909
- const usePrismaticJoint = (body1, body2, [body1Anchor, body2Anchor, axis, limits]) => {
910
- const {
911
- rapier
912
- } = useRapier();
913
- const params = rapier.JointData.prismatic(vectorArrayToVector3(body1Anchor), vectorArrayToVector3(body2Anchor), vectorArrayToVector3(axis));
914
-
915
- if (limits) {
916
- params.limitsEnabled = true;
917
- params.limits = limits;
918
- }
919
-
920
- return useImpulseJoint(body1, body2, params);
921
846
  };
922
847
 
923
848
  const calcForceByType = {
@@ -1005,7 +930,7 @@ const Attractor = /*#__PURE__*/React.memo(props => {
1005
930
  });
1006
931
  });
1007
932
 
1008
- const RapierContext = /*#__PURE__*/React.createContext(undefined);
933
+ const rapierContext = /*#__PURE__*/React.createContext(undefined);
1009
934
 
1010
935
  const getCollisionPayloadFromSource = (target, other) => {
1011
936
  var _target$collider$stat, _target$rigidBody$sta, _other$collider$state, _other$rigidBody$stat, _other$collider$state2, _other$rigidBody$stat2;
@@ -1060,7 +985,9 @@ const Physics = ({
1060
985
  const rigidBodyEvents = useConst(() => new Map());
1061
986
  const colliderEvents = useConst(() => new Map());
1062
987
  const eventQueue = useConst(() => new rapier3dCompat.EventQueue(false));
1063
- const attractorStates = useConst(() => new Map()); // Init world
988
+ const attractorStates = useConst(() => new Map());
989
+ const beforeStepCallbacks = useConst(() => new Set());
990
+ const afterStepCallbacks = useConst(() => new Set()); // Init world
1064
991
 
1065
992
  React.useEffect(() => {
1066
993
  const world = getWorldRef.current();
@@ -1079,6 +1006,7 @@ const Physics = ({
1079
1006
  world.gravity = vectorArrayToVector3(_gravity);
1080
1007
  }
1081
1008
  }, [_gravity]);
1009
+ const api = React.useMemo(() => createWorldApi(getWorldRef), []);
1082
1010
  const getSourceFromColliderHandle = React.useCallback(handle => {
1083
1011
  const world = worldRef.current;
1084
1012
 
@@ -1125,9 +1053,21 @@ const Physics = ({
1125
1053
 
1126
1054
  const clampedDelta = three.MathUtils.clamp(dt, 0, 0.2);
1127
1055
 
1056
+ const stepWorld = () => {
1057
+ // Trigger beforeStep callbacks
1058
+ beforeStepCallbacks.forEach(callback => {
1059
+ callback(api);
1060
+ });
1061
+ world.step(eventQueue); // Trigger afterStep callbacks
1062
+
1063
+ afterStepCallbacks.forEach(callback => {
1064
+ callback(api);
1065
+ });
1066
+ };
1067
+
1128
1068
  if (timeStepVariable) {
1129
1069
  world.timestep = clampedDelta;
1130
- world.step(eventQueue);
1070
+ stepWorld();
1131
1071
  } else {
1132
1072
  world.timestep = _timeStep; // don't step time forwards if paused
1133
1073
  // Increase accumulator
@@ -1151,7 +1091,7 @@ const Physics = ({
1151
1091
  applyAttractorForceOnRigidBody(body, attractorState);
1152
1092
  });
1153
1093
  });
1154
- world.step(eventQueue);
1094
+ stepWorld();
1155
1095
  steppingState.accumulator -= _timeStep;
1156
1096
  }
1157
1097
  }
@@ -1314,7 +1254,6 @@ const Physics = ({
1314
1254
  fiber.useFrame((_, dt) => {
1315
1255
  if (!_paused) step(dt);
1316
1256
  }, updatePriority);
1317
- const api = React.useMemo(() => createWorldApi(getWorldRef), []);
1318
1257
  const context = React.useMemo(() => ({
1319
1258
  rapier,
1320
1259
  world: api,
@@ -1327,10 +1266,12 @@ const Physics = ({
1327
1266
  rigidBodyEvents,
1328
1267
  colliderEvents,
1329
1268
  attractorStates,
1269
+ beforeStepCallbacks,
1270
+ afterStepCallbacks,
1330
1271
  isPaused: _paused,
1331
1272
  step
1332
1273
  }), [_paused, step]);
1333
- return /*#__PURE__*/React__default["default"].createElement(RapierContext.Provider, {
1274
+ return /*#__PURE__*/React__default["default"].createElement(rapierContext.Provider, {
1334
1275
  value: context
1335
1276
  }, children);
1336
1277
  };
@@ -1558,7 +1499,7 @@ const RigidBody = /*#__PURE__*/React.memo( /*#__PURE__*/React.forwardRef((props,
1558
1499
  }));
1559
1500
  RigidBody.displayName = "RigidBody";
1560
1501
 
1561
- const MeshCollider = props => {
1502
+ const MeshCollider = /*#__PURE__*/React.memo(props => {
1562
1503
  const {
1563
1504
  children,
1564
1505
  type
@@ -1586,7 +1527,7 @@ const MeshCollider = props => {
1586
1527
  }, children, childColliderProps.map((colliderProps, index) => /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({
1587
1528
  key: index
1588
1529
  }, colliderProps))));
1589
- };
1530
+ });
1590
1531
  MeshCollider.displayName = "MeshCollider";
1591
1532
 
1592
1533
  function mapsEqual(map1, map2) {
@@ -1648,7 +1589,7 @@ const AttractorHelper = props => {
1648
1589
  }));
1649
1590
  };
1650
1591
 
1651
- const Debug = () => {
1592
+ const Debug = /*#__PURE__*/React.memo(() => {
1652
1593
  const {
1653
1594
  world,
1654
1595
  attractorStates
@@ -1677,7 +1618,7 @@ const Debug = () => {
1677
1618
  }), /*#__PURE__*/React__default["default"].createElement("bufferGeometry", null)), attractors.map((attractor, i) => /*#__PURE__*/React__default["default"].createElement(AttractorHelper, _extends({
1678
1619
  key: attractor.object.uuid
1679
1620
  }, attractor))));
1680
- };
1621
+ });
1681
1622
 
1682
1623
  const _excluded = ["positions", "rotations", "children"];
1683
1624
  const InstancedRigidBodies = /*#__PURE__*/React.forwardRef((props, ref) => {
@@ -1791,6 +1732,103 @@ const InstancedRigidBodies = /*#__PURE__*/React.forwardRef((props, ref) => {
1791
1732
  });
1792
1733
  InstancedRigidBodies.displayName = "InstancedRigidBodies";
1793
1734
 
1735
+ const useImpulseJoint = (body1, body2, params) => {
1736
+ const {
1737
+ world
1738
+ } = useRapier();
1739
+ const jointRef = React.useRef();
1740
+ const getJointRef = React.useRef(() => {
1741
+ if (!jointRef.current) {
1742
+ let rb1;
1743
+ let rb2;
1744
+
1745
+ if ("current" in body1 && body1.current && "current" in body2 && body2.current) {
1746
+ rb1 = world.getRigidBody(body1.current.handle);
1747
+ rb2 = world.getRigidBody(body2.current.handle);
1748
+ const newJoint = world.createImpulseJoint(params, rb1, rb2);
1749
+ jointRef.current = newJoint;
1750
+ }
1751
+ }
1752
+
1753
+ return jointRef.current;
1754
+ });
1755
+ React.useEffect(() => {
1756
+ const joint = getJointRef.current();
1757
+ return () => {
1758
+ if (joint) {
1759
+ world.removeImpulseJoint(joint);
1760
+ jointRef.current = undefined;
1761
+ }
1762
+ };
1763
+ }, []);
1764
+ const api = React.useMemo(() => createJointApi(getJointRef), []);
1765
+ return api;
1766
+ };
1767
+ /**
1768
+ *
1769
+ * A fixed joint ensures that two rigid-bodies don't move relative to each other.
1770
+ * Fixed joints are characterized by one local frame (represented by an isometry) on each rigid-body.
1771
+ * The fixed-joint makes these frames coincide in world-space.
1772
+ */
1773
+
1774
+ const useFixedJoint = (body1, body2, [body1Anchor, body1LocalFrame, body2Anchor, body2LocalFrame]) => {
1775
+ const {
1776
+ rapier
1777
+ } = useRapier();
1778
+ return useImpulseJoint(body1, body2, rapier.JointData.fixed(vectorArrayToVector3(body1Anchor), tupleToObject(body1LocalFrame, ["x", "y", "z", "w"]), vectorArrayToVector3(body2Anchor), tupleToObject(body2LocalFrame, ["x", "y", "z", "w"])));
1779
+ };
1780
+ /**
1781
+ * The spherical joint ensures that two points on the local-spaces of two rigid-bodies always coincide (it prevents any relative
1782
+ * translational motion at this points). This is typically used to simulate ragdolls arms, pendulums, etc.
1783
+ * They are characterized by one local anchor on each rigid-body. Each anchor represents the location of the
1784
+ * points that need to coincide on the local-space of each rigid-body.
1785
+ */
1786
+
1787
+ const useSphericalJoint = (body1, body2, [body1Anchor, body2Anchor]) => {
1788
+ const {
1789
+ rapier
1790
+ } = useRapier();
1791
+ return useImpulseJoint(body1, body2, rapier.JointData.spherical(vectorArrayToVector3(body1Anchor), vectorArrayToVector3(body2Anchor)));
1792
+ };
1793
+ /**
1794
+ * The revolute joint prevents any relative movement between two rigid-bodies, except for relative
1795
+ * rotations along one axis. This is typically used to simulate wheels, fans, etc.
1796
+ * They are characterized by one local anchor as well as one local axis on each rigid-body.
1797
+ */
1798
+
1799
+ const useRevoluteJoint = (body1, body2, [body1Anchor, body2Anchor, axis, limits]) => {
1800
+ const {
1801
+ rapier
1802
+ } = useRapier();
1803
+ const params = rapier.JointData.revolute(vectorArrayToVector3(body1Anchor), vectorArrayToVector3(body2Anchor), vectorArrayToVector3(axis));
1804
+
1805
+ if (limits) {
1806
+ params.limitsEnabled = true;
1807
+ params.limits = limits;
1808
+ }
1809
+
1810
+ return useImpulseJoint(body1, body2, params);
1811
+ };
1812
+ /**
1813
+ * The prismatic joint prevents any relative movement between two rigid-bodies, except for relative translations along one axis.
1814
+ * It is characterized by one local anchor as well as one local axis on each rigid-body. In 3D, an optional
1815
+ * local tangent axis can be specified for each rigid-body.
1816
+ */
1817
+
1818
+ const usePrismaticJoint = (body1, body2, [body1Anchor, body2Anchor, axis, limits]) => {
1819
+ const {
1820
+ rapier
1821
+ } = useRapier();
1822
+ const params = rapier.JointData.prismatic(vectorArrayToVector3(body1Anchor), vectorArrayToVector3(body2Anchor), vectorArrayToVector3(axis));
1823
+
1824
+ if (limits) {
1825
+ params.limitsEnabled = true;
1826
+ params.limits = limits;
1827
+ }
1828
+
1829
+ return useImpulseJoint(body1, body2, params);
1830
+ };
1831
+
1794
1832
  /**
1795
1833
  * Calculates an InteractionGroup bitmask for use in the `collisionGroups` or `solverGroups`
1796
1834
  * properties of RigidBody or Collider components. The first argument represents a list of
@@ -1856,11 +1894,11 @@ exports.RigidBody = RigidBody;
1856
1894
  exports.RoundCuboidCollider = RoundCuboidCollider;
1857
1895
  exports.TrimeshCollider = TrimeshCollider;
1858
1896
  exports.interactionGroups = interactionGroups;
1859
- exports.useChildColliderProps = useChildColliderProps;
1897
+ exports.useAfterPhysicsStep = useAfterPhysicsStep;
1898
+ exports.useBeforePhysicsStep = useBeforePhysicsStep;
1860
1899
  exports.useFixedJoint = useFixedJoint;
1861
1900
  exports.useImpulseJoint = useImpulseJoint;
1862
1901
  exports.usePrismaticJoint = usePrismaticJoint;
1863
1902
  exports.useRapier = useRapier;
1864
1903
  exports.useRevoluteJoint = useRevoluteJoint;
1865
- exports.useRigidBody = useRigidBody;
1866
1904
  exports.useSphericalJoint = useSphericalJoint;