@react-three/rapier 0.16.0-canary.1 → 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.
@@ -1,9 +1,8 @@
1
1
  import type Rapier from "@dimforge/rapier3d-compat";
2
- import { Collider, ColliderHandle, RigidBody, RigidBodyHandle } from "@dimforge/rapier3d-compat";
2
+ import { Collider, ColliderHandle, RigidBody, RigidBodyHandle, World } from "@dimforge/rapier3d-compat";
3
3
  import React, { FC, ReactNode } from "react";
4
4
  import { Matrix4, Object3D, Vector3 } from "three";
5
5
  import { CollisionEnterHandler, CollisionExitHandler, ContactForceHandler, IntersectionEnterHandler, IntersectionExitHandler, RigidBodyAutoCollider, Vector3Tuple } from "../types";
6
- import { WorldApi } from "../utils/api";
7
6
  export interface RigidBodyState {
8
7
  meshType: "instancedMesh" | "mesh";
9
8
  rigidBody: RigidBody;
@@ -18,7 +17,7 @@ export interface RigidBodyState {
18
17
  isSleeping: boolean;
19
18
  }
20
19
  export declare type RigidBodyStateMap = Map<RigidBody["handle"], RigidBodyState>;
21
- export declare type WorldStepCallback = (worldApi: WorldApi) => void;
20
+ export declare type WorldStepCallback = (world: World) => void;
22
21
  export declare type WorldStepCallbackSet = Set<{
23
22
  current: WorldStepCallback;
24
23
  }>;
@@ -77,7 +76,7 @@ export interface RapierContext {
77
76
  /**
78
77
  * The Rapier physics world
79
78
  */
80
- world: WorldApi;
79
+ world: World;
81
80
  /**
82
81
  * If the physics simulation is paused
83
82
  */
@@ -4,7 +4,6 @@ export type { InstancedRigidBodiesProps, InstancedRigidBodyProps } from "./compo
4
4
  export type { CylinderColliderProps, BallColliderProps, CapsuleColliderProps, ConeColliderProps, ConvexHullColliderProps, CuboidColliderProps, HeightfieldColliderProps, RoundCuboidColliderProps, TrimeshColliderProps, ColliderOptionsRequiredArgs } from "./components/AnyCollider";
5
5
  export type { PhysicsProps, RapierContext, WorldStepCallback } from "./components/Physics";
6
6
  export type { MeshColliderProps } from "./components/MeshCollider";
7
- export type { WorldApi } from "./utils/api";
8
7
  export { Physics } from "./components/Physics";
9
8
  export { RigidBody } from "./components/RigidBody";
10
9
  export { MeshCollider } from "./components/MeshCollider";
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Creates a proxy that will create a singleton instance of the given class
3
+ * when a property is accessed, and not before.
4
+ *
5
+ * @returns A proxy and a reset function, so that the instance can created again
6
+ */
7
+ export declare const createSingletonProxy: <SingletonClass extends object, CreationFn extends () => SingletonClass = () => SingletonClass>(createInstance: CreationFn) => {
8
+ proxy: SingletonClass;
9
+ reset: () => void;
10
+ };
@@ -1,7 +1,6 @@
1
- import { Collider, RigidBody } from "@dimforge/rapier3d-compat";
1
+ import { Collider, RigidBody, World } from "@dimforge/rapier3d-compat";
2
2
  import { BufferGeometry, Object3D, Vector3 } from "three";
3
3
  import { ColliderProps, RigidBodyProps } from "..";
4
- import { WorldApi } from "./api";
5
4
  import { ColliderState, ColliderStateMap, EventMap } from "../components/Physics";
6
5
  import { ColliderShape, RigidBodyAutoCollider } from "../types";
7
6
  export declare const scaleColliderArgs: (shape: ColliderShape, args: (number | ArrayLike<number> | {
@@ -13,7 +12,7 @@ export declare const scaleColliderArgs: (shape: ColliderShape, args: (number | A
13
12
  y: number;
14
13
  z: number;
15
14
  })[];
16
- export declare const createColliderFromOptions: (options: ColliderProps, world: WorldApi, scale: Vector3, getRigidBody?: () => RigidBody) => Collider;
15
+ export declare const createColliderFromOptions: (options: ColliderProps, world: World, scale: Vector3, getRigidBody?: () => RigidBody) => Collider;
17
16
  declare type ImmutableColliderOptions = (keyof ColliderProps)[];
18
17
  export declare const immutableColliderOptions: ImmutableColliderOptions;
19
18
  export declare const setColliderOptions: (collider: Collider, options: ColliderProps, states: ColliderStateMap) => void;
@@ -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
@@ -1167,7 +1171,7 @@ const AnyCollider = /*#__PURE__*/React.memo( /*#__PURE__*/React.forwardRef((prop
1167
1171
  colliderRef.current = collider;
1168
1172
  return collider;
1169
1173
  }, collider => {
1170
- world.removeCollider(collider);
1174
+ world.removeCollider(collider, true);
1171
1175
  }, [...immutablePropArray, rigidBodyContext]);
1172
1176
  React.useEffect(() => {
1173
1177
  const collider = getInstance();
@@ -1669,7 +1673,7 @@ const useImpulseJoint = (body1, body2, params) => {
1669
1673
  const jointRef = React.useRef();
1670
1674
  useImperativeInstance(() => {
1671
1675
  if (body1.current && body2.current) {
1672
- const newJoint = world.createImpulseJoint(params, body1.current, body2.current);
1676
+ const newJoint = world.createImpulseJoint(params, body1.current, body2.current, true);
1673
1677
  jointRef.current = newJoint; // console.log(body1.current, body2.current, newJoint);
1674
1678
 
1675
1679
  return newJoint;
@@ -1677,7 +1681,7 @@ const useImpulseJoint = (body1, body2, params) => {
1677
1681
  }, joint => {
1678
1682
  if (joint) {
1679
1683
  jointRef.current = undefined;
1680
- world.removeImpulseJoint(joint);
1684
+ world.removeImpulseJoint(joint, true);
1681
1685
  }
1682
1686
  }, []);
1683
1687
  return jointRef;
@@ -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
@@ -1167,7 +1171,7 @@ const AnyCollider = /*#__PURE__*/React.memo( /*#__PURE__*/React.forwardRef((prop
1167
1171
  colliderRef.current = collider;
1168
1172
  return collider;
1169
1173
  }, collider => {
1170
- world.removeCollider(collider);
1174
+ world.removeCollider(collider, true);
1171
1175
  }, [...immutablePropArray, rigidBodyContext]);
1172
1176
  React.useEffect(() => {
1173
1177
  const collider = getInstance();
@@ -1669,7 +1673,7 @@ const useImpulseJoint = (body1, body2, params) => {
1669
1673
  const jointRef = React.useRef();
1670
1674
  useImperativeInstance(() => {
1671
1675
  if (body1.current && body2.current) {
1672
- const newJoint = world.createImpulseJoint(params, body1.current, body2.current);
1676
+ const newJoint = world.createImpulseJoint(params, body1.current, body2.current, true);
1673
1677
  jointRef.current = newJoint; // console.log(body1.current, body2.current, newJoint);
1674
1678
 
1675
1679
  return newJoint;
@@ -1677,7 +1681,7 @@ const useImpulseJoint = (body1, body2, params) => {
1677
1681
  }, joint => {
1678
1682
  if (joint) {
1679
1683
  jointRef.current = undefined;
1680
- world.removeImpulseJoint(joint);
1684
+ world.removeImpulseJoint(joint, true);
1681
1685
  }
1682
1686
  }, []);
1683
1687
  return jointRef;
@@ -1,7 +1,7 @@
1
1
  import { ActiveEvents, ColliderDesc, EventQueue, RigidBodyDesc } from '@dimforge/rapier3d-compat';
2
2
  export { CoefficientCombineRule, Collider as RapierCollider, RigidBody as RapierRigidBody } from '@dimforge/rapier3d-compat';
3
3
  import { useFrame, useThree } from '@react-three/fiber';
4
- import React, { useRef, useEffect, memo, useMemo, useContext, useState, useCallback, createContext, forwardRef, Fragment } from 'react';
4
+ import React, { useRef, useEffect, memo, useMemo, useContext, useState, createContext, useCallback, forwardRef, Fragment } from 'react';
5
5
  import { Quaternion, Euler, Vector3, Object3D, Matrix4, BufferAttribute, MathUtils, DynamicDrawUsage } from 'three';
6
6
  import { useAsset } from 'use-asset';
7
7
  import { mergeVertices } from 'three-stdlib';
@@ -47,40 +47,6 @@ function _objectSpread2(target) {
47
47
  return target;
48
48
  }
49
49
 
50
- const createWorldApi = getWorld => {
51
- return {
52
- raw: () => getWorld(),
53
- getCollider: handle => getWorld().getCollider(handle),
54
- getRigidBody: handle => getWorld().getRigidBody(handle),
55
- createRigidBody: desc => getWorld().createRigidBody(desc),
56
- createCollider: (desc, rigidBody) => getWorld().createCollider(desc, rigidBody),
57
- removeRigidBody: rigidBody => {
58
- if (!getWorld().bodies.contains(rigidBody.handle)) return;
59
- getWorld().removeRigidBody(rigidBody);
60
- },
61
- removeCollider: (collider, wakeUp = true) => {
62
- if (!getWorld().colliders.contains(collider.handle)) return;
63
- getWorld().removeCollider(collider, wakeUp);
64
- },
65
- createImpulseJoint: (params, rigidBodyA, rigidBodyB, wakeUp = true) => getWorld().createImpulseJoint(params, rigidBodyA, rigidBodyB, wakeUp),
66
- removeImpulseJoint: (joint, wakeUp = true) => {
67
- if (!getWorld().impulseJoints.contains(joint.handle)) return;
68
- getWorld().removeImpulseJoint(joint, wakeUp);
69
- },
70
- forEachCollider: callback => getWorld().forEachCollider(callback),
71
- setGravity: ({
72
- x,
73
- y,
74
- z
75
- }) => getWorld().gravity = {
76
- x,
77
- y,
78
- z
79
- },
80
- debugRender: () => getWorld().debugRender()
81
- };
82
- };
83
-
84
50
  const _quaternion = new Quaternion();
85
51
  new Euler();
86
52
  const _vector3 = new Vector3();
@@ -659,30 +625,37 @@ const Debug = /*#__PURE__*/memo(() => {
659
625
  });
660
626
 
661
627
  /**
662
- * Initiate an instance and return a safe getter
628
+ * Creates a proxy that will create a singleton instance of the given class
629
+ * when a property is accessed, and not before.
630
+ *
631
+ * @returns A proxy and a reset function, so that the instance can created again
663
632
  */
633
+ const createSingletonProxy = createInstance => {
634
+ let instance;
635
+ const handler = {
636
+ get(target, prop) {
637
+ if (!instance) {
638
+ instance = createInstance();
639
+ }
664
640
 
665
- const useImperativeInstance = (createFn, destroyFn, dependencyList) => {
666
- const ref = useRef();
667
- const getInstance = useCallback(() => {
668
- if (!ref.current) {
669
- ref.current = createFn();
641
+ return Reflect.get(instance, prop);
670
642
  }
671
643
 
672
- return ref.current;
673
- }, dependencyList);
674
- useEffect(() => {
675
- // Save the destroy function and instance
676
- const instance = getInstance();
644
+ };
645
+ const proxy = new Proxy({}, handler);
677
646
 
678
- const destroy = () => destroyFn(instance);
647
+ const reset = () => {
648
+ instance = undefined;
649
+ };
650
+ /**
651
+ * Return the proxy and a reset function
652
+ */
679
653
 
680
- return () => {
681
- destroy();
682
- ref.current = undefined;
683
- };
684
- }, [getInstance]);
685
- return getInstance;
654
+
655
+ return {
656
+ proxy,
657
+ reset
658
+ };
686
659
  };
687
660
 
688
661
  const rapierContext = /*#__PURE__*/createContext(undefined);
@@ -734,38 +707,42 @@ const Physics = ({
734
707
  const rapier = useAsset(importRapier);
735
708
  const {
736
709
  invalidate
737
- } = useThree(); // Init World
738
-
739
- const getWorld = useImperativeInstance(() => {
740
- return new rapier.World(vectorArrayToVector3(_gravity));
741
- }, world => {
742
- world.free();
743
- }, []);
710
+ } = useThree();
744
711
  const rigidBodyStates = useConst(() => new Map());
745
712
  const colliderStates = useConst(() => new Map());
746
713
  const rigidBodyEvents = useConst(() => new Map());
747
714
  const colliderEvents = useConst(() => new Map());
748
715
  const eventQueue = useConst(() => new EventQueue(false));
749
716
  const beforeStepCallbacks = useConst(() => new Set());
750
- const afterStepCallbacks = useConst(() => new Set()); // Update gravity
717
+ const afterStepCallbacks = useConst(() => new Set());
718
+ /**
719
+ * Initiate the world
720
+ * This creates a singleton proxy, so that the world is only created when
721
+ * something within it is accessed.
722
+ */
751
723
 
724
+ const {
725
+ proxy: worldProxy,
726
+ reset: resetWorldProxy
727
+ } = useConst(() => createSingletonProxy(() => new rapier.World(vectorArrayToVector3(_gravity))));
752
728
  useEffect(() => {
753
- const world = getWorld();
729
+ return () => {
730
+ worldProxy.free();
731
+ resetWorldProxy();
732
+ };
733
+ }, []); // Update gravity
754
734
 
755
- if (world) {
756
- world.gravity = vectorArrayToVector3(_gravity);
757
- }
735
+ useEffect(() => {
736
+ worldProxy.gravity = vectorArrayToVector3(_gravity);
758
737
  }, [_gravity]);
759
- const api = useMemo(() => createWorldApi(getWorld), []);
760
738
  const getSourceFromColliderHandle = useCallback(handle => {
761
739
  var _collider$parent;
762
740
 
763
- const world = getWorld();
764
- const collider = world.getCollider(handle);
741
+ const collider = worldProxy.getCollider(handle);
765
742
  const colEvents = colliderEvents.get(handle);
766
743
  const colliderState = colliderStates.get(handle);
767
744
  const rigidBodyHandle = collider === null || collider === void 0 ? void 0 : (_collider$parent = collider.parent()) === null || _collider$parent === void 0 ? void 0 : _collider$parent.handle;
768
- const rigidBody = rigidBodyHandle !== undefined ? world.getRigidBody(rigidBodyHandle) : undefined;
745
+ const rigidBody = rigidBodyHandle !== undefined ? worldProxy.getRigidBody(rigidBodyHandle) : undefined;
769
746
  const rbEvents = rigidBody && rigidBodyHandle !== undefined ? rigidBodyEvents.get(rigidBodyHandle) : undefined;
770
747
  const rigidBodyState = rigidBodyHandle !== undefined ? rigidBodyStates.get(rigidBodyHandle) : undefined;
771
748
  const source = {
@@ -787,7 +764,7 @@ const Physics = ({
787
764
  accumulator: 0
788
765
  });
789
766
  const step = useCallback(dt => {
790
- const world = getWorld();
767
+ const world = worldProxy;
791
768
  /* Check if the timestep is supposed to be variable. We'll do this here
792
769
  once so we don't have to string-check every frame. */
793
770
 
@@ -802,12 +779,12 @@ const Physics = ({
802
779
  const stepWorld = () => {
803
780
  // Trigger beforeStep callbacks
804
781
  beforeStepCallbacks.forEach(callback => {
805
- callback.current(api);
782
+ callback.current(worldProxy);
806
783
  });
807
784
  world.step(eventQueue); // Trigger afterStep callbacks
808
785
 
809
786
  afterStepCallbacks.forEach(callback => {
810
- callback.current(api);
787
+ callback.current(worldProxy);
811
788
  });
812
789
  };
813
790
 
@@ -997,7 +974,7 @@ const Physics = ({
997
974
  }, [_paused, _timeStep, _interpolate]);
998
975
  const context = useMemo(() => ({
999
976
  rapier,
1000
- world: api,
977
+ world: worldProxy,
1001
978
  physicsOptions: {
1002
979
  colliders: _colliders,
1003
980
  gravity: _gravity
@@ -1043,6 +1020,33 @@ function _extends() {
1043
1020
  return _extends.apply(this, arguments);
1044
1021
  }
1045
1022
 
1023
+ /**
1024
+ * Initiate an instance and return a safe getter
1025
+ */
1026
+
1027
+ const useImperativeInstance = (createFn, destroyFn, dependencyList) => {
1028
+ const ref = useRef();
1029
+ const getInstance = useCallback(() => {
1030
+ if (!ref.current) {
1031
+ ref.current = createFn();
1032
+ }
1033
+
1034
+ return ref.current;
1035
+ }, dependencyList);
1036
+ useEffect(() => {
1037
+ // Save the destroy function and instance
1038
+ const instance = getInstance();
1039
+
1040
+ const destroy = () => destroyFn(instance);
1041
+
1042
+ return () => {
1043
+ destroy();
1044
+ ref.current = undefined;
1045
+ };
1046
+ }, [getInstance]);
1047
+ return getInstance;
1048
+ };
1049
+
1046
1050
  /**
1047
1051
  * Takes an object resembling a Vector3 and returs a Three.Vector3
1048
1052
  * @category Math helpers
@@ -1142,7 +1146,7 @@ const AnyCollider = /*#__PURE__*/memo( /*#__PURE__*/forwardRef((props, forwarded
1142
1146
  colliderRef.current = collider;
1143
1147
  return collider;
1144
1148
  }, collider => {
1145
- world.removeCollider(collider);
1149
+ world.removeCollider(collider, true);
1146
1150
  }, [...immutablePropArray, rigidBodyContext]);
1147
1151
  useEffect(() => {
1148
1152
  const collider = getInstance();
@@ -1644,7 +1648,7 @@ const useImpulseJoint = (body1, body2, params) => {
1644
1648
  const jointRef = useRef();
1645
1649
  useImperativeInstance(() => {
1646
1650
  if (body1.current && body2.current) {
1647
- const newJoint = world.createImpulseJoint(params, body1.current, body2.current);
1651
+ const newJoint = world.createImpulseJoint(params, body1.current, body2.current, true);
1648
1652
  jointRef.current = newJoint; // console.log(body1.current, body2.current, newJoint);
1649
1653
 
1650
1654
  return newJoint;
@@ -1652,7 +1656,7 @@ const useImpulseJoint = (body1, body2, params) => {
1652
1656
  }, joint => {
1653
1657
  if (joint) {
1654
1658
  jointRef.current = undefined;
1655
- world.removeImpulseJoint(joint);
1659
+ world.removeImpulseJoint(joint, true);
1656
1660
  }
1657
1661
  }, []);
1658
1662
  return jointRef;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-three/rapier",
3
- "version": "0.16.0-canary.1",
3
+ "version": "1.0.0-canary.2",
4
4
  "source": "src/index.ts",
5
5
  "main": "dist/react-three-rapier.cjs.js",
6
6
  "module": "dist/react-three-rapier.esm.js",
@@ -8,9 +8,7 @@
8
8
  "files": [
9
9
  "dist"
10
10
  ],
11
- "scripts": {
12
- "ts": "tsc -w"
13
- },
11
+ "scripts": {},
14
12
  "devDependencies": {
15
13
  "@react-three/drei": "9.45.0",
16
14
  "@react-three/fiber": "8.9.1",
@@ -1,17 +0,0 @@
1
- import { Collider, ColliderDesc, DebugRenderBuffers, ImpulseJoint, JointData, RigidBody, RigidBodyDesc, World } from "@dimforge/rapier3d-compat";
2
- import { Vector3 } from "three";
3
- export interface WorldApi {
4
- raw(): World;
5
- getCollider(handle: number): Collider | undefined;
6
- getRigidBody(handle: number): RigidBody | undefined;
7
- createRigidBody(desc: RigidBodyDesc): RigidBody;
8
- createCollider(desc: ColliderDesc, parent?: RigidBody): Collider;
9
- removeRigidBody(rigidBody: RigidBody): void;
10
- removeCollider(collider: Collider, wakeUp?: boolean): void;
11
- createImpulseJoint(params: JointData, rigidBodyA: RigidBody, rigidBodyB: RigidBody, wakeUp?: boolean): ImpulseJoint;
12
- removeImpulseJoint(joint: ImpulseJoint, wakeUp?: boolean): void;
13
- forEachCollider(callback: (collider: Collider) => void): void;
14
- setGravity(gravity: Vector3): void;
15
- debugRender(): DebugRenderBuffers;
16
- }
17
- export declare const createWorldApi: (getWorld: () => World) => WorldApi;