@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.
- package/dist/declarations/src/components/Physics.d.ts +33 -0
- package/dist/declarations/src/utils/singleton-proxy.d.ts +1 -0
- package/dist/react-three-rapier.cjs.dev.js +12 -3
- package/dist/react-three-rapier.cjs.prod.js +12 -3
- package/dist/react-three-rapier.esm.js +12 -3
- package/package.json +1 -1
- package/readme.md +38 -1
@@ -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
|
*/
|
@@ -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(
|
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(
|
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(
|
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
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.
|
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
|
+
```
|