@react-three/rapier 1.1.2 → 1.2.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.
@@ -77,6 +77,39 @@ export interface RapierContext {
77
77
  * The Rapier physics world
78
78
  */
79
79
  world: World;
80
+ /**
81
+ * Can be used to overwrite the current World. Useful when working with snapshots.
82
+ *
83
+ * @example
84
+ * ```tsx
85
+ * import { useRapier } from '@react-three/rapier';
86
+ *
87
+ * const SnapshottingComponent = () => {
88
+ * const { world, setWorld, rapier } = useRapier();
89
+ * const worldSnapshot = useRef<Uint8Array>();
90
+ *
91
+ * // Store the snapshot
92
+ * const takeSnapshot = () => {
93
+ * const snapshot = world.takeSnapshot()
94
+ * worldSnapshot.current = snapshot
95
+ * }
96
+ *
97
+ * // Create a new World from the snapshot, and replace the current one
98
+ * const restoreSnapshot = () => {
99
+ * setWorld(rapier.World.restoreSnapshot(worldSnapshot.current))
100
+ * }
101
+ *
102
+ * return <>
103
+ * <Rigidbody>...</RigidBody>
104
+ * <Rigidbody>...</RigidBody>
105
+ * <Rigidbody>...</RigidBody>
106
+ * <Rigidbody>...</RigidBody>
107
+ * <Rigidbody>...</RigidBody>
108
+ * </>
109
+ * }
110
+ * ```
111
+ */
112
+ setWorld: (world: World) => void;
80
113
  /**
81
114
  * If the physics simulation is paused
82
115
  */
@@ -7,4 +7,5 @@
7
7
  export declare const createSingletonProxy: <SingletonClass extends object, CreationFn extends () => SingletonClass = () => SingletonClass>(createInstance: CreationFn) => {
8
8
  proxy: SingletonClass;
9
9
  reset: () => void;
10
+ set: (newInstance: SingletonClass) => void;
10
11
  };
@@ -572,7 +572,7 @@ const useMutableCallback = fn => {
572
572
 
573
573
  const useRapier = () => {
574
574
  const rapier = React.useContext(rapierContext);
575
- if (!rapier) throw new Error('react-three-rapier: useRapier must be used within <Physics />!');
575
+ if (!rapier) throw new Error("react-three-rapier: useRapier must be used within <Physics />!");
576
576
  return rapier;
577
577
  };
578
578
  /**
@@ -682,6 +682,10 @@ const createSingletonProxy = createInstance => {
682
682
  const reset = () => {
683
683
  instance = undefined;
684
684
  };
685
+
686
+ const set = newInstance => {
687
+ instance = newInstance;
688
+ };
685
689
  /**
686
690
  * Return the proxy and a reset function
687
691
  */
@@ -689,7 +693,8 @@ const createSingletonProxy = createInstance => {
689
693
 
690
694
  return {
691
695
  proxy,
692
- reset
696
+ reset,
697
+ set
693
698
  };
694
699
  };
695
700
 
@@ -764,7 +769,8 @@ const Physics = props => {
764
769
 
765
770
  const {
766
771
  proxy: worldProxy,
767
- reset: resetWorldProxy
772
+ reset: resetWorldProxy,
773
+ set: setWorldProxy
768
774
  } = useConst(() => createSingletonProxy(() => new rapier.World(vectorArrayToVector3(gravity))));
769
775
  React.useEffect(() => {
770
776
  return () => {
@@ -1020,6 +1026,9 @@ const Physics = props => {
1020
1026
  const context = React.useMemo(() => ({
1021
1027
  rapier,
1022
1028
  world: worldProxy,
1029
+ setWorld: world => {
1030
+ setWorldProxy(world);
1031
+ },
1023
1032
  physicsOptions: {
1024
1033
  colliders,
1025
1034
  gravity
@@ -572,7 +572,7 @@ const useMutableCallback = fn => {
572
572
 
573
573
  const useRapier = () => {
574
574
  const rapier = React.useContext(rapierContext);
575
- if (!rapier) throw new Error('react-three-rapier: useRapier must be used within <Physics />!');
575
+ if (!rapier) throw new Error("react-three-rapier: useRapier must be used within <Physics />!");
576
576
  return rapier;
577
577
  };
578
578
  /**
@@ -682,6 +682,10 @@ const createSingletonProxy = createInstance => {
682
682
  const reset = () => {
683
683
  instance = undefined;
684
684
  };
685
+
686
+ const set = newInstance => {
687
+ instance = newInstance;
688
+ };
685
689
  /**
686
690
  * Return the proxy and a reset function
687
691
  */
@@ -689,7 +693,8 @@ const createSingletonProxy = createInstance => {
689
693
 
690
694
  return {
691
695
  proxy,
692
- reset
696
+ reset,
697
+ set
693
698
  };
694
699
  };
695
700
 
@@ -764,7 +769,8 @@ const Physics = props => {
764
769
 
765
770
  const {
766
771
  proxy: worldProxy,
767
- reset: resetWorldProxy
772
+ reset: resetWorldProxy,
773
+ set: setWorldProxy
768
774
  } = useConst(() => createSingletonProxy(() => new rapier.World(vectorArrayToVector3(gravity))));
769
775
  React.useEffect(() => {
770
776
  return () => {
@@ -1020,6 +1026,9 @@ const Physics = props => {
1020
1026
  const context = React.useMemo(() => ({
1021
1027
  rapier,
1022
1028
  world: worldProxy,
1029
+ setWorld: world => {
1030
+ setWorldProxy(world);
1031
+ },
1023
1032
  physicsOptions: {
1024
1033
  colliders,
1025
1034
  gravity
@@ -547,7 +547,7 @@ const useMutableCallback = fn => {
547
547
 
548
548
  const useRapier = () => {
549
549
  const rapier = useContext(rapierContext);
550
- if (!rapier) throw new Error('react-three-rapier: useRapier must be used within <Physics />!');
550
+ if (!rapier) throw new Error("react-three-rapier: useRapier must be used within <Physics />!");
551
551
  return rapier;
552
552
  };
553
553
  /**
@@ -657,6 +657,10 @@ const createSingletonProxy = createInstance => {
657
657
  const reset = () => {
658
658
  instance = undefined;
659
659
  };
660
+
661
+ const set = newInstance => {
662
+ instance = newInstance;
663
+ };
660
664
  /**
661
665
  * Return the proxy and a reset function
662
666
  */
@@ -664,7 +668,8 @@ const createSingletonProxy = createInstance => {
664
668
 
665
669
  return {
666
670
  proxy,
667
- reset
671
+ reset,
672
+ set
668
673
  };
669
674
  };
670
675
 
@@ -739,7 +744,8 @@ const Physics = props => {
739
744
 
740
745
  const {
741
746
  proxy: worldProxy,
742
- reset: resetWorldProxy
747
+ reset: resetWorldProxy,
748
+ set: setWorldProxy
743
749
  } = useConst(() => createSingletonProxy(() => new rapier.World(vectorArrayToVector3(gravity))));
744
750
  useEffect(() => {
745
751
  return () => {
@@ -995,6 +1001,9 @@ const Physics = props => {
995
1001
  const context = useMemo(() => ({
996
1002
  rapier,
997
1003
  world: worldProxy,
1004
+ setWorld: world => {
1005
+ setWorldProxy(world);
1006
+ },
998
1007
  physicsOptions: {
999
1008
  colliders,
1000
1009
  gravity
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-three/rapier",
3
- "version": "1.1.2",
3
+ "version": "1.2.1",
4
4
  "source": "src/index.ts",
5
5
  "main": "dist/react-three-rapier.cjs.js",
6
6
  "module": "dist/react-three-rapier.esm.js",
package/readme.md CHANGED
@@ -82,6 +82,7 @@ For full API outline and documentation, see 🧩 [API Docs](https://pmndrs.githu
82
82
  - [Advanced hooks usage](#advanced-hooks-usage)
83
83
  - [Manual stepping](#manual-stepping)
84
84
  - [On-demand rendering](#on-demand-rendering)
85
+ - [Snapshots](#snapshots)
85
86
 
86
87
  ---
87
88
 
@@ -413,7 +414,7 @@ const Scene = () => {
413
414
  // While Rapier's return types need conversion, setting values can be done directly with Three.js types
414
415
  rigidBody.current.setTranslation(position, true);
415
416
  rigidBody.current.setRotation(quaternion, true);
416
- rigidBody.current.setAngVel({ x: 0, y: 2, z: 0 }, true);
417
+ rigidBody.current.setAngvel({ x: 0, y: 2, z: 0 }, true);
417
418
  }
418
419
  }, []);
419
420
 
@@ -812,3 +813,39 @@ Setting `<Physics updateLoop="independent" />` will make the physics simulation
812
813
  <Physics updateLoop="independent">...</Physics>
813
814
  </Canvas>
814
815
  ```
816
+
817
+ ## Snapshots
818
+ The `world` can be serialized as a `Uint8Array` using `world.takeSnapshot()`, see Rapier's docs on [Serialization](https://rapier.rs/docs/user_guides/javascript/serialization/) for more info.
819
+
820
+ The snapshot can be used to construct a new world. In `r3/rapier`, you need to replace the world with this snapshot.
821
+
822
+ > [!NOTE]
823
+ > This only works if the snapshotted world is identical to the restored one. If objects, or the order of creation of objects vary, expect RigidBodies to scramble.
824
+
825
+ ```tsx
826
+ import { useRapier } from '@react-three/rapier';
827
+
828
+ const SnapshottingComponent = () => {
829
+ const { world, setWorld, rapier } = useRapier();
830
+ const worldSnapshot = useRef<Uint8Array>();
831
+
832
+ // Store the snapshot
833
+ const takeSnapshot = () => {
834
+ const snapshot = world.takeSnapshot()
835
+ worldSnapshot.current = snapshot
836
+ }
837
+
838
+ // Create a new World from the snapshot, and replace the current one
839
+ const restoreSnapshot = () => {
840
+ setWorld(rapier.World.restoreSnapshot(worldSnapshot.current))
841
+ }
842
+
843
+ return <>
844
+ <Rigidbody>...</RigidBody>
845
+ <Rigidbody>...</RigidBody>
846
+ <Rigidbody>...</RigidBody>
847
+ <Rigidbody>...</RigidBody>
848
+ <Rigidbody>...</RigidBody>
849
+ </>
850
+ }
851
+ ```