@threlte/rapier 1.0.0-next.0 → 1.0.0-next.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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # @threlte/extras
2
2
 
3
+ ## 1.0.0-next.1
4
+
5
+ ### Major Changes
6
+
7
+ - 4b67b473: Removed transform properties on rapier components Collider, AutoColliders and RigidBody
8
+
3
9
  ## 1.0.0-next.0
4
10
 
5
11
  ### Major Changes
@@ -1,19 +1,15 @@
1
1
  <script>import { ActiveCollisionTypes, CoefficientCombineRule } from '@dimforge/rapier3d-compat';
2
- import { SceneGraphObject } from '@threlte/core';
3
- import { createEventDispatcher, onDestroy, onMount } from 'svelte';
4
- import { Object3D } from 'three';
2
+ import { createRawEventDispatcher, SceneGraphObject } from '@threlte/core';
3
+ import { onDestroy, onMount } from 'svelte';
4
+ import { Group } from 'three';
5
5
  import { useCollisionGroups } from '../../hooks/useCollisionGroups';
6
6
  import { useHasEventListeners } from '../../hooks/useHasEventListener';
7
7
  import { useRapier } from '../../hooks/useRapier';
8
8
  import { useRigidBody } from '../../hooks/useRigidBody';
9
9
  import { applyColliderActiveEvents } from '../../lib/applyColliderActiveEvents';
10
- import { applyTransforms } from '../../lib/applyTransforms';
11
10
  import { createCollidersFromChildren } from '../../lib/createCollidersFromChildren';
12
11
  import { eulerToQuaternion } from '../../lib/eulerToQuaternion';
13
12
  export let shape = 'convexHull';
14
- export let position = undefined;
15
- export let rotation = undefined;
16
- export let scale = undefined;
17
13
  export let restitution = undefined;
18
14
  export let restitutionCombineRule = undefined;
19
15
  export let friction = undefined;
@@ -25,61 +21,61 @@ export let mass = undefined;
25
21
  export let centerOfMass = undefined;
26
22
  export let principalAngularInertia = undefined;
27
23
  export let angularInertiaLocalFrame = undefined;
28
- const object = new Object3D();
29
- /**
30
- * Immediately apply transforms
31
- */
32
- applyTransforms(object, position, rotation, scale);
33
- object.updateWorldMatrix(true, false);
24
+ const group = new Group();
34
25
  const rigidBody = useRigidBody();
35
26
  const { world, addColliderToContext, removeColliderFromContext } = useRapier();
36
27
  export let colliders = [];
37
28
  const collisionGroups = useCollisionGroups();
38
- const dispatcher = createEventDispatcher();
29
+ const dispatcher = createRawEventDispatcher();
39
30
  const { hasEventListeners: colliderHasEventListeners } = useHasEventListeners();
