@threlte/rapier 0.0.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/LICENSE.md +21 -0
- package/README.md +19 -0
- package/dist/CHANGELOG.md +103 -0
- package/dist/LICENSE.md +21 -0
- package/dist/README.md +19 -0
- package/dist/components/Colliders/AutoColliders.svelte +74 -0
- package/dist/components/Colliders/AutoColliders.svelte.d.ts +33 -0
- package/dist/components/Colliders/Collider.svelte +119 -0
- package/dist/components/Colliders/Collider.svelte.d.ts +32 -0
- package/dist/components/CollisionGroups/CollisionGroups.svelte +31 -0
- package/dist/components/CollisionGroups/CollisionGroups.svelte.d.ts +21 -0
- package/dist/components/Debug/Debug.svelte +30 -0
- package/dist/components/Debug/Debug.svelte.d.ts +60 -0
- package/dist/components/RigidBody/RigidBody.svelte +111 -0
- package/dist/components/RigidBody/RigidBody.svelte.d.ts +39 -0
- package/dist/components/World/InnerWorld.svelte +32 -0
- package/dist/components/World/InnerWorld.svelte.d.ts +32 -0
- package/dist/components/World/World.svelte +63 -0
- package/dist/components/World/World.svelte.d.ts +33 -0
- package/dist/hooks/useCollisionGroups.d.ts +5 -0
- package/dist/hooks/useCollisionGroups.js +52 -0
- package/dist/hooks/useFrameHandler.d.ts +2 -0
- package/dist/hooks/useFrameHandler.js +176 -0
- package/dist/hooks/useRapier.d.ts +2 -0
- package/dist/hooks/useRapier.js +4 -0
- package/dist/hooks/useRigidBody.d.ts +2 -0
- package/dist/hooks/useRigidBody.js +4 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +13 -0
- package/dist/lib/applyTransforms.d.ts +3 -0
- package/dist/lib/applyTransforms.js +17 -0
- package/dist/lib/createCollidersFromChildren.d.ts +16 -0
- package/dist/lib/createCollidersFromChildren.js +94 -0
- package/dist/lib/createRapierContext.d.ts +16 -0
- package/dist/lib/createRapierContext.js +56 -0
- package/dist/lib/getWorldTransforms.d.ts +41 -0
- package/dist/lib/getWorldTransforms.js +55 -0
- package/dist/lib/parseRigidBodyType.d.ts +3 -0
- package/dist/lib/parseRigidBodyType.js +10 -0
- package/dist/lib/positionToVector3.d.ts +3 -0
- package/dist/lib/positionToVector3.js +8 -0
- package/dist/lib/rotationToEuler.d.ts +3 -0
- package/dist/lib/rotationToEuler.js +8 -0
- package/dist/lib/rotationToQuaternion.d.ts +3 -0
- package/dist/lib/rotationToQuaternion.js +10 -0
- package/dist/lib/scaleColliderArgs.d.ts +5 -0
- package/dist/lib/scaleColliderArgs.js +25 -0
- package/dist/lib/scaleToVector3.d.ts +3 -0
- package/dist/lib/scaleToVector3.js +16 -0
- package/dist/recipes/BasicPlayerController.svelte +129 -0
- package/dist/recipes/BasicPlayerController.svelte.d.ts +29 -0
- package/dist/types/components.d.ts +131 -0
- package/dist/types/components.js +1 -0
- package/dist/types/types.d.ts +38 -0
- package/dist/types/types.js +1 -0
- package/package.json +50 -0
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
<script>import { LayerableObject, SceneGraphObject } from '@threlte/core';
|
|
2
|
+
import { createEventDispatcher, onDestroy, setContext } from 'svelte';
|
|
3
|
+
import { Object3D, Vector3 } from 'three';
|
|
4
|
+
import { useRapier } from '../../hooks/useRapier';
|
|
5
|
+
import { applyTransforms } from '../../lib/applyTransforms';
|
|
6
|
+
import { getWorldPosition, getWorldQuaternion } from '../../lib/getWorldTransforms';
|
|
7
|
+
import { parseRigidBodyType } from '../../lib/parseRigidBodyType';
|
|
8
|
+
import { positionToVector3 } from '../../lib/positionToVector3';
|
|
9
|
+
import { rotationToEuler } from '../../lib/rotationToEuler';
|
|
10
|
+
const { world, rapier, addRigidBodyToContext, removeRigidBodyFromContext } = useRapier();
|
|
11
|
+
export let type = 'dynamic';
|
|
12
|
+
export let canSleep = true;
|
|
13
|
+
export let linearVelocity = {};
|
|
14
|
+
export let angularVelocity = {};
|
|
15
|
+
export let gravityScale = 1;
|
|
16
|
+
export let ccd = false;
|
|
17
|
+
export let position = undefined;
|
|
18
|
+
export let rotation = undefined;
|
|
19
|
+
export let scale = undefined;
|
|
20
|
+
export let lookAt = undefined;
|
|
21
|
+
export let lockRotations = false;
|
|
22
|
+
export let lockTranslations = false;
|
|
23
|
+
export let enabledRotations = [
|
|
24
|
+
true,
|
|
25
|
+
true,
|
|
26
|
+
true
|
|
27
|
+
];
|
|
28
|
+
export let enabledTranslations = [
|
|
29
|
+
true,
|
|
30
|
+
true,
|
|
31
|
+
true
|
|
32
|
+
];
|
|
33
|
+
export let dominance = 0;
|
|
34
|
+
const dispatcher = createEventDispatcher();
|
|
35
|
+
const object = new Object3D();
|
|
36
|
+
/**
|
|
37
|
+
* Used to traverseAncestors to restore transform
|
|
38
|
+
*/
|
|
39
|
+
object.userData.isRigidBody = true;
|
|
40
|
+
/**
|
|
41
|
+
* isSleeping used for events "sleep" and "wake" in `useFrameHandler`
|
|
42
|
+
*/
|
|
43
|
+
object.userData.isSleeping = false;
|
|
44
|
+
/**
|
|
45
|
+
* Immediately apply transforms to get the objects
|
|
46
|
+
* world position to apply to the RigidBody.
|
|
47
|
+
* This is a one-off operation as RigidBodies should
|
|
48
|
+
* not be moved around after initialization.
|
|
49
|
+
*/
|
|
50
|
+
applyTransforms(object, position, rotation, scale, lookAt);
|
|
51
|
+
/**
|
|
52
|
+
* Update the world matrix of the object before applying
|
|
53
|
+
* the world position to the RigidBody
|
|
54
|
+
*/
|
|
55
|
+
object.updateWorldMatrix(true, false);
|
|
56
|
+
const worldPosition = getWorldPosition(object);
|
|
57
|
+
const worldRotation = getWorldQuaternion(object);
|
|
58
|
+
const parentWorldScale = object.parent?.getWorldScale(new Vector3()) || new Vector3(1, 1, 1);
|
|
59
|
+
/**
|
|
60
|
+
* RigidBody Description
|
|
61
|
+
*/
|
|
62
|
+
const desc = new rapier.RigidBodyDesc(parseRigidBodyType(type))
|
|
63
|
+
.setCanSleep(canSleep)
|
|
64
|
+
.setTranslation(worldPosition.x * parentWorldScale.x, worldPosition.y * parentWorldScale.y, worldPosition.z * parentWorldScale.z)
|
|
65
|
+
.setRotation({ x: worldRotation.x, y: worldRotation.y, z: worldRotation.z, w: worldRotation.w });
|
|
66
|
+
/**
|
|
67
|
+
* RigidBody init
|
|
68
|
+
*/
|
|
69
|
+
export const rigidBody = world.createRigidBody(desc);
|
|
70
|
+
/**
|
|
71
|
+
* Will come in handy in the future for joints
|
|
72
|
+
*/
|
|
73
|
+
object.userData.rigidBody = rigidBody;
|
|
74
|
+
/**
|
|
75
|
+
* Reactive RigidBody properties
|
|
76
|
+
*/
|
|
77
|
+
$: {
|
|
78
|
+
rigidBody.setBodyType(parseRigidBodyType(type));
|
|
79
|
+
rigidBody.setLinvel(positionToVector3(linearVelocity), true);
|
|
80
|
+
rigidBody.setAngvel(rotationToEuler(angularVelocity), true);
|
|
81
|
+
rigidBody.setGravityScale(gravityScale, true);
|
|
82
|
+
rigidBody.enableCcd(ccd);
|
|
83
|
+
rigidBody.setDominanceGroup(dominance);
|
|
84
|
+
rigidBody.lockRotations(lockRotations, true);
|
|
85
|
+
rigidBody.lockTranslations(lockTranslations, true);
|
|
86
|
+
rigidBody.setEnabledRotations(...enabledRotations, true);
|
|
87
|
+
rigidBody.setEnabledTranslations(...enabledTranslations, true);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Setting the RigidBody context so that colliders can
|
|
91
|
+
* hook onto.
|
|
92
|
+
*/
|
|
93
|
+
setContext('threlte-rapier-rigidbody', rigidBody);
|
|
94
|
+
/**
|
|
95
|
+
* Add the mesh to the context
|
|
96
|
+
*/
|
|
97
|
+
addRigidBodyToContext(rigidBody, object, dispatcher);
|
|
98
|
+
/**
|
|
99
|
+
* cleanup
|
|
100
|
+
*/
|
|
101
|
+
onDestroy(() => {
|
|
102
|
+
removeRigidBodyFromContext(rigidBody);
|
|
103
|
+
world.removeRigidBody(rigidBody);
|
|
104
|
+
});
|
|
105
|
+
</script>
|
|
106
|
+
|
|
107
|
+
<SceneGraphObject {object}>
|
|
108
|
+
<slot />
|
|
109
|
+
</SceneGraphObject>
|
|
110
|
+
|
|
111
|
+
<LayerableObject {object} />
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
import type { RigidBodyProperties } from '../../types/components';
|
|
3
|
+
import type { RigidBodyEventMap } from '../../types/types';
|
|
4
|
+
declare const __propDef: {
|
|
5
|
+
props: {
|
|
6
|
+
type?: import("../../lib/parseRigidBodyType").RigidBodyTypeString | undefined;
|
|
7
|
+
canSleep?: boolean | undefined;
|
|
8
|
+
linearVelocity?: import("@threlte/core").Position | undefined;
|
|
9
|
+
angularVelocity?: import("@threlte/core").Rotation | undefined;
|
|
10
|
+
gravityScale?: number | undefined;
|
|
11
|
+
ccd?: boolean | undefined;
|
|
12
|
+
position?: RigidBodyProperties['position'];
|
|
13
|
+
rotation?: RigidBodyProperties['rotation'];
|
|
14
|
+
scale?: RigidBodyProperties['scale'];
|
|
15
|
+
lookAt?: RigidBodyProperties['lookAt'];
|
|
16
|
+
lockRotations?: boolean | undefined;
|
|
17
|
+
lockTranslations?: boolean | undefined;
|
|
18
|
+
enabledRotations?: import("../../types/components").Boolean3Array | undefined;
|
|
19
|
+
enabledTranslations?: import("../../types/components").Boolean3Array | undefined;
|
|
20
|
+
dominance?: number | undefined;
|
|
21
|
+
/**
|
|
22
|
+
* RigidBody init
|
|
23
|
+
*/ rigidBody?: import("@dimforge/rapier3d-compat").RigidBody | undefined;
|
|
24
|
+
};
|
|
25
|
+
slots: {
|
|
26
|
+
default: {};
|
|
27
|
+
};
|
|
28
|
+
getters: {
|
|
29
|
+
rigidBody: import("@dimforge/rapier3d-compat").RigidBody;
|
|
30
|
+
};
|
|
31
|
+
events: RigidBodyEventMap;
|
|
32
|
+
};
|
|
33
|
+
export declare type RigidBodyProps = typeof __propDef.props;
|
|
34
|
+
export declare type RigidBodyEvents = typeof __propDef.events;
|
|
35
|
+
export declare type RigidBodySlots = typeof __propDef.slots;
|
|
36
|
+
export default class RigidBody extends SvelteComponentTyped<RigidBodyProps, RigidBodyEvents, RigidBodySlots> {
|
|
37
|
+
get rigidBody(): import("@dimforge/rapier3d-compat").RigidBody;
|
|
38
|
+
}
|
|
39
|
+
export {};
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
<script context="module">import { onDestroy, setContext, tick } from 'svelte';
|
|
2
|
+
import { useFrameHandler } from '../../hooks/useFrameHandler';
|
|
3
|
+
import { createRapierContext } from '../../lib/createRapierContext';
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<script>import { positionToVector3 } from '../../lib/positionToVector3';
|
|
7
|
+
export let gravity = { y: -9.81 };
|
|
8
|
+
export let rawIntegrationParameters = undefined;
|
|
9
|
+
export let rawIslands = undefined;
|
|
10
|
+
export let rawBroadPhase = undefined;
|
|
11
|
+
export let rawNarrowPhase = undefined;
|
|
12
|
+
export let rawBodies = undefined;
|
|
13
|
+
export let rawColliders = undefined;
|
|
14
|
+
export let rawImpulseJoints = undefined;
|
|
15
|
+
export let rawMultibodyJoints = undefined;
|
|
16
|
+
export let rawCCDSolver = undefined;
|
|
17
|
+
export let rawQueryPipeline = undefined;
|
|
18
|
+
export let rawPhysicsPipeline = undefined;
|
|
19
|
+
export let rawSerializationPipeline = undefined;
|
|
20
|
+
export let rawDebugRenderPipeline = undefined;
|
|
21
|
+
const rapierContext = createRapierContext(positionToVector3(gravity), rawIntegrationParameters, rawIslands, rawBroadPhase, rawNarrowPhase, rawBodies, rawColliders, rawImpulseJoints, rawMultibodyJoints, rawCCDSolver, rawQueryPipeline, rawPhysicsPipeline, rawSerializationPipeline, rawDebugRenderPipeline);
|
|
22
|
+
setContext('threlte-rapier-context', rapierContext);
|
|
23
|
+
$: if (gravity !== undefined)
|
|
24
|
+
rapierContext.world.gravity = positionToVector3(gravity);
|
|
25
|
+
useFrameHandler(rapierContext);
|
|
26
|
+
onDestroy(async () => {
|
|
27
|
+
await tick();
|
|
28
|
+
rapierContext.world.free();
|
|
29
|
+
});
|
|
30
|
+
</script>
|
|
31
|
+
|
|
32
|
+
<slot />
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
import type { InnerWorldProperties } from '../../types/components';
|
|
3
|
+
declare const __propDef: {
|
|
4
|
+
props: {
|
|
5
|
+
gravity?: InnerWorldProperties['gravity'];
|
|
6
|
+
rawIntegrationParameters?: InnerWorldProperties['rawIntegrationParameters'];
|
|
7
|
+
rawIslands?: InnerWorldProperties['rawIslands'];
|
|
8
|
+
rawBroadPhase?: InnerWorldProperties['rawBroadPhase'];
|
|
9
|
+
rawNarrowPhase?: InnerWorldProperties['rawNarrowPhase'];
|
|
10
|
+
rawBodies?: InnerWorldProperties['rawBodies'];
|
|
11
|
+
rawColliders?: InnerWorldProperties['rawColliders'];
|
|
12
|
+
rawImpulseJoints?: InnerWorldProperties['rawImpulseJoints'];
|
|
13
|
+
rawMultibodyJoints?: InnerWorldProperties['rawMultibodyJoints'];
|
|
14
|
+
rawCCDSolver?: InnerWorldProperties['rawCCDSolver'];
|
|
15
|
+
rawQueryPipeline?: InnerWorldProperties['rawQueryPipeline'];
|
|
16
|
+
rawPhysicsPipeline?: InnerWorldProperties['rawPhysicsPipeline'];
|
|
17
|
+
rawSerializationPipeline?: InnerWorldProperties['rawSerializationPipeline'];
|
|
18
|
+
rawDebugRenderPipeline?: InnerWorldProperties['rawDebugRenderPipeline'];
|
|
19
|
+
};
|
|
20
|
+
events: {
|
|
21
|
+
[evt: string]: CustomEvent<any>;
|
|
22
|
+
};
|
|
23
|
+
slots: {
|
|
24
|
+
default: {};
|
|
25
|
+
};
|
|
26
|
+
};
|
|
27
|
+
export declare type InnerWorldProps = typeof __propDef.props;
|
|
28
|
+
export declare type InnerWorldEvents = typeof __propDef.events;
|
|
29
|
+
export declare type InnerWorldSlots = typeof __propDef.slots;
|
|
30
|
+
export default class InnerWorld extends SvelteComponentTyped<InnerWorldProps, InnerWorldEvents, InnerWorldSlots> {
|
|
31
|
+
}
|
|
32
|
+
export {};
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
<script context="module">import RAPIER from '@dimforge/rapier3d-compat';
|
|
2
|
+
import { onMount } from 'svelte';
|
|
3
|
+
import { writable } from 'svelte/store';
|
|
4
|
+
/**
|
|
5
|
+
* RAPIER.init() should only be called once
|
|
6
|
+
*/
|
|
7
|
+
let initialized = writable(false);
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<script>import InnerWorld from './InnerWorld.svelte';
|
|
11
|
+
export let gravity = undefined;
|
|
12
|
+
export let rawIntegrationParameters = undefined;
|
|
13
|
+
export let rawIslands = undefined;
|
|
14
|
+
export let rawBroadPhase = undefined;
|
|
15
|
+
export let rawNarrowPhase = undefined;
|
|
16
|
+
export let rawBodies = undefined;
|
|
17
|
+
export let rawColliders = undefined;
|
|
18
|
+
export let rawImpulseJoints = undefined;
|
|
19
|
+
export let rawMultibodyJoints = undefined;
|
|
20
|
+
export let rawCCDSolver = undefined;
|
|
21
|
+
export let rawQueryPipeline = undefined;
|
|
22
|
+
export let rawPhysicsPipeline = undefined;
|
|
23
|
+
export let rawSerializationPipeline = undefined;
|
|
24
|
+
export let rawDebugRenderPipeline = undefined;
|
|
25
|
+
let error = false;
|
|
26
|
+
const init = async () => {
|
|
27
|
+
if ($initialized)
|
|
28
|
+
return;
|
|
29
|
+
try {
|
|
30
|
+
await RAPIER.init();
|
|
31
|
+
$initialized = true;
|
|
32
|
+
}
|
|
33
|
+
catch (e) {
|
|
34
|
+
error = true;
|
|
35
|
+
}
|
|
36
|
+
};
|
|
37
|
+
onMount(init);
|
|
38
|
+
</script>
|
|
39
|
+
|
|
40
|
+
{#if $initialized}
|
|
41
|
+
<InnerWorld
|
|
42
|
+
{gravity}
|
|
43
|
+
{rawIntegrationParameters}
|
|
44
|
+
{rawIslands}
|
|
45
|
+
{rawBroadPhase}
|
|
46
|
+
{rawNarrowPhase}
|
|
47
|
+
{rawBodies}
|
|
48
|
+
{rawColliders}
|
|
49
|
+
{rawImpulseJoints}
|
|
50
|
+
{rawMultibodyJoints}
|
|
51
|
+
{rawCCDSolver}
|
|
52
|
+
{rawQueryPipeline}
|
|
53
|
+
{rawPhysicsPipeline}
|
|
54
|
+
{rawSerializationPipeline}
|
|
55
|
+
{rawDebugRenderPipeline}
|
|
56
|
+
>
|
|
57
|
+
<slot />
|
|
58
|
+
</InnerWorld>
|
|
59
|
+
{/if}
|
|
60
|
+
|
|
61
|
+
{#if error}
|
|
62
|
+
<slot name="fallback" />
|
|
63
|
+
{/if}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
import type { WorldProperties } from '../../types/components';
|
|
3
|
+
declare const __propDef: {
|
|
4
|
+
props: {
|
|
5
|
+
gravity?: WorldProperties['gravity'];
|
|
6
|
+
rawIntegrationParameters?: WorldProperties['rawIntegrationParameters'];
|
|
7
|
+
rawIslands?: WorldProperties['rawIslands'];
|
|
8
|
+
rawBroadPhase?: WorldProperties['rawBroadPhase'];
|
|
9
|
+
rawNarrowPhase?: WorldProperties['rawNarrowPhase'];
|
|
10
|
+
rawBodies?: WorldProperties['rawBodies'];
|
|
11
|
+
rawColliders?: WorldProperties['rawColliders'];
|
|
12
|
+
rawImpulseJoints?: WorldProperties['rawImpulseJoints'];
|
|
13
|
+
rawMultibodyJoints?: WorldProperties['rawMultibodyJoints'];
|
|
14
|
+
rawCCDSolver?: WorldProperties['rawCCDSolver'];
|
|
15
|
+
rawQueryPipeline?: WorldProperties['rawQueryPipeline'];
|
|
16
|
+
rawPhysicsPipeline?: WorldProperties['rawPhysicsPipeline'];
|
|
17
|
+
rawSerializationPipeline?: WorldProperties['rawSerializationPipeline'];
|
|
18
|
+
rawDebugRenderPipeline?: WorldProperties['rawDebugRenderPipeline'];
|
|
19
|
+
};
|
|
20
|
+
events: {
|
|
21
|
+
[evt: string]: CustomEvent<any>;
|
|
22
|
+
};
|
|
23
|
+
slots: {
|
|
24
|
+
default: {};
|
|
25
|
+
fallback: {};
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
export declare type WorldProps = typeof __propDef.props;
|
|
29
|
+
export declare type WorldEvents = typeof __propDef.events;
|
|
30
|
+
export declare type WorldSlots = typeof __propDef.slots;
|
|
31
|
+
export default class World extends SvelteComponentTyped<WorldProps, WorldEvents, WorldSlots> {
|
|
32
|
+
}
|
|
33
|
+
export {};
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { getContext, onDestroy } from 'svelte';
|
|
2
|
+
import { get } from 'svelte/store';
|
|
3
|
+
const applyBitMask = (collidersMap, bitMask) => {
|
|
4
|
+
collidersMap.forEach((c) => {
|
|
5
|
+
if (c && c.collider && c.collider.isValid()) {
|
|
6
|
+
c.collider.setCollisionGroups(bitMask);
|
|
7
|
+
}
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
export const useCollisionGroups = () => {
|
|
11
|
+
const collidersMap = new Map();
|
|
12
|
+
const bitMaskStore = getContext('threlte-rapier-collision-group');
|
|
13
|
+
if (!bitMaskStore)
|
|
14
|
+
return {
|
|
15
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
16
|
+
registerColliders: (colliders) => { },
|
|
17
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-function
|
|
18
|
+
removeColliders: (colliders) => { }
|
|
19
|
+
};
|
|
20
|
+
let bitMask = get(bitMaskStore);
|
|
21
|
+
const unsubscribe = bitMaskStore.subscribe((newBitMask) => {
|
|
22
|
+
bitMask = newBitMask;
|
|
23
|
+
applyBitMask(collidersMap, newBitMask);
|
|
24
|
+
});
|
|
25
|
+
onDestroy(unsubscribe);
|
|
26
|
+
const registerColliders = (colliders) => {
|
|
27
|
+
colliders.forEach((c) => {
|
|
28
|
+
if (!collidersMap.has(c.handle)) {
|
|
29
|
+
collidersMap.set(c.handle, {
|
|
30
|
+
collider: c,
|
|
31
|
+
initialCollisionGroup: c.collisionGroups()
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
applyBitMask(collidersMap, bitMask);
|
|
36
|
+
};
|
|
37
|
+
const removeColliders = (colliders) => {
|
|
38
|
+
colliders.forEach((c) => {
|
|
39
|
+
const mapItem = collidersMap.get(c.handle);
|
|
40
|
+
if (mapItem) {
|
|
41
|
+
if (c && c.isValid()) {
|
|
42
|
+
c.setCollisionGroups(mapItem.initialCollisionGroup);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
collidersMap.delete(c.handle);
|
|
46
|
+
});
|
|
47
|
+
};
|
|
48
|
+
return {
|
|
49
|
+
registerColliders,
|
|
50
|
+
removeColliders
|
|
51
|
+
};
|
|
52
|
+
};
|
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
import { EventQueue } from '@dimforge/rapier3d-compat';
|
|
2
|
+
import { useFrame } from '@threlte/core';
|
|
3
|
+
import { Object3D, Quaternion, Vector3 } from 'three';
|
|
4
|
+
const tempObject = new Object3D();
|
|
5
|
+
const tempVector3 = new Vector3();
|
|
6
|
+
const tempQuaternion = new Quaternion();
|
|
7
|
+
export const useFrameHandler = (ctx) => {
|
|
8
|
+
const eventQueue = new EventQueue(false);
|
|
9
|
+
let time = performance.now();
|
|
10
|
+
useFrame(() => {
|
|
11
|
+
// if (!eventQueue) return
|
|
12
|
+
const { world } = ctx;
|
|
13
|
+
// Set timestep to current delta, to allow for variable frame rates
|
|
14
|
+
// We cap the delta at 100, so that the physics simulation doesn't get wild
|
|
15
|
+
const now = performance.now();
|
|
16
|
+
const delta = Math.min(100, now - time);
|
|
17
|
+
world.timestep = delta / 1000;
|
|
18
|
+
world.step(eventQueue);
|
|
19
|
+
// Update meshes
|
|
20
|
+
ctx.rigidBodyObjects.forEach((mesh, handle) => {
|
|
21
|
+
const rigidBody = world.getRigidBody(handle);
|
|
22
|
+
if (!rigidBody)
|
|
23
|
+
return;
|
|
24
|
+
const dispatcher = ctx.rigidBodyEventDispatchers.get(handle);
|
|
25
|
+
if (!rigidBody || !rigidBody.isValid())
|
|
26
|
+
return;
|
|
27
|
+
if (dispatcher) {
|
|
28
|
+
if (rigidBody.isSleeping() && !mesh.userData.isSleeping) {
|
|
29
|
+
dispatcher('sleep');
|
|
30
|
+
}
|
|
31
|
+
if (!rigidBody.isSleeping() && mesh.userData.isSleeping) {
|
|
32
|
+
dispatcher('wake');
|
|
33
|
+
}
|
|
34
|
+
mesh.userData.isSleeping = rigidBody.isSleeping();
|
|
35
|
+
}
|
|
36
|
+
if (!rigidBody || rigidBody.isSleeping() || rigidBody.isFixed() || !mesh.parent) {
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
// Position
|
|
40
|
+
const { x, y, z } = rigidBody.translation();
|
|
41
|
+
tempObject.position.set(x, y, z);
|
|
42
|
+
// Rotation
|
|
43
|
+
const rotation = rigidBody.rotation();
|
|
44
|
+
tempQuaternion.set(rotation.x, rotation.y, rotation.z, rotation.w);
|
|
45
|
+
tempObject.rotation.setFromQuaternion(tempQuaternion);
|
|
46
|
+
// Scale
|
|
47
|
+
mesh.getWorldScale(tempVector3);
|
|
48
|
+
tempObject.scale.copy(tempVector3);
|
|
49
|
+
tempObject.updateMatrix();
|
|
50
|
+
tempObject.applyMatrix4(mesh.parent.matrixWorld.clone().invert());
|
|
51
|
+
tempObject.updateMatrix();
|
|
52
|
+
mesh.position.setFromMatrixPosition(tempObject.matrix);
|
|
53
|
+
mesh.rotation.setFromRotationMatrix(tempObject.matrix);
|
|
54
|
+
});
|
|
55
|
+
// Collision events
|
|
56
|
+
eventQueue.drainCollisionEvents((handle1, handle2, started) => {
|
|
57
|
+
const collider1 = world.getCollider(handle1);
|
|
58
|
+
const collider2 = world.getCollider(handle2);
|
|
59
|
+
// Sanity check
|
|
60
|
+
if (!collider1 || !collider2) {
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
const colliderDispatcher1 = ctx.colliderEventDispatchers.get(collider1.handle);
|
|
64
|
+
const colliderDispatcher2 = ctx.colliderEventDispatchers.get(collider2.handle);
|
|
65
|
+
const rigidBody1 = collider1.parent();
|
|
66
|
+
const rigidBody2 = collider2.parent();
|
|
67
|
+
const rigidBodyDispatcher1 = rigidBody1
|
|
68
|
+
? ctx.rigidBodyEventDispatchers.get(rigidBody1.handle)
|
|
69
|
+
: undefined;
|
|
70
|
+
const rigidBodyDispatcher2 = rigidBody2
|
|
71
|
+
? ctx.rigidBodyEventDispatchers.get(rigidBody2.handle)
|
|
72
|
+
: undefined;
|
|
73
|
+
if (started) {
|
|
74
|
+
// intersections are triggered by sensors
|
|
75
|
+
const isIntersection = world.intersectionPair(collider1, collider2);
|
|
76
|
+
if (isIntersection) {
|
|
77
|
+
// Collider Events
|
|
78
|
+
colliderDispatcher1?.('sensorenter', {
|
|
79
|
+
targetCollider: collider2,
|
|
80
|
+
targetRigidBody: rigidBody2
|
|
81
|
+
});
|
|
82
|
+
colliderDispatcher2?.('sensorenter', {
|
|
83
|
+
targetCollider: collider1,
|
|
84
|
+
targetRigidBody: rigidBody1
|
|
85
|
+
});
|
|
86
|
+
// RigidBody Events
|
|
87
|
+
rigidBodyDispatcher1?.('sensorenter', {
|
|
88
|
+
targetCollider: collider2,
|
|
89
|
+
targetRigidBody: rigidBody2
|
|
90
|
+
});
|
|
91
|
+
rigidBodyDispatcher2?.('sensorenter', {
|
|
92
|
+
targetCollider: collider1,
|
|
93
|
+
targetRigidBody: rigidBody1
|
|
94
|
+
});
|
|
95
|
+
// intersections with sensors don't trigger contact pairs, returning
|
|
96
|
+
return;
|
|
97
|
+
}
|
|
98
|
+
world.contactPair(collider1, collider2, (manifold, flipped) => {
|
|
99
|
+
// Collider events
|
|
100
|
+
colliderDispatcher1?.('collisionenter', {
|
|
101
|
+
flipped,
|
|
102
|
+
manifold,
|
|
103
|
+
targetCollider: collider2,
|
|
104
|
+
targetRigidBody: rigidBody2
|
|
105
|
+
});
|
|
106
|
+
colliderDispatcher2?.('collisionenter', {
|
|
107
|
+
flipped,
|
|
108
|
+
manifold,
|
|
109
|
+
targetCollider: collider1,
|
|
110
|
+
targetRigidBody: rigidBody1
|
|
111
|
+
});
|
|
112
|
+
// RigidBody Events
|
|
113
|
+
rigidBodyDispatcher1?.('collisionenter', {
|
|
114
|
+
flipped,
|
|
115
|
+
manifold,
|
|
116
|
+
targetCollider: collider2,
|
|
117
|
+
targetRigidBody: rigidBody2
|
|
118
|
+
});
|
|
119
|
+
rigidBodyDispatcher2?.('collisionenter', {
|
|
120
|
+
flipped,
|
|
121
|
+
manifold,
|
|
122
|
+
targetCollider: collider1,
|
|
123
|
+
targetRigidBody: rigidBody1
|
|
124
|
+
});
|
|
125
|
+
});
|
|
126
|
+
}
|
|
127
|
+
else {
|
|
128
|
+
// COLLISION / INTERSECTION ENDED
|
|
129
|
+
// intersections are triggered by sensors, but apparently not on collision exit
|
|
130
|
+
const isIntersection = world.intersectionPair(collider1, collider2) ||
|
|
131
|
+
collider1.isSensor() ||
|
|
132
|
+
collider2.isSensor();
|
|
133
|
+
if (isIntersection) {
|
|
134
|
+
colliderDispatcher1?.('sensorexit', {
|
|
135
|
+
targetCollider: collider2,
|
|
136
|
+
targetRigidBody: rigidBody2
|
|
137
|
+
});
|
|
138
|
+
colliderDispatcher2?.('sensorexit', {
|
|
139
|
+
targetCollider: collider1,
|
|
140
|
+
targetRigidBody: rigidBody1
|
|
141
|
+
});
|
|
142
|
+
// RigidBody Events
|
|
143
|
+
rigidBodyDispatcher1?.('sensorexit', {
|
|
144
|
+
targetCollider: collider2,
|
|
145
|
+
targetRigidBody: rigidBody2
|
|
146
|
+
});
|
|
147
|
+
rigidBodyDispatcher2?.('sensorexit', {
|
|
148
|
+
targetCollider: collider1,
|
|
149
|
+
targetRigidBody: rigidBody1
|
|
150
|
+
});
|
|
151
|
+
// intersections with sensors don't trigger contact pairs, returning
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
// Collider events
|
|
155
|
+
colliderDispatcher1?.('collisionexit', {
|
|
156
|
+
targetCollider: collider2,
|
|
157
|
+
targetRigidBody: rigidBody2
|
|
158
|
+
});
|
|
159
|
+
colliderDispatcher2?.('collisionexit', {
|
|
160
|
+
targetCollider: collider1,
|
|
161
|
+
targetRigidBody: rigidBody1
|
|
162
|
+
});
|
|
163
|
+
// RigidBody Events
|
|
164
|
+
rigidBodyDispatcher1?.('collisionexit', {
|
|
165
|
+
targetCollider: collider2,
|
|
166
|
+
targetRigidBody: rigidBody2
|
|
167
|
+
});
|
|
168
|
+
rigidBodyDispatcher2?.('collisionexit', {
|
|
169
|
+
targetCollider: collider1,
|
|
170
|
+
targetRigidBody: rigidBody1
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
});
|
|
174
|
+
time = now;
|
|
175
|
+
});
|
|
176
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export { useRapier } from './hooks/useRapier';
|
|
2
|
+
export { useCollisionGroups } from './hooks/useCollisionGroups';
|
|
3
|
+
export { useRigidBody } from './hooks/useRigidBody';
|
|
4
|
+
export { default as World } from './components/World/World.svelte';
|
|
5
|
+
export { default as RigidBody } from './components/RigidBody/RigidBody.svelte';
|
|
6
|
+
export { default as Debug } from './components/Debug/Debug.svelte';
|
|
7
|
+
export { default as Collider } from './components/Colliders/Collider.svelte';
|
|
8
|
+
export { default as AutoColliders } from './components/Colliders/AutoColliders.svelte';
|
|
9
|
+
export { default as CollisionGroups } from './components/CollisionGroups/CollisionGroups.svelte';
|
|
10
|
+
export { default as BasicPlayerController } from './recipes/BasicPlayerController.svelte';
|
|
11
|
+
export type { AutoCollidersProperties, ColliderProperties, Boolean3Array, RigidBodyProperties, WorldProperties } from './types/components';
|
|
12
|
+
export type { CollisionGroupsBitMask, AutoCollidersShapes, ColliderEventDispatcher, ColliderShapes, RapierContext, RigidBodyEventDispatcher } from './types/types';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
// hooks
|
|
2
|
+
export { useRapier } from './hooks/useRapier';
|
|
3
|
+
export { useCollisionGroups } from './hooks/useCollisionGroups';
|
|
4
|
+
export { useRigidBody } from './hooks/useRigidBody';
|
|
5
|
+
// components
|
|
6
|
+
export { default as World } from './components/World/World.svelte';
|
|
7
|
+
export { default as RigidBody } from './components/RigidBody/RigidBody.svelte';
|
|
8
|
+
export { default as Debug } from './components/Debug/Debug.svelte';
|
|
9
|
+
export { default as Collider } from './components/Colliders/Collider.svelte';
|
|
10
|
+
export { default as AutoColliders } from './components/Colliders/AutoColliders.svelte';
|
|
11
|
+
export { default as CollisionGroups } from './components/CollisionGroups/CollisionGroups.svelte';
|
|
12
|
+
// recipes
|
|
13
|
+
export { default as BasicPlayerController } from './recipes/BasicPlayerController.svelte';
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { Object3D, Vector3 } from 'three';
|
|
2
|
+
import { positionToVector3 } from './positionToVector3';
|
|
3
|
+
import { rotationToEuler } from './rotationToEuler';
|
|
4
|
+
import { scaleToVector3 } from './scaleToVector3';
|
|
5
|
+
export const applyTransforms = (object, position, rotation, scale, lookAt) => {
|
|
6
|
+
object.position.copy(positionToVector3(position));
|
|
7
|
+
if (lookAt instanceof Object3D) {
|
|
8
|
+
object.lookAt(lookAt.getWorldPosition(new Vector3()));
|
|
9
|
+
}
|
|
10
|
+
else if (lookAt) {
|
|
11
|
+
object.lookAt(positionToVector3(lookAt));
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
object.rotation.copy(rotationToEuler(rotation));
|
|
15
|
+
}
|
|
16
|
+
object.scale.copy(scaleToVector3(scale));
|
|
17
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Collider, World, RigidBody } from '@dimforge/rapier3d-compat';
|
|
2
|
+
import { type Object3D } from 'three';
|
|
3
|
+
import type { AutoCollidersShapes } from '../types/types';
|
|
4
|
+
/**
|
|
5
|
+
*
|
|
6
|
+
* Creates collider descriptions including default translations
|
|
7
|
+
*
|
|
8
|
+
* @param object
|
|
9
|
+
* @param world
|
|
10
|
+
* @param friction
|
|
11
|
+
* @param restitution
|
|
12
|
+
* @param collidersType
|
|
13
|
+
* @param rigidBody
|
|
14
|
+
* @returns
|
|
15
|
+
*/
|
|
16
|
+
export declare const createCollidersFromChildren: (object: Object3D, collidersType: AutoCollidersShapes, world: World, rigidBody?: RigidBody) => Collider[];
|