@react-three/rapier 0.10.0 → 0.11.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.
@@ -109,6 +109,7 @@ interface RapierWorldProps {
109
109
  /**
110
110
  * The update priority at which the physics simulation should run.
111
111
  *
112
+ * @see https://docs.pmnd.rs/react-three-fiber/api/hooks#taking-over-the-render-loop
112
113
  * @defaultValue undefined
113
114
  */
114
115
  updatePriority?: number;
@@ -8,3 +8,4 @@ export declare const rapierQuaternionToQuaternion: ({ x, y, z, w }: RapierQuater
8
8
  export declare const rigidBodyTypeFromString: (type: RigidBodyTypeString) => number;
9
9
  export declare const scaleVertices: (vertices: ArrayLike<number>, scale: Vector3) => number[];
10
10
  export declare const vectorToTuple: (v: Vector3 | Quaternion | any[] | undefined | number | Euler) => any[];
11
+ export declare function useConst<T>(initialValue: T | (() => T)): T;
@@ -131,6 +131,17 @@ const vectorToTuple = v => {
131
131
 
132
132
  return [v];
133
133
  };
134
+ function useConst(initialValue) {
135
+ const ref = React.useRef();
136
+
137
+ if (ref.current === undefined) {
138
+ ref.current = {
139
+ value: typeof initialValue === "function" ? initialValue() : initialValue
140
+ };
141
+ }
142
+
143
+ return ref.current.value;
144
+ }
134
145
 
135
146
  const createRigidBodyApi = ref => {
136
147
  return {
@@ -580,7 +591,9 @@ const useColliderEvents = (collidersRef, props, events) => {
580
591
 
581
592
  const rigidBodyDescFromOptions = options => {
582
593
  const type = rigidBodyTypeFromString((options === null || options === void 0 ? void 0 : options.type) || "dynamic");
583
- const desc = new rapier3dCompat.RigidBodyDesc(type);
594
+ const desc = new rapier3dCompat.RigidBodyDesc(type); // Apply immutable options
595
+
596
+ desc.canSleep = (options === null || options === void 0 ? void 0 : options.canSleep) || true;
584
597
  return desc;
585
598
  };
586
599
  const createRigidBodyState = ({
@@ -620,6 +633,12 @@ const mutableRigidBodyOptions = {
620
633
  enabledTranslations: (rb, [x, y, z]) => {
621
634
  rb.setEnabledTranslations(x, y, z, true);
622
635
  },
636
+ lockRotations: (rb, value) => {
637
+ rb.lockRotations(value, true);
638
+ },
639
+ lockTranslations: (rb, value) => {
640
+ rb.lockTranslations(value, true);
641
+ },
623
642
  angularVelocity: (rb, [x, y, z]) => {
624
643
  rb.setAngvel({
625
644
  x,
@@ -640,6 +659,11 @@ const mutableRigidBodyOptions = {
640
659
  userData: (rb, value) => {
641
660
  rb.userData = value;
642
661
  },
662
+
663
+ type(rb, value) {
664
+ rb.setBodyType(rigidBodyTypeFromString(value));
665
+ },
666
+
643
667
  position: () => {},
644
668
  rotation: () => {},
645
669
  quaternion: () => {},
@@ -1013,12 +1037,12 @@ const Physics = ({
1013
1037
 
1014
1038
  return worldRef.current;
1015
1039
  });
1016
- const [rigidBodyStates] = React.useState(() => new Map());
1017
- const [colliderStates] = React.useState(() => new Map());
1018
- const [rigidBodyEvents] = React.useState(() => new Map());
1019
- const [colliderEvents] = React.useState(() => new Map());
1020
- const [eventQueue] = React.useState(() => new rapier3dCompat.EventQueue(false));
1021
- const [attractorStates] = React.useState(() => new Map()); // Init world
1040
+ const rigidBodyStates = useConst(() => new Map());
1041
+ const colliderStates = useConst(() => new Map());
1042
+ const rigidBodyEvents = useConst(() => new Map());
1043
+ const colliderEvents = useConst(() => new Map());
1044
+ const eventQueue = useConst(() => new rapier3dCompat.EventQueue(false));
1045
+ const attractorStates = useConst(() => new Map()); // Init world
1022
1046
 
1023
1047
  React.useEffect(() => {
1024
1048
  const world = getWorldRef.current();
@@ -131,6 +131,17 @@ const vectorToTuple = v => {
131
131
 
132
132
  return [v];
133
133
  };
134
+ function useConst(initialValue) {
135
+ const ref = React.useRef();
136
+
137
+ if (ref.current === undefined) {
138
+ ref.current = {
139
+ value: typeof initialValue === "function" ? initialValue() : initialValue
140
+ };
141
+ }
142
+
143
+ return ref.current.value;
144
+ }
134
145
 
135
146
  const createRigidBodyApi = ref => {
136
147
  return {
@@ -580,7 +591,9 @@ const useColliderEvents = (collidersRef, props, events) => {
580
591
 
581
592
  const rigidBodyDescFromOptions = options => {
582
593
  const type = rigidBodyTypeFromString((options === null || options === void 0 ? void 0 : options.type) || "dynamic");
583
- const desc = new rapier3dCompat.RigidBodyDesc(type);
594
+ const desc = new rapier3dCompat.RigidBodyDesc(type); // Apply immutable options
595
+
596
+ desc.canSleep = (options === null || options === void 0 ? void 0 : options.canSleep) || true;
584
597
  return desc;
585
598
  };
586
599
  const createRigidBodyState = ({
@@ -620,6 +633,12 @@ const mutableRigidBodyOptions = {
620
633
  enabledTranslations: (rb, [x, y, z]) => {
621
634
  rb.setEnabledTranslations(x, y, z, true);
622
635
  },
636
+ lockRotations: (rb, value) => {
637
+ rb.lockRotations(value, true);
638
+ },
639
+ lockTranslations: (rb, value) => {
640
+ rb.lockTranslations(value, true);
641
+ },
623
642
  angularVelocity: (rb, [x, y, z]) => {
624
643
  rb.setAngvel({
625
644
  x,
@@ -640,6 +659,11 @@ const mutableRigidBodyOptions = {
640
659
  userData: (rb, value) => {
641
660
  rb.userData = value;
642
661
  },
662
+
663
+ type(rb, value) {
664
+ rb.setBodyType(rigidBodyTypeFromString(value));
665
+ },
666
+
643
667
  position: () => {},
644
668
  rotation: () => {},
645
669
  quaternion: () => {},
@@ -1013,12 +1037,12 @@ const Physics = ({
1013
1037
 
1014
1038
  return worldRef.current;
1015
1039
  });
1016
- const [rigidBodyStates] = React.useState(() => new Map());
1017
- const [colliderStates] = React.useState(() => new Map());
1018
- const [rigidBodyEvents] = React.useState(() => new Map());
1019
- const [colliderEvents] = React.useState(() => new Map());
1020
- const [eventQueue] = React.useState(() => new rapier3dCompat.EventQueue(false));
1021
- const [attractorStates] = React.useState(() => new Map()); // Init world
1040
+ const rigidBodyStates = useConst(() => new Map());
1041
+ const colliderStates = useConst(() => new Map());
1042
+ const rigidBodyEvents = useConst(() => new Map());
1043
+ const colliderEvents = useConst(() => new Map());
1044
+ const eventQueue = useConst(() => new rapier3dCompat.EventQueue(false));
1045
+ const attractorStates = useConst(() => new Map()); // Init world
1022
1046
 
1023
1047
  React.useEffect(() => {
1024
1048
  const world = getWorldRef.current();
@@ -1,7 +1,7 @@
1
1
  import { ColliderDesc, ActiveEvents, RigidBodyDesc, EventQueue } 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, { useMemo, useEffect, useContext, useState, useRef, memo, createContext, useCallback, forwardRef, useImperativeHandle, useLayoutEffect } from 'react';
4
+ import React, { useRef, useMemo, useEffect, useContext, useState, memo, createContext, useCallback, forwardRef, useImperativeHandle, useLayoutEffect } from 'react';
5
5
  import { Quaternion, Euler, Vector3, Object3D, Matrix4, MathUtils, InstancedMesh, BufferAttribute, DynamicDrawUsage } from 'three';
6
6
  import { useAsset } from 'use-asset';
7
7
  import { mergeVertices, VertexNormalsHelper } from 'three-stdlib';
@@ -106,6 +106,17 @@ const vectorToTuple = v => {
106
106
 
107
107
  return [v];
108
108
  };
109
+ function useConst(initialValue) {
110
+ const ref = useRef();
111
+
112
+ if (ref.current === undefined) {
113
+ ref.current = {
114
+ value: typeof initialValue === "function" ? initialValue() : initialValue
115
+ };
116
+ }
117
+
118
+ return ref.current.value;
119
+ }
109
120
 
110
121
  const createRigidBodyApi = ref => {
111
122
  return {
@@ -555,7 +566,9 @@ const useColliderEvents = (collidersRef, props, events) => {
555
566
 
556
567
  const rigidBodyDescFromOptions = options => {
557
568
  const type = rigidBodyTypeFromString((options === null || options === void 0 ? void 0 : options.type) || "dynamic");
558
- const desc = new RigidBodyDesc(type);
569
+ const desc = new RigidBodyDesc(type); // Apply immutable options
570
+
571
+ desc.canSleep = (options === null || options === void 0 ? void 0 : options.canSleep) || true;
559
572
  return desc;
560
573
  };
561
574
  const createRigidBodyState = ({
@@ -595,6 +608,12 @@ const mutableRigidBodyOptions = {
595
608
  enabledTranslations: (rb, [x, y, z]) => {
596
609
  rb.setEnabledTranslations(x, y, z, true);
597
610
  },
611
+ lockRotations: (rb, value) => {
612
+ rb.lockRotations(value, true);
613
+ },
614
+ lockTranslations: (rb, value) => {
615
+ rb.lockTranslations(value, true);
616
+ },
598
617
  angularVelocity: (rb, [x, y, z]) => {
599
618
  rb.setAngvel({
600
619
  x,
@@ -615,6 +634,11 @@ const mutableRigidBodyOptions = {
615
634
  userData: (rb, value) => {
616
635
  rb.userData = value;
617
636
  },
637
+
638
+ type(rb, value) {
639
+ rb.setBodyType(rigidBodyTypeFromString(value));
640
+ },
641
+
618
642
  position: () => {},
619
643
  rotation: () => {},
620
644
  quaternion: () => {},
@@ -988,12 +1012,12 @@ const Physics = ({
988
1012
 
989
1013
  return worldRef.current;
990
1014
  });
991
- const [rigidBodyStates] = useState(() => new Map());
992
- const [colliderStates] = useState(() => new Map());
993
- const [rigidBodyEvents] = useState(() => new Map());
994
- const [colliderEvents] = useState(() => new Map());
995
- const [eventQueue] = useState(() => new EventQueue(false));
996
- const [attractorStates] = useState(() => new Map()); // Init world
1015
+ const rigidBodyStates = useConst(() => new Map());
1016
+ const colliderStates = useConst(() => new Map());
1017
+ const rigidBodyEvents = useConst(() => new Map());
1018
+ const colliderEvents = useConst(() => new Map());
1019
+ const eventQueue = useConst(() => new EventQueue(false));
1020
+ const attractorStates = useConst(() => new Map()); // Init world
997
1021
 
998
1022
  useEffect(() => {
999
1023
  const world = getWorldRef.current();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-three/rapier",
3
- "version": "0.10.0",
3
+ "version": "0.11.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",
@@ -12,18 +12,18 @@
12
12
  "ts": "tsc -w"
13
13
  },
14
14
  "devDependencies": {
15
- "@react-three/drei": "^9.34.1",
16
- "@react-three/fiber": "^8.8.9",
15
+ "@react-three/drei": "9.45.0",
16
+ "@react-three/fiber": "8.9.1",
17
17
  "@react-three/test-renderer": "^8.0.17",
18
18
  "@types/react-dom": "^18.0.2",
19
19
  "@types/three": "^0.139.0",
20
20
  "@vitejs/plugin-react": "^2.1.0",
21
- "@vitest/ui": "^0.24.1",
21
+ "@vitest/ui": "^0.25.2",
22
22
  "happy-dom": "^7.5.5",
23
- "react": "^18.1.0",
24
- "react-dom": "^18.1.0",
25
- "three": "^0.139.2",
26
- "vitest": "^0.24.1"
23
+ "react": "18.2.0",
24
+ "react-dom": "18.2.0",
25
+ "three": "0.146.0",
26
+ "vitest": "^0.25.2"
27
27
  },
28
28
  "peerDependencies": {
29
29
  "@react-three/fiber": "^8.0.12",
@@ -31,7 +31,7 @@
31
31
  "three": ">=0.139.2"
32
32
  },
33
33
  "dependencies": {
34
- "@dimforge/rapier3d-compat": "0.9.0",
34
+ "@dimforge/rapier3d-compat": "0.10.0",
35
35
  "three-stdlib": "^2.15.0",
36
36
  "use-asset": "^1.0.4"
37
37
  },
package/readme.md CHANGED
@@ -41,19 +41,51 @@ const App = () => {
41
41
 
42
42
  ## Readme Topics
43
43
 
44
- - [Automatic Colliders](#automatic-colliders)
44
+ - [Basic Usage](#basic-usage)
45
+ - [Readme Topics](#readme-topics)
46
+ - [The Physics Component](#the-physics-component)
47
+ - [Automatic colliders](#automatic-colliders)
48
+ - [Collider Examples](#collider-examples)
45
49
  - [Instanced Meshes](#instanced-meshes)
46
50
  - [Debug](#debug)
47
51
  - [Collision Events](#collision-events)
48
- - [Collision Groups](#configuring-collision-and-solver-groups)
49
- - [Contact Force Events](#contact-force-events)
52
+ - [Configuring collision and solver groups](#configuring-collision-and-solver-groups)
53
+ - [Contact force events](#contact-force-events)
50
54
  - [Sensors](#sensors)
55
+ - [Sensors Example](#sensors-example)
51
56
  - [Attractors](#attractors)
52
- - [The timeStep](#configuring-time-step-size)
57
+ - [Attractors Example](#attractors-example)
58
+ - [Configuring Time Step Size](#configuring-time-step-size)
53
59
  - [Manual stepping](#manual-stepping)
60
+ - [Joints](#joints)
61
+ - [Joints Example](#joints-example)
54
62
 
55
63
  ---
56
64
 
65
+ ## The Physics Component
66
+ The `<Physics />` component is the root component of your physics world. It is responsible for creating the physics world and managing the simulation. It relies on lazily initiating `Rapier` and needs to be wrapped in `<Suspense />`.
67
+
68
+ ```tsx
69
+ // The gravity of the physics workd
70
+ gravity?: Vector3Array; // default [0, -9.81, 0]
71
+
72
+ // Which collider shape to generate for meshes by default
73
+ colliders?: RigidBodyAutoCollider; // default "cuboid"
74
+
75
+ // The number of physics steps per second
76
+ timeStep?: number | "vary"; // default 1/60
77
+
78
+ // Pause the physic simulation
79
+ paused?: boolean; // default false
80
+
81
+ // Which order to run the physics simulation
82
+ updatePriority?: number;
83
+
84
+ // If the physics updates slower than the monitor refreshes,
85
+ // interpolation will smooth out the steps between frames
86
+ interpolate?: boolean; // default true
87
+ ```
88
+
57
89
  ## Automatic colliders
58
90
 
59
91
  RigidBodies generate automatic colliders by default for all meshes that it contains. You can control the default collider by setting the `colliders` prop on a `<RigidBody />`, or change it globally by setting `colliders` on `<Physics />`. Setting `colliders={false}` disables auto-generation.
@@ -149,6 +181,10 @@ If part of our meshes are invisible and you want to include them in the collider
149
181
  </RigidBody>
150
182
  ```
151
183
 
184
+ ### Collider Examples
185
+ <a href="https://codesandbox.io/s/react-three-rapier-auto-colliders-b4coz1"><img src="https://raw.githubusercontent.com/pmndrs/react-three-rapier/HEAD/packages/react-three-rapier/misc/example-auto-colliders.jpg" width="240" /></a>
186
+ <a href="https://codesandbox.io/s/react-three-rapier-compound-colliders-ol5ybn"><img src="https://raw.githubusercontent.com/pmndrs/react-three-rapier/HEAD/packages/react-three-rapier/misc/example-compound-shapes.jpg" width="240" /></a>
187
+
152
188
  ## Instanced Meshes
153
189
 
154
190
  Instanced meshes can also be used and have automatic colliders generated from their mesh.
@@ -393,6 +429,9 @@ To detect when a collider enters or leaves another collider, you can use the `on
393
429
  </RigidBody>
394
430
  ```
395
431
 
432
+ ### Sensors Example
433
+ <a href="https://codesandbox.io/s/react-three-rapier-sensors-byjmsk"><img src="https://raw.githubusercontent.com/pmndrs/react-three-rapier/HEAD/packages/react-three-rapier/misc/example-sensors.jpg" width="240" /></a>
434
+
396
435
  ## Attractors
397
436
 
398
437
  An attractor simulates a source of gravity. Any `RigidBody` within range will be _pulled_ (attracted) toward the attractor.
@@ -427,6 +466,9 @@ Gravity types:
427
466
  - `mass2` is the mass of the rigid-body at the time of calculation. Note that rigid-bodies with colliders will use the mass provided to the collider. This is not a value you can control from the attractor, only from wherever you're creating rigid-body components in the scene.
428
467
  - `distance` is the distance between the attractor and rigid-body at the time of calculation
429
468
 
469
+ ### Attractors Example
470
+ <a href="https://codesandbox.io/s/react-three-rapier-attractors-oyj640"><img src="https://raw.githubusercontent.com/pmndrs/react-three-rapier/HEAD/packages/react-three-rapier/misc/example-attractors.jpg" width="240" /></a>
471
+
430
472
  ## Configuring Time Step Size
431
473
 
432
474
  By default, `<Physics>` will simulate the physics world at a fixed rate of 60 frames per second. This can be changed by setting the `timeStep` prop on `<Physics>`:
@@ -455,4 +497,7 @@ step(1 / 60);
455
497
 
456
498
  ## Joints
457
499
 
458
- WIP
500
+ - WIP
501
+
502
+ ### Joints Example
503
+ <a href="https://codesandbox.io/s/react-three-rapier-sensors-byjmsk"><img src="https://raw.githubusercontent.com/pmndrs/react-three-rapier/HEAD/packages/react-three-rapier/misc/example-joints.jpg" width="240" /></a>