40
- onMount(() => {
41
- colliders = createCollidersFromChildren(object, shape ?? 'convexHull', world, rigidBody);
42
- colliders.forEach((c) => addColliderToContext(c, object, dispatcher));
43
- collisionGroups.registerColliders(colliders);
44
- });
45
- $: {
46
- if (colliders.length > 0) {
47
- colliders.forEach((collider) => {
48
- applyColliderActiveEvents(collider, colliderHasEventListeners, rigidBody?.userData?.hasEventListeners);
49
- collider.setActiveCollisionTypes(ActiveCollisionTypes.ALL);
50
- collider.setRestitution(restitution ?? 0);
51
- collider.setRestitutionCombineRule(restitutionCombineRule ?? CoefficientCombineRule.Average);
52
- collider.setFriction(friction ?? 0.7);
53
- collider.setFrictionCombineRule(frictionCombineRule ?? CoefficientCombineRule.Average);
54
- collider.setSensor(sensor ?? false);
55
- collider.setContactForceEventThreshold(contactForceEventThreshold ?? 0);
56
- if (density)
57
- collider.setDensity(density);
58
- if (mass) {
59
- if (centerOfMass && principalAngularInertia && angularInertiaLocalFrame)
60
- collider.setMassProperties(mass, { x: centerOfMass[0], y: centerOfMass[1], z: centerOfMass[2] }, {
61
- x: principalAngularInertia[0],
62
- y: principalAngularInertia[1],
63
- z: principalAngularInertia[2]
64
- }, eulerToQuaternion(angularInertiaLocalFrame));
65
- else
66
- collider.setMass(mass);
67
- }
68
- });
69
- }
70
- }
71
- /**
72
- * Cleanup
73
- */
74
- onDestroy(() => {
31
+ const cleanup = () => {
75
32
  collisionGroups.removeColliders(colliders);
76
33
  colliders.forEach((c) => {
77
34
  removeColliderFromContext(c);
78
35
  world.removeCollider(c, true);
79
36
  });
37
+ colliders.length = 0;
38
+ };
39
+ export const create = () => {
40
+ cleanup();
41
+ colliders = createCollidersFromChildren(group, shape ?? 'convexHull', world, rigidBody);
42
+ colliders.forEach((c) => addColliderToContext(c, group, dispatcher));
43
+ collisionGroups.registerColliders(colliders);
44
+ colliders.forEach((collider) => {
45
+ applyColliderActiveEvents(collider, colliderHasEventListeners, rigidBody?.userData?.hasEventListeners);
46
+ collider.setActiveCollisionTypes(ActiveCollisionTypes.ALL);
47
+ collider.setRestitution(restitution ?? 0);
48
+ collider.setRestitutionCombineRule(restitutionCombineRule ?? CoefficientCombineRule.Average);
49
+ collider.setFriction(friction ?? 0.7);
50
+ collider.setFrictionCombineRule(frictionCombineRule ?? CoefficientCombineRule.Average);
51
+ collider.setSensor(sensor ?? false);
52
+ collider.setContactForceEventThreshold(contactForceEventThreshold ?? 0);
53
+ if (density)
54
+ collider.setDensity(density);
55
+ if (mass) {
56
+ if (centerOfMass && principalAngularInertia && angularInertiaLocalFrame)
57
+ collider.setMassProperties(mass, { x: centerOfMass[0], y: centerOfMass[1], z: centerOfMass[2] }, {
58
+ x: principalAngularInertia[0],
59
+ y: principalAngularInertia[1],
60
+ z: principalAngularInertia[2]
61
+ }, eulerToQuaternion(angularInertiaLocalFrame));
62
+ else
63
+ collider.setMass(mass);
64
+ }
65
+ });
66
+ };
67
+ onMount(() => {
68
+ create();
80
69
  });
70
+ export const refresh = () => {
71
+ create();
72
+ };
73
+ /**
74
+ * Cleanup
75
+ */
76
+ onDestroy(cleanup);
81
77
  </script>
82
78
 
83
- <SceneGraphObject {object}>
84
- <slot />
79
+ <SceneGraphObject object={group}>
80
+ <slot {colliders} {refresh} />
85
81
  </SceneGraphObject>
@@ -1,16 +1,12 @@
1
1
  import type { CoefficientCombineRule, Collider } from '@dimforge/rapier3d-compat'
2
- import type { Position, Rotation } from '@threlte/core'
3
2
  import { SvelteComponentTyped } from 'svelte'
4
3
  import type { Euler, Vector3 } from 'three'
5
- import type { AutoCollidersShapes } from '../../types/types'
4
+ import type { AutoCollidersShapes, ColliderEventMap } from '../../types/types'
6
5
 
7
6
  // ------------------ BASE ------------------
8
7
 
9
8
  type BaseProps = {
10
9
  shape?: AutoCollidersShapes
11
- position?: Parameters<Vector3['set']>
12
- rotation?: Parameters<Euler['set']>
13
- scale?: Parameters<Vector3['set']>
14
10
  restitution?: number
15
11
  restitutionCombineRule?: CoefficientCombineRule
16
12
  friction?: number
@@ -18,6 +14,7 @@ type BaseProps = {
18
14
  sensor?: boolean
19
15
  colliders?: Collider[]
20
16
  contactForceEventThreshold?: number
17
+ refresh?: () => void
21
18
  }
22
19
 
23
20
  // ------------------ MASS ------------------
@@ -30,20 +27,20 @@ type Density = {
30
27
  principalAngularInertia?: never
31
28
  angularInertiaLocalFrame?: never
32
29
  }
30
+
33
31
  type Mass = {
34
32
  mass: number
35
-
36
33
  density?: never
37
34
  centerOfMass?: never
38
35
  principalAngularInertia?: never
39
36
  angularInertiaLocalFrame?: never
40
37
  }
38
+
41
39
  type MassProperties = {
42
40
  mass: number
43
41
  centerOfMass: Parameters<Vector3['set']>
44
42
  principalAngularInertia: Parameters<Vector3['set']>
45
43
  angularInertiaLocalFrame: Parameters<Euler['set']>
46
-
47
44
  density?: never
48
45
  }
49
46
 
@@ -69,6 +66,15 @@ type MassProps<TMassDef extends MassDef> = TMassDef extends Density
69
66
 
70
67
  export type AutoCollidersProps<TMassDef extends MassDef> = BaseProps & MassProps<TMassDef>
71
68
 
69
+ type AutoCollidersSlots = {
70
+ default: {
71
+ colliders: Collider[]
72
+ refresh: () => void
73
+ }
74
+ }
75
+
72
76
  export default class AutoColliders<TMassDef extends MassDef> extends SvelteComponentTyped<
73
- AutoCollidersProps<TMassDef>
77
+ AutoCollidersProps<TMassDef>,
78
+ ColliderEventMap,
79
+ AutoCollidersSlots
74
80
  > {}
@@ -1,21 +1,18 @@
1
1
  <script>import { ActiveCollisionTypes, CoefficientCombineRule, Collider, ColliderDesc } from '@dimforge/rapier3d-compat';
2
- import { SceneGraphObject, useFrame } from '@threlte/core';
3
- import { createEventDispatcher, onDestroy, onMount, tick } from 'svelte';
2
+ import { createRawEventDispatcher, SceneGraphObject, useFrame } from '@threlte/core';
3
+ import { onDestroy, onMount, tick } from 'svelte';
4
4
  import { Object3D, Quaternion, Vector3 } from 'three';
5
5
  import { useCollisionGroups } from '../../hooks/useCollisionGroups';
6
6
  import { useHasEventListeners } from '../../hooks/useHasEventListener';
7
7
  import { useRapier } from '../../hooks/useRapier';
8
8
  import { useRigidBody } from '../../hooks/useRigidBody';
9
9
  import { applyColliderActiveEvents } from '../../lib/applyColliderActiveEvents';
10
- import { applyTransforms } from '../../lib/applyTransforms';
11
10
  import { eulerToQuaternion } from '../../lib/eulerToQuaternion';
12
11
  import { getWorldPosition, getWorldQuaternion } from '../../lib/getWorldTransforms';
13
12
  import { scaleColliderArgs } from '../../lib/scaleColliderArgs';
14
13
  export let shape;
15
14
  export let args;
16
- export let position = undefined;
17
- export let rotation = undefined;
18
- export let scale = undefined;
15
+ export let type = undefined;
19
16
  export let restitution = undefined;
20
17
  export let restitutionCombineRule = undefined;
21
18
  export let friction = undefined;
@@ -28,18 +25,13 @@ export let centerOfMass = undefined;
28
25
  export let principalAngularInertia = undefined;
29
26
  export let angularInertiaLocalFrame = undefined;
30
27
  const object = new Object3D();
31
- /**
32
- * Immediately apply transforms
33
- */
34
- applyTransforms(object, position, rotation, scale);
35
- object.updateWorldMatrix(true, false);
36
28
  const rigidBody = useRigidBody();
37
- const isAttached = !!rigidBody;
29
+ const hasRigidBodyParent = !!rigidBody;
38
30
  const rapierContext = useRapier();
39
31
  const { world } = rapierContext;
40
32
  export let collider = undefined;
41
33
  const collisionGroups = useCollisionGroups();
42
- const dispatcher = createEventDispatcher();
34
+ const dispatcher = createRawEventDispatcher();
43
35
  /**
44
36
  * Actual collider setup happens onMount as only then
45
37
  * the transforms are finished.
@@ -59,7 +51,7 @@ onMount(async () => {
59
51
  * For use in conjunction with component <CollisionGroups>
60
52
  */
61
53
  collisionGroups.registerColliders([collider]);
62
- if (isAttached) {
54
+ if (hasRigidBodyParent) {
63
55
  const rigidBodyWorldPos = new Vector3();
64
56
  const rigidBodyWorldQuatInversed = new Quaternion();
65
57
  object.traverseAncestors((child) => {
@@ -109,19 +101,27 @@ $: {
109
101
  }
110
102
  }
111
103
  }
112
- /**
113
- * If the Collider isAttached (i.e. NOT child of a RigidBody), update the
114
- * transforms on every frame.
115
- */
116
- useFrame(() => {
104
+ export const refresh = () => {
117
105
  if (!collider)
118
106
  return;
119
- applyTransforms(object, position, rotation, scale);
120
107
  collider.setTranslation(getWorldPosition(object));
121
108
  collider.setRotation(getWorldQuaternion(object));
109
+ };
110
+ /**
111
+ * If the Collider isAttached (i.e. NOT child of a RigidBody), update the
112
+ * transforms on every frame.
113
+ */
114
+ const { start, stop } = useFrame(() => {
115
+ refresh();
122
116
  }, {
123
- autostart: !isAttached
117
+ autostart: !hasRigidBodyParent && type === 'dynamic'
124
118
  });
119
+ $: {
120
+ if (!hasRigidBodyParent && type === 'dynamic')
121
+ start();
122
+ else
123
+ stop();
124
+ }
125
125
  /**
126
126
  * Cleanup
127
127
  */
@@ -131,9 +131,10 @@ onDestroy(() => {
131
131
  rapierContext.removeColliderFromContext(collider);
132
132
  collisionGroups.removeColliders([collider]);
133
133
  world.removeCollider(collider, true);
134
+ collider = undefined;
134
135
  });
135
136
  </script>
136
137
 
137
138
  <SceneGraphObject {object}>
138
- <slot />
139
+ <slot {collider} />
139
140
  </SceneGraphObject>
@@ -1,24 +1,26 @@
1
1
  import type {
2
2
  CoefficientCombineRule,
3
- Collider as rapierCollider,
3
+ Collider as RapierCollider,
4
4
  ColliderDesc
5
5
  } from '@dimforge/rapier3d-compat'
6
6
  import { SvelteComponentTyped } from 'svelte'
7
7
  import type { Euler, Vector3 } from 'three'
8
+ import type { ColliderEventMap } from '../../types/types'
8
9
 
9
10
  // ------------------ BASE ------------------
10
11
 
12
+ type Type = 'static' | 'dynamic'
13
+
11
14
  type BaseProps = {
12
- position?: Parameters<Vector3['set']>
13
- rotation?: Parameters<Euler['set']>
14
- scale?: Parameters<Vector3['set']>
15
+ type?: Type
15
16
  restitution?: number
16
17
  restitutionCombineRule?: CoefficientCombineRule
17
18
  friction?: number
18
19
  frictionCombineRule?: CoefficientCombineRule
19
20
  sensor?: boolean
20
- collider?: rapierCollider
21
+ collider?: RapierCollider
21
22
  contactForceEventThreshold?: number
23
+ refresh?: () => void
22
24
  }
23
25
 
24
26
  // ------------------ SHAPE ------------------
@@ -54,7 +56,6 @@ type ShapeProps<TShape extends Shape> = {
54
56
 
55
57
  type Density = {
56
58
  density: number
57
-
58
59
  mass?: never
59
60
  centerOfMass?: never
60
61
  principalAngularInertia?: never
@@ -62,7 +63,6 @@ type Density = {
62
63
  }
63
64
  type Mass = {
64
65
  mass: number
65
-
66
66
  density?: never
67
67
  centerOfMass?: never
68
68
  principalAngularInertia?: never
@@ -73,7 +73,6 @@ type MassProperties = {
73
73
  centerOfMass: Parameters<Vector3['set']>
74
74
  principalAngularInertia: Parameters<Vector3['set']>
75
75
  angularInertiaLocalFrame: Parameters<Euler['set']>
76
-
77
76
  density?: never
78
77
  }
79
78
 
@@ -101,7 +100,13 @@ export type ColliderProps<TShape extends Shape, TMassDef extends MassDef> = Base
101
100
  ShapeProps<TShape> &
102
101
  MassProps<TMassDef>
103
102
 
103
+ export type ColliderSlots = {
104
+ default: {
105
+ collider: RapierCollider
106
+ }
107
+ }
108
+
104
109
  export default class Collider<
105
110
  TShape extends Shape,
106
111
  TMassDef extends MassDef
107
- > extends SvelteComponentTyped<ColliderProps<TShape, TMassDef>> {}
112
+ > extends SvelteComponentTyped<ColliderProps<TShape, TMassDef>, ColliderEventMap, ColliderSlots> {}
@@ -1,28 +1,9 @@
1
1
  <script>import { setContext } from 'svelte';
2
2
  import { writable } from 'svelte/store';
3
+ import { computeBitMask } from '../../lib/computeBitMask';
3
4
  export let groups = undefined;
4
5
  export let filter = undefined;
5
6
  export let memberships = undefined;
6
- const computeBitMask = (groups, filter, memberships) => {
7
- if (groups !== undefined) {
8
- // groups is setting the filter and memberships at once
9
- const g = groups;
10
- const mask = g.reduce((acc, f) => {
11
- return acc | (1 << f);
12
- }, 0) |
13
- g.reduce((acc, m) => {
14
- return acc | (1 << (m + 16));
15
- }, 0);
16
- return mask;
17
- }
18
- const mask = memberships.reduce((acc, f) => {
19
- return acc | (1 << f);
20
- }, 0) |
21
- filter.reduce((acc, m) => {
22
- return acc | (1 << (m + 16));
23
- }, 0);
24
- return mask;
25
- };
26
7
  const store = writable(computeBitMask(groups, filter, memberships));
27
8
  $: store.set(computeBitMask(groups, filter, memberships));
28
9
  setContext('threlte-rapier-collision-group', store);
@@ -1,15 +1,11 @@
1
- <script>import { SceneGraphObject } from '@threlte/core';
2
- import { createEventDispatcher, onDestroy, setContext, tick } from 'svelte';
1
+ <script>import { createRawEventDispatcher, SceneGraphObject } from '@threlte/core';
2
+ import { onDestroy, setContext, tick } from 'svelte';
3
3
  import { Object3D, Vector3 } from 'three';
4
4
  import { useHasEventListeners } from '../../hooks/useHasEventListener';
5
5
  import { useRapier } from '../../hooks/useRapier';
6
- import { applyTransforms } from '../../lib/applyTransforms';
7
6
  import { getWorldPosition, getWorldQuaternion, getWorldScale } from '../../lib/getWorldTransforms';
8
7
  import { parseRigidBodyType } from '../../lib/parseRigidBodyType';
9
8
  const { world, rapier, addRigidBodyToContext, removeRigidBodyFromContext } = useRapier();
10
- export let position = undefined;
11
- export let rotation = undefined;
12
- export let scale = undefined;
13
9
  export let linearVelocity = undefined;
14
10
  export let angularVelocity = undefined;
15
11
  export let type = 'dynamic';
@@ -23,7 +19,8 @@ export let lockTranslations = false;
23
19
  export let enabledRotations = [true, true, true];
24
20
  export let enabledTranslations = [true, true, true];
25
21
  export let dominance = 0;
26
- const dispatcher = createEventDispatcher();
22
+ export let enabled = true;
23
+ const dispatcher = createRawEventDispatcher();
27
24
  const object = new Object3D();
28
25
  /**
29
26
  * Used to traverseAncestors to restore transform
@@ -33,18 +30,6 @@ object.userData.isRigidBody = true;
33
30
  * isSleeping used for events "sleep" and "wake" in `useFrameHandler`
34
31
  */
35
32
  object.userData.isSleeping = false;
36
- /**
37
- * Immediately apply transforms to get the objects
38
- * world position to apply to the RigidBody.
39
- * This is a one-off operation as RigidBodies should
40
- * not be moved around after initialization.
41
- */
42
- applyTransforms(object, position, rotation, scale);
43
- /**
44
- * Update the world matrix of the object before applying
45
- * the world position to the RigidBody
46
- */
47
- object.updateWorldMatrix(true, false);
48
33
  /**
49
34
  * RigidBody Description
50
35
  */
@@ -62,7 +47,6 @@ const rigidBodyTemp = world.createRigidBody(desc);
62
47
  */
63
48
  const initPosition = async () => {
64
49
  await tick();
65
- applyTransforms(object, position, rotation, scale);
66
50
  object.updateMatrix();
67
51
  object.updateWorldMatrix(true, false);
68
52
  const parentWorldScale = object.parent ? getWorldScale(object.parent) : new Vector3(1, 1, 1);
@@ -80,22 +64,21 @@ object.userData.rigidBody = rigidBodyTemp;
80
64
  /**
81
65
  * Reactive RigidBody properties
82
66
  */
83
- $: {
84
- rigidBodyTemp.setBodyType(parseRigidBodyType(type));
85
- if (linearVelocity)
86
- rigidBodyTemp.setLinvel({ x: linearVelocity[0], y: linearVelocity[1], z: linearVelocity[2] }, true);
87
- if (angularVelocity)
88
- rigidBodyTemp.setAngvel({ x: angularVelocity[0], y: angularVelocity[1], z: angularVelocity[2] }, true);
89
- rigidBodyTemp.setGravityScale(gravityScale, true);
90
- rigidBodyTemp.enableCcd(ccd);
91
- rigidBodyTemp.setDominanceGroup(dominance);
92
- rigidBodyTemp.lockRotations(lockRotations, true);
93
- rigidBodyTemp.lockTranslations(lockTranslations, true);
94
- rigidBodyTemp.setEnabledRotations(...enabledRotations, true);
95
- rigidBodyTemp.setEnabledTranslations(...enabledTranslations, true);
96
- rigidBodyTemp.setAngularDamping(angularDamping);
97
- rigidBodyTemp.setLinearDamping(linearDamping);
98
- }
67
+ $: rigidBodyTemp.setBodyType(parseRigidBodyType(type), true);
68
+ $: if (linearVelocity)
69
+ rigidBodyTemp.setLinvel({ x: linearVelocity[0], y: linearVelocity[1], z: linearVelocity[2] }, true);
70
+ $: if (angularVelocity)
71
+ rigidBodyTemp.setAngvel({ x: angularVelocity[0], y: angularVelocity[1], z: angularVelocity[2] }, true);
72
+ $: rigidBodyTemp.setGravityScale(gravityScale, true);
73
+ $: rigidBodyTemp.enableCcd(ccd);
74
+ $: rigidBodyTemp.setDominanceGroup(dominance);
75
+ $: rigidBodyTemp.lockRotations(lockRotations, true);
76
+ $: rigidBodyTemp.lockTranslations(lockTranslations, true);
77
+ $: rigidBodyTemp.setEnabledRotations(...enabledRotations, true);
78
+ $: rigidBodyTemp.setEnabledTranslations(...enabledTranslations, true);
79
+ $: rigidBodyTemp.setAngularDamping(angularDamping);
80
+ $: rigidBodyTemp.setLinearDamping(linearDamping);
81
+ $: rigidBodyTemp.setEnabled(enabled);
99
82
  /**
100
83
  * Add userData to the rigidBody
101
84
  */
@@ -8,10 +8,6 @@ export type Boolean3Array = [x: boolean, y: boolean, z: boolean]
8
8
  export type RigidBodyProps = {
9
9
  rigidBody?: RapierRigidBody
10
10
 
11
- position?: Parameters<Vector3['set']>
12
- rotation?: Parameters<Euler['set']>
13
- scale?: Parameters<Vector3['set']>
14
-
15
11
  /**
16
12
  * Specify the type of this rigid body
17
13
  */
@@ -89,6 +85,11 @@ export type RigidBodyProps = {
89
85
  * values are 0.0 (no damping at all).
90
86
  */
91
87
  angularDamping?: number
88
+
89
+ /**
90
+ * Set the rigidBody as enabled or disabled.
91
+ */
92
+ enabled?: boolean
92
93
  }
93
94
 
94
95
  export default class RigidBody extends SvelteComponentTyped<RigidBodyProps> {}
@@ -20,12 +20,13 @@ export let rawQueryPipeline = undefined;
20
20
  export let rawPhysicsPipeline = undefined;
21
21
  export let rawSerializationPipeline = undefined;
22
22
  export let rawDebugRenderPipeline = undefined;
23
+ export let order = undefined;
23
24
  const rapierContext = createRapierContext({ x: gravity[0], y: gravity[1], z: gravity[2] }, rawIntegrationParameters, rawIslands, rawBroadPhase, rawNarrowPhase, rawBodies, rawColliders, rawImpulseJoints, rawMultibodyJoints, rawCCDSolver, rawQueryPipeline, rawPhysicsPipeline, rawSerializationPipeline, rawDebugRenderPipeline);
24
25
  setContext('threlte-rapier-context', rapierContext);
25
26
  $: if (gravity !== undefined) {
26
27
  rapierContext.world.gravity = { x: gravity[0], y: gravity[1], z: gravity[2] };
27
28
  }
28
- useFrameHandler(rapierContext);
29
+ useFrameHandler(rapierContext, order);
29
30
  onDestroy(async () => {
30
31
  await tick();
31
32
  rapierContext.world.free();
@@ -15,6 +15,7 @@ declare const __propDef: {
15
15
  rawPhysicsPipeline?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawPhysicsPipeline | undefined;
16
16
  rawSerializationPipeline?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawSerializationPipeline | undefined;
17
17
  rawDebugRenderPipeline?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawDebugRenderPipeline | undefined;
18
+ order?: number | undefined;
18
19
  };
19
20
  events: {
20
21
  [evt: string]: CustomEvent<any>;
@@ -26,6 +26,12 @@ export let rawQueryPipeline = undefined;
26
26
  export let rawPhysicsPipeline = undefined;
27
27
  export let rawSerializationPipeline = undefined;
28
28
  export let rawDebugRenderPipeline = undefined;
29
+ /**
30
+ * The property order is passed to the useFrame handler.
31
+ * Use this to control when the rapier physics engine is updating the scene.
32
+ * @default undefined
33
+ */
34
+ export let order = undefined;
29
35
  let error = false;
30
36
  const init = async () => {
31
37
  if ($initialized)
@@ -57,6 +63,7 @@ onMount(init);
57
63
  {rawPhysicsPipeline}
58
64
  {rawSerializationPipeline}
59
65
  {rawDebugRenderPipeline}
66
+ {order}
60
67
  >
61
68
  <slot />
62
69
  </InnerWorld>
@@ -31,6 +31,7 @@ export type WorldProps = {
31
31
  rawPhysicsPipeline?: RawPhysicsPipeline
32
32
  rawSerializationPipeline?: RawSerializationPipeline
33
33
  rawDebugRenderPipeline?: RawDebugRenderPipeline
34
+ order?: number
34
35
  }
35
36
 
36
37
  export default class World extends SvelteComponentTyped<WorldProps> {}
@@ -1,2 +1,2 @@
1
1
  import type { RapierContext } from '../types/types';
2
- export declare const useFrameHandler: (ctx: RapierContext) => void;
2
+ export declare const useFrameHandler: (ctx: RapierContext, order?: number) => void;
@@ -1,5 +1,6 @@
1
1
  import { Collider, EventQueue } from '@dimforge/rapier3d-compat';
2
2
  import { useFrame } from '@threlte/core';
3
+ import { derived } from 'svelte/store';
3
4
  import { Object3D, Quaternion, Vector3 } from 'three';
4
5
  const tempObject = new Object3D();
5
6
  const tempVector3 = new Vector3();
@@ -22,17 +23,14 @@ const getEventDispatchers = (ctx, collider1, collider2) => {
22
23
  rigidBodyDispatcher2
23
24
  };
24
25
  };
25
- export const useFrameHandler = (ctx) => {
26
+ export const useFrameHandler = (ctx, order) => {
26
27
  const eventQueue = new EventQueue(false);
27
- let time = performance.now();
28
- useFrame(() => {
28
+ const { start, started, stop } = useFrame((_, delta) => {
29
29
  // if (!eventQueue) return
30
30
  const { world } = ctx;
31
31
  // Set timestep to current delta, to allow for variable frame rates
32
32
  // We cap the delta at 100, so that the physics simulation doesn't get wild
33
- const now = performance.now();
34
- const delta = Math.min(100, now - time);
35
- world.timestep = delta / 1000;
33
+ world.timestep = Math.min(0.1, delta);
36
34
  world.step(eventQueue);
37
35
  // Update meshes
38
36
  ctx.rigidBodyObjects.forEach((mesh, handle) => {
@@ -227,6 +225,9 @@ export const useFrameHandler = (ctx) => {
227
225
  });
228
226
  }
229
227
  });
230
- time = now;
231
- });
228
+ }, { order });
229
+ // replacing the original pause and resume functions as well as the paused property
230
+ ctx.pause = () => stop();
231
+ ctx.resume = () => start();
232
+ ctx.paused = derived(started, (started) => !started);
232
233
  };
package/dist/index.d.ts CHANGED
@@ -13,6 +13,7 @@ export { default as Collider } from './components/Colliders/Collider.svelte';
13
13
  export { default as AutoColliders } from './components/Colliders/AutoColliders.svelte';
14
14
  export { default as CollisionGroups } from './components/CollisionGroups/CollisionGroups.svelte';
15
15
  export { default as Attractor } from './components/Attractor/Attractor.svelte';
16
+ export { computeBitMask } from './lib/computeBitMask';
16
17
  export { default as BasicPlayerController } from './recipes/BasicPlayerController.svelte';
17
18
  export type { AutoCollidersProperties, AttractorProperties } from './types/components';
18
19
  export type { CollisionGroupsBitMask, AutoCollidersShapes, ColliderEventDispatcher, ColliderShapes, RapierContext, RigidBodyEventDispatcher, CollisionEnterEvent, CollisionExitEvent, SensorEnterEvent, SensorExitEvent, ContactEvent } from './types/types';
package/dist/index.js CHANGED
@@ -16,5 +16,7 @@ export { default as Collider } from './components/Colliders/Collider.svelte';
16
16
  export { default as AutoColliders } from './components/Colliders/AutoColliders.svelte';
17
17
  export { default as CollisionGroups } from './components/CollisionGroups/CollisionGroups.svelte';
18
18
  export { default as Attractor } from './components/Attractor/Attractor.svelte';
19
+ // lib
20
+ export { computeBitMask } from './lib/computeBitMask';
19
21
  // recipes
20
22
  export { default as BasicPlayerController } from './recipes/BasicPlayerController.svelte';
@@ -0,0 +1,5 @@
1
+ declare type N = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15;
2
+ export declare type Groups = N[];
3
+ export declare type MembershipsAndFilter = N[];
4
+ export declare const computeBitMask: (groups: Groups, filter: MembershipsAndFilter, memberships: MembershipsAndFilter) => number;
5
+ export {};
@@ -0,0 +1,20 @@
1
+ export const computeBitMask = (groups, filter, memberships) => {
2
+ if (groups !== undefined) {
3
+ // groups is setting the filter and memberships at once
4
+ const g = groups;
5
+ const mask = g.reduce((acc, f) => {
6
+ return acc | (1 << f);
7
+ }, 0) |
8
+ g.reduce((acc, m) => {
9
+ return acc | (1 << (m + 16));
10
+ }, 0);
11
+ return mask;
12
+ }
13
+ const mask = memberships.reduce((acc, f) => {
14
+ return acc | (1 << f);
15
+ }, 0) |
16
+ filter.reduce((acc, m) => {
17
+ return acc | (1 << (m + 16));
18
+ }, 0);
19
+ return mask;
20
+ };
@@ -14,4 +14,7 @@ export declare const createRapierContext: (gravity: RAPIER.Vector, rawIntegratio
14
14
  addRigidBodyToContext: (rigidBody: RigidBody, object: Object3D, eventDispatcher: RigidBodyEventDispatcher) => void;
15
15
  removeRigidBodyFromContext: (rigidBody: RigidBody) => void;
16
16
  debug: import("svelte/store").Writable<boolean>;
17
+ pause: () => void;
18
+ resume: () => void;
19
+ paused: import("svelte/store").Readable<boolean>;
17
20
  };
@@ -1,5 +1,6 @@
1
1
  import RAPIER from '@dimforge/rapier3d-compat';
2
- import { writable } from 'svelte/store';
2
+ import { currentWritable } from '@threlte/core';
3
+ import { readable, writable } from 'svelte/store';
3
4
  export const createRapierContext = (...args) => {
4
5
  const world = new RAPIER.World(...args);
5
6
  const colliderObjects = new Map();
@@ -42,6 +43,11 @@ export const createRapierContext = (...args) => {
42
43
  rigidBodyObjects.delete(rigidBody.handle);
43
44
  rigidBodyEventDispatchers.delete(rigidBody.handle);
44
45
  };
46
+ // Dummy functions, will be replaced by useFrameHandler fn
47
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
48
+ const pause = () => { };
49
+ // eslint-disable-next-line @typescript-eslint/no-empty-function
50
+ const resume = () => { };
45
51
  return {
46
52
  rapier: RAPIER,
47
53
  world,
@@ -54,5 +60,8 @@ export const createRapierContext = (...args) => {
54
60
  addRigidBodyToContext,
55
61
  removeRigidBodyFromContext,
56
62
  debug: writable(false),
63
+ pause,
64
+ resume,
65
+ paused: readable(false)
57
66
  };
58
67
  };
@@ -21,5 +21,5 @@ export const scaleColliderArgs = (shape, args, scale) => {
21
21
  return newArgs;
22
22
  }
23
23
  const scaleArray = [scale.x, scale.y, scale.z];
24
- return newArgs.map((arg, index) => scaleArray[index] * arg);
24
+ return newArgs.map((arg, index) => (scaleArray[index] ?? 1) * arg);
25
25
  };
@@ -1,5 +1,4 @@
1
- <script>import { T, useFrame, useThrelte } from '@threlte/core';
2
- import { createEventDispatcher } from 'svelte';
1
+ <script>import { createRawEventDispatcher, T, useFrame, useThrelte } from '@threlte/core';
3
2
  import { Vector2, Vector3 } from 'three';
4
3
  import Collider from '../components/Colliders/Collider.svelte';
5
4
  import CollisionGroups from '../components/CollisionGroups/CollisionGroups.svelte';
@@ -23,7 +22,7 @@ const keys = {
23
22
  };
24
23
  const t = new Vector3();
25
24
  const t2 = new Vector2();
26
- const dispatch = createEventDispatcher();
25
+ const dispatch = createRawEventDispatcher();
27
26
  let grounded = false;
28
27
  let groundsSensored = 0;
29
28
  $: {
@@ -99,37 +98,33 @@ const onKeyUp = (e) => {
99
98
  };
100
99
  </script>
101
100
 
102
- <svelte:window
103
- on:keydown|preventDefault={onKeyDown}
104
- on:keyup|preventDefault={onKeyUp}
105
- />
101
+ <svelte:window on:keydown|preventDefault={onKeyDown} on:keyup|preventDefault={onKeyUp} />
106
102
 
107
- <RigidBody
108
- dominance={127}
109
- enabledRotations={[false, false, false]}
110
- bind:rigidBody
111
- {position}
112
- type={'dynamic'}
113
- >
114
- <CollisionGroups groups={playerCollisionGroups}>
115
- <Collider
116
- shape={'capsule'}
117
- args={[height / 2 - radius, radius]}
118
- />
119
- </CollisionGroups>
103
+ <T.Group {position}>
104
+ <RigidBody
105
+ dominance={127}
106
+ enabledRotations={[false, false, false]}
107
+ bind:rigidBody
108
+ type={'dynamic'}
109
+ >
110
+ <CollisionGroups groups={playerCollisionGroups}>
111
+ <Collider shape={'capsule'} args={[height / 2 - radius, radius]} />
112
+ </CollisionGroups>
120
113
 
121
- <CollisionGroups groups={groundCollisionGroups}>
122
- <Collider
123
- sensor
124
- on:sensorenter={() => (groundsSensored += 1)}
125
- on:sensorexit={() => (groundsSensored -= 1)}
126
- shape={'ball'}
127
- args={[radius * 1.2]}
128
- position={[0, -height / 2 + radius, 0]}
129
- />
130
- </CollisionGroups>
114
+ <CollisionGroups groups={groundCollisionGroups}>
115
+ <T.Group position={[0, -height / 2 + radius, 0]}>
116
+ <Collider
117
+ sensor
118
+ on:sensorenter={() => (groundsSensored += 1)}
119
+ on:sensorexit={() => (groundsSensored -= 1)}
120
+ shape={'ball'}
121
+ args={[radius * 1.2]}
122
+ />
123
+ </T.Group>
124
+ </CollisionGroups>
131
125
 
132
- <T.Group position.y={-height / 2}>
133
- <slot />
134
- </T.Group>
135
- </RigidBody>
126
+ <T.Group position.y={-height / 2}>
127
+ <slot />
128
+ </T.Group>
129
+ </RigidBody>
130
+ </T.Group>
@@ -12,9 +12,6 @@ declare const __propDef: {
12
12
  groundCollisionGroups?: CollisionGroupsBitMask | undefined;
13
13
  };
14
14
  events: {
15
- groundenter: CustomEvent<void>;
16
- groundexit: CustomEvent<void>;
17
- } & {
18
15
  [evt: string]: CustomEvent<any>;
19
16
  };
20
17
  slots: {
@@ -1,8 +1,8 @@
1
- import type { createEventDispatcher } from 'svelte';
2
- import type { RigidBody, RigidBodyHandle, TempContactManifold, ColliderHandle, Collider, Vector } from '@dimforge/rapier3d-compat';
3
- import type { createRapierContext } from '../lib/createRapierContext';
1
+ import type { Collider, ColliderHandle, RigidBody, RigidBodyHandle, TempContactManifold, Vector } from '@dimforge/rapier3d-compat';
2
+ import type { createRawEventDispatcher } from '@threlte/core';
4
3
  import type { Writable } from 'svelte/store';
5
4
  import type { useHasEventListeners } from '../hooks/useHasEventListener';
5
+ import type { createRapierContext } from '../lib/createRapierContext';
6
6
  export declare type ColliderShapes = 'ball' | 'capsule' | 'segment' | 'triangle' | 'roundTriangle' | 'polyline' | 'trimesh' | 'cuboid' | 'roundCuboid' | 'heightfield' | 'cylinder' | 'roundCylinder' | 'cone' | 'roundCone' | 'convexHull' | 'convexMesh' | 'roundConvexHull' | 'roundConvexMesh';
7
7
  export declare type AutoCollidersShapes = 'cuboid' | 'ball' | 'trimesh' | 'convexHull' | 'capsule';
8
8
  export declare type ColliderEventMap = {
@@ -42,8 +42,8 @@ export declare type RigidBodyEventMap = ColliderEventMap & {
42
42
  sleep: void;
43
43
  wake: void;
44
44
  };
45
- export declare type RigidBodyEventDispatcher = ReturnType<typeof createEventDispatcher<RigidBodyEventMap>>;
46
- export declare type ColliderEventDispatcher = ReturnType<typeof createEventDispatcher<ColliderEventMap>>;
45
+ export declare type RigidBodyEventDispatcher = ReturnType<typeof createRawEventDispatcher<RigidBodyEventMap>>;
46
+ export declare type ColliderEventDispatcher = ReturnType<typeof createRawEventDispatcher<ColliderEventMap>>;
47
47
  export declare type RigidBodyEventDispatchers = Map<RigidBodyHandle, RigidBodyEventDispatcher>;
48
48
  export declare type ColliderEventDispatchers = Map<ColliderHandle, ColliderEventDispatcher>;
49
49
  export declare type RapierContext = ReturnType<typeof createRapierContext>;
package/package.json CHANGED
@@ -1,14 +1,14 @@
1
1
  {
2
2
  "name": "@threlte/rapier",
3
- "version": "1.0.0-next.0",
3
+ "version": "1.0.0-next.1",
4
4
  "author": "Grischa Erbe <hello@legrisch.com> (https://legrisch.com)",
5
5
  "license": "MIT",
6
6
  "devDependencies": {
7
- "@dimforge/rapier3d-compat": "^0.9.0",
7
+ "@dimforge/rapier3d-compat": "^0.11.2",
8
8
  "@sveltejs/adapter-auto": "1.0.0-next.61",
9
9
  "@sveltejs/adapter-static": "1.0.0-next.35",
10
10
  "@sveltejs/kit": "1.0.0-next.377",
11
- "@threlte/core": "6.0.0-next.0",
11
+ "@threlte/core": "6.0.0-next.2",
12
12
  "@types/node": "^18.0.3",
13
13
  "@types/three": "^0.144.0",
14
14
  "@typescript-eslint/eslint-plugin": "^4.31.1",
@@ -23,7 +23,7 @@
23
23
  "svelte-check": "^2.7.0",
24
24
  "svelte-preprocess": "^4.10.5",
25
25
  "svelte2tsx": "^0.5.9",
26
- "three": "^0.145.0",
26
+ "three": "^0.151.3",
27
27
  "ts-node": "^10.8.2",
28
28
  "tsafe": "^0.9.0",
29
29
  "tslib": "^2.3.1",