@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,94 @@
|
|
|
1
|
+
import { ActiveEvents, Collider, ColliderDesc, World, RigidBody } from '@dimforge/rapier3d-compat';
|
|
2
|
+
import { Mesh, Quaternion, Vector3 } from 'three';
|
|
3
|
+
/**
|
|
4
|
+
*
|
|
5
|
+
* Creates collider descriptions including default translations
|
|
6
|
+
*
|
|
7
|
+
* @param object
|
|
8
|
+
* @param world
|
|
9
|
+
* @param friction
|
|
10
|
+
* @param restitution
|
|
11
|
+
* @param collidersType
|
|
12
|
+
* @param rigidBody
|
|
13
|
+
* @returns
|
|
14
|
+
*/
|
|
15
|
+
export const createCollidersFromChildren = (object, collidersType, world, rigidBody) => {
|
|
16
|
+
const colliders = [];
|
|
17
|
+
let description;
|
|
18
|
+
const offset = new Vector3();
|
|
19
|
+
/**
|
|
20
|
+
* Trying to find the parent RigidBody.
|
|
21
|
+
* If we find something, good. If not,
|
|
22
|
+
* the Colliders are created on the world positions
|
|
23
|
+
* of the meshes they resemble.
|
|
24
|
+
*/
|
|
25
|
+
const rigidBodyWorldPos = new Vector3();
|
|
26
|
+
const rigidBodyWorldQuatInversed = new Quaternion();
|
|
27
|
+
object.traverseAncestors((child) => {
|
|
28
|
+
if (child.userData.isRigidBody) {
|
|
29
|
+
child.getWorldPosition(rigidBodyWorldPos);
|
|
30
|
+
child.getWorldQuaternion(rigidBodyWorldQuatInversed);
|
|
31
|
+
rigidBodyWorldQuatInversed.invert();
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
object.traverse((child) => {
|
|
35
|
+
if ('isMesh' in child) {
|
|
36
|
+
const { geometry } = child;
|
|
37
|
+
const worldPos = child.getWorldPosition(new Vector3());
|
|
38
|
+
const { x, y, z } = worldPos.sub(rigidBodyWorldPos);
|
|
39
|
+
const worldQuat = child.getWorldQuaternion(new Quaternion());
|
|
40
|
+
const { x: rx, y: ry, z: rz, w: rw } = worldQuat.clone().premultiply(rigidBodyWorldQuatInversed);
|
|
41
|
+
const scale = child.getWorldScale(new Vector3());
|
|
42
|
+
switch (collidersType) {
|
|
43
|
+
case 'cuboid':
|
|
44
|
+
{
|
|
45
|
+
geometry.computeBoundingBox();
|
|
46
|
+
const { boundingBox } = geometry;
|
|
47
|
+
const size = boundingBox.getSize(new Vector3());
|
|
48
|
+
boundingBox.getCenter(offset);
|
|
49
|
+
description = ColliderDesc.cuboid((size.x / 2) * scale.x, (size.y / 2) * scale.y, (size.z / 2) * scale.z);
|
|
50
|
+
}
|
|
51
|
+
break;
|
|
52
|
+
case 'ball':
|
|
53
|
+
{
|
|
54
|
+
geometry.computeBoundingSphere();
|
|
55
|
+
const { boundingSphere } = geometry;
|
|
56
|
+
const radius = boundingSphere.radius * scale.x;
|
|
57
|
+
offset.copy(boundingSphere.center);
|
|
58
|
+
description = ColliderDesc.ball(radius);
|
|
59
|
+
}
|
|
60
|
+
break;
|
|
61
|
+
case 'trimesh':
|
|
62
|
+
{
|
|
63
|
+
const g = geometry.clone().scale(scale.x, scale.y, scale.z);
|
|
64
|
+
description = ColliderDesc.trimesh(g.attributes.position.array, g.index?.array);
|
|
65
|
+
}
|
|
66
|
+
break;
|
|
67
|
+
case 'capsule':
|
|
68
|
+
{
|
|
69
|
+
geometry.computeBoundingBox();
|
|
70
|
+
const { boundingBox } = geometry;
|
|
71
|
+
const size = boundingBox.getSize(new Vector3());
|
|
72
|
+
boundingBox.getCenter(offset);
|
|
73
|
+
const radius = Math.max((size.x / 2) * scale.x, (size.z / 2) * scale.z);
|
|
74
|
+
description = ColliderDesc.capsule((size.y / 2) * scale.y - radius, radius);
|
|
75
|
+
}
|
|
76
|
+
break;
|
|
77
|
+
case 'convexHull':
|
|
78
|
+
// eslint-disable-next-line no-case-declarations
|
|
79
|
+
const g = geometry.clone().scale(scale.x, scale.y, scale.z);
|
|
80
|
+
{
|
|
81
|
+
description = ColliderDesc.convexHull(g.attributes.position.array);
|
|
82
|
+
}
|
|
83
|
+
break;
|
|
84
|
+
}
|
|
85
|
+
description
|
|
86
|
+
.setTranslation(x + offset.x, y + offset.y, z + offset.z)
|
|
87
|
+
.setRotation({ x: rx, y: ry, z: rz, w: rw })
|
|
88
|
+
.setActiveEvents(ActiveEvents.COLLISION_EVENTS);
|
|
89
|
+
const collider = world.createCollider(description, rigidBody);
|
|
90
|
+
colliders.push(collider);
|
|
91
|
+
}
|
|
92
|
+
});
|
|
93
|
+
return colliders;
|
|
94
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Collider, RigidBody } from '@dimforge/rapier3d-compat';
|
|
2
|
+
import RAPIER from '@dimforge/rapier3d-compat';
|
|
3
|
+
import type { Object3D } from 'three';
|
|
4
|
+
import type { ColliderEventDispatcher, ColliderEventDispatchers, RigidBodyEventDispatcher, RigidBodyEventDispatchers } from '../types/types';
|
|
5
|
+
export declare const createRapierContext: (gravity: RAPIER.Vector, rawIntegrationParameters?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawIntegrationParameters | undefined, rawIslands?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawIslandManager | undefined, rawBroadPhase?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawBroadPhase | undefined, rawNarrowPhase?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawNarrowPhase | undefined, rawBodies?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawRigidBodySet | undefined, rawColliders?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawColliderSet | undefined, rawImpulseJoints?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawImpulseJointSet | undefined, rawMultibodyJoints?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawMultibodyJointSet | undefined, rawCCDSolver?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawCCDSolver | undefined, rawQueryPipeline?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawQueryPipeline | undefined, rawPhysicsPipeline?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawPhysicsPipeline | undefined, rawSerializationPipeline?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawSerializationPipeline | undefined, rawDebugRenderPipeline?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawDebugRenderPipeline | undefined) => {
|
|
6
|
+
rapier: typeof RAPIER;
|
|
7
|
+
world: RAPIER.World;
|
|
8
|
+
colliderObjects: Map<number, Object3D<import("three").Event>>;
|
|
9
|
+
rigidBodyObjects: Map<number, Object3D<import("three").Event>>;
|
|
10
|
+
rigidBodyEventDispatchers: RigidBodyEventDispatchers;
|
|
11
|
+
colliderEventDispatchers: ColliderEventDispatchers;
|
|
12
|
+
addColliderToContext: (collider: Collider, object: Object3D, eventDispatcher: ColliderEventDispatcher) => void;
|
|
13
|
+
removeColliderFromContext: (collider: Collider) => void;
|
|
14
|
+
addRigidBodyToContext: (rigidBody: RigidBody, object: Object3D, eventDispatcher: RigidBodyEventDispatcher) => void;
|
|
15
|
+
removeRigidBodyFromContext: (rigidBody: RigidBody) => void;
|
|
16
|
+
};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import RAPIER from '@dimforge/rapier3d-compat';
|
|
2
|
+
export const createRapierContext = (...args) => {
|
|
3
|
+
const world = new RAPIER.World(...args);
|
|
4
|
+
const colliderObjects = new Map();
|
|
5
|
+
const rigidBodyObjects = new Map();
|
|
6
|
+
const rigidBodyEventDispatchers = new Map();
|
|
7
|
+
const colliderEventDispatchers = new Map();
|
|
8
|
+
/**
|
|
9
|
+
* Adds a collider to the context
|
|
10
|
+
* @param collider
|
|
11
|
+
* @param object
|
|
12
|
+
* @param eventDispatcher
|
|
13
|
+
*/
|
|
14
|
+
const addColliderToContext = (collider, object, eventDispatcher) => {
|
|
15
|
+
colliderObjects.set(collider.handle, object);
|
|
16
|
+
colliderEventDispatchers.set(collider.handle, eventDispatcher);
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Removes the collider from the context
|
|
20
|
+
* @param collider
|
|
21
|
+
*/
|
|
22
|
+
const removeColliderFromContext = (collider) => {
|
|
23
|
+
colliderObjects.delete(collider.handle);
|
|
24
|
+
colliderEventDispatchers.delete(collider.handle);
|
|
25
|
+
};
|
|
26
|
+
/**
|
|
27
|
+
* Adds a RigidBody to the context
|
|
28
|
+
* @param rigidBody
|
|
29
|
+
* @param object
|
|
30
|
+
* @param eventDispatcher
|
|
31
|
+
*/
|
|
32
|
+
const addRigidBodyToContext = (rigidBody, object, eventDispatcher) => {
|
|
33
|
+
rigidBodyObjects.set(rigidBody.handle, object);
|
|
34
|
+
rigidBodyEventDispatchers.set(rigidBody.handle, eventDispatcher);
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* Removes the RigidBody from the context
|
|
38
|
+
* @param rigidBody
|
|
39
|
+
*/
|
|
40
|
+
const removeRigidBodyFromContext = (rigidBody) => {
|
|
41
|
+
rigidBodyObjects.delete(rigidBody.handle);
|
|
42
|
+
rigidBodyEventDispatchers.delete(rigidBody.handle);
|
|
43
|
+
};
|
|
44
|
+
return {
|
|
45
|
+
rapier: RAPIER,
|
|
46
|
+
world,
|
|
47
|
+
colliderObjects,
|
|
48
|
+
rigidBodyObjects,
|
|
49
|
+
rigidBodyEventDispatchers,
|
|
50
|
+
colliderEventDispatchers,
|
|
51
|
+
addColliderToContext,
|
|
52
|
+
removeColliderFromContext,
|
|
53
|
+
addRigidBodyToContext,
|
|
54
|
+
removeRigidBodyFromContext
|
|
55
|
+
};
|
|
56
|
+
};
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { Euler, Object3D, Quaternion, Vector3 } from 'three';
|
|
2
|
+
/**
|
|
3
|
+
* Get the world position of an object.
|
|
4
|
+
* If no target is provided, a globally used
|
|
5
|
+
* temporary Vector3 is used.
|
|
6
|
+
*
|
|
7
|
+
* @param object
|
|
8
|
+
* @param target
|
|
9
|
+
* @returns
|
|
10
|
+
*/
|
|
11
|
+
export declare const getWorldPosition: (object: Object3D, target?: Vector3) => Vector3;
|
|
12
|
+
/**
|
|
13
|
+
* Get the world quaternion of an object.
|
|
14
|
+
* If no target is provided, a globally used
|
|
15
|
+
* temporary Quaternion is used.
|
|
16
|
+
*
|
|
17
|
+
* @param object
|
|
18
|
+
* @param target
|
|
19
|
+
* @returns
|
|
20
|
+
*/
|
|
21
|
+
export declare const getWorldQuaternion: (object: Object3D, target?: Quaternion) => Quaternion;
|
|
22
|
+
/**
|
|
23
|
+
* Get the world rotation of an object.
|
|
24
|
+
* If no target is provided, a globally used
|
|
25
|
+
* temporary Euler is used.
|
|
26
|
+
*
|
|
27
|
+
* @param object
|
|
28
|
+
* @param target
|
|
29
|
+
* @returns
|
|
30
|
+
*/
|
|
31
|
+
export declare const getWorldRotation: (object: Object3D, target?: Euler) => Euler;
|
|
32
|
+
/**
|
|
33
|
+
* Get the world scale of an object.
|
|
34
|
+
* If no target is provided, a globally used
|
|
35
|
+
* temporary Vector3 is used.
|
|
36
|
+
*
|
|
37
|
+
* @param object
|
|
38
|
+
* @param target
|
|
39
|
+
* @returns
|
|
40
|
+
*/
|
|
41
|
+
export declare const getWorldScale: (object: Object3D, target?: Vector3) => Vector3;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { Euler, Object3D, Quaternion, Vector3 } from 'three';
|
|
2
|
+
const tempVector3 = new Vector3();
|
|
3
|
+
const tempQuaternion = new Quaternion();
|
|
4
|
+
const tempEuler = new Euler();
|
|
5
|
+
/**
|
|
6
|
+
* Get the world position of an object.
|
|
7
|
+
* If no target is provided, a globally used
|
|
8
|
+
* temporary Vector3 is used.
|
|
9
|
+
*
|
|
10
|
+
* @param object
|
|
11
|
+
* @param target
|
|
12
|
+
* @returns
|
|
13
|
+
*/
|
|
14
|
+
export const getWorldPosition = (object, target) => {
|
|
15
|
+
return object.getWorldPosition(target ?? tempVector3);
|
|
16
|
+
};
|
|
17
|
+
/**
|
|
18
|
+
* Get the world quaternion of an object.
|
|
19
|
+
* If no target is provided, a globally used
|
|
20
|
+
* temporary Quaternion is used.
|
|
21
|
+
*
|
|
22
|
+
* @param object
|
|
23
|
+
* @param target
|
|
24
|
+
* @returns
|
|
25
|
+
*/
|
|
26
|
+
export const getWorldQuaternion = (object, target) => {
|
|
27
|
+
return object.getWorldQuaternion(target ?? tempQuaternion);
|
|
28
|
+
};
|
|
29
|
+
/**
|
|
30
|
+
* Get the world rotation of an object.
|
|
31
|
+
* If no target is provided, a globally used
|
|
32
|
+
* temporary Euler is used.
|
|
33
|
+
*
|
|
34
|
+
* @param object
|
|
35
|
+
* @param target
|
|
36
|
+
* @returns
|
|
37
|
+
*/
|
|
38
|
+
export const getWorldRotation = (object, target) => {
|
|
39
|
+
object.getWorldQuaternion(tempQuaternion);
|
|
40
|
+
return target
|
|
41
|
+
? target.setFromQuaternion(tempQuaternion)
|
|
42
|
+
: tempEuler.setFromQuaternion(tempQuaternion);
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* Get the world scale of an object.
|
|
46
|
+
* If no target is provided, a globally used
|
|
47
|
+
* temporary Vector3 is used.
|
|
48
|
+
*
|
|
49
|
+
* @param object
|
|
50
|
+
* @param target
|
|
51
|
+
* @returns
|
|
52
|
+
*/
|
|
53
|
+
export const getWorldScale = (object, target) => {
|
|
54
|
+
return object.getWorldScale(target ?? tempVector3);
|
|
55
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { RigidBodyType } from '@dimforge/rapier3d-compat';
|
|
2
|
+
const rigidBodyTypeMap = {
|
|
3
|
+
dynamic: RigidBodyType.Dynamic,
|
|
4
|
+
fixed: RigidBodyType.Fixed,
|
|
5
|
+
kinematicPosition: RigidBodyType.KinematicPositionBased,
|
|
6
|
+
kinematicVelocity: RigidBodyType.KinematicVelocityBased
|
|
7
|
+
};
|
|
8
|
+
export const parseRigidBodyType = (type) => {
|
|
9
|
+
return rigidBodyTypeMap[type];
|
|
10
|
+
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Euler } from 'three';
|
|
2
|
+
export const rotationToEuler = (rotation, euler) => {
|
|
3
|
+
if (euler) {
|
|
4
|
+
euler.set(rotation?.x ?? 0, rotation?.y ?? 0, rotation?.z ?? 0);
|
|
5
|
+
return euler;
|
|
6
|
+
}
|
|
7
|
+
return new Euler(rotation?.x ?? 0, rotation?.y ?? 0, rotation?.z ?? 0);
|
|
8
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { Quaternion } from 'three';
|
|
2
|
+
import { rotationToEuler } from './rotationToEuler';
|
|
3
|
+
export const rotationToQuaternion = (rotation, quaternion) => {
|
|
4
|
+
const euler = rotationToEuler(rotation);
|
|
5
|
+
if (quaternion) {
|
|
6
|
+
quaternion.setFromEuler(euler);
|
|
7
|
+
return quaternion;
|
|
8
|
+
}
|
|
9
|
+
return new Quaternion().setFromEuler(euler);
|
|
10
|
+
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ColliderDesc } from '@dimforge/rapier3d-compat';
|
|
2
|
+
import type { Vector3 } from 'three';
|
|
3
|
+
import type { ColliderShapes } from '../types/types';
|
|
4
|
+
export declare const scaleVertices: (vertices: ArrayLike<number>, scale: Vector3) => number[];
|
|
5
|
+
export declare const scaleColliderArgs: <Shape extends ColliderShapes>(shape: Shape, args: Parameters<(typeof ColliderDesc)[Shape]>, scale: Vector3) => Parameters<(typeof ColliderDesc)[Shape]>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export const scaleVertices = (vertices, scale) => {
|
|
2
|
+
const scaledVerts = Array.from(vertices);
|
|
3
|
+
for (let i = 0; i < vertices.length / 3; i++) {
|
|
4
|
+
scaledVerts[i * 3] *= scale.x;
|
|
5
|
+
scaledVerts[i * 3 + 1] *= scale.y;
|
|
6
|
+
scaledVerts[i * 3 + 2] *= scale.z;
|
|
7
|
+
}
|
|
8
|
+
return scaledVerts;
|
|
9
|
+
};
|
|
10
|
+
export const scaleColliderArgs = (shape, args, scale) => {
|
|
11
|
+
// Heightfield only scales the last arg
|
|
12
|
+
const newArgs = args.slice();
|
|
13
|
+
if (shape === 'heightfield') {
|
|
14
|
+
;
|
|
15
|
+
newArgs[3] *= scale.x;
|
|
16
|
+
return newArgs;
|
|
17
|
+
}
|
|
18
|
+
// Trimesh and convex scale the vertices
|
|
19
|
+
if (shape === 'trimesh' || shape === 'convexHull') {
|
|
20
|
+
newArgs[0] = new Float32Array(scaleVertices(newArgs[0], scale));
|
|
21
|
+
return newArgs;
|
|
22
|
+
}
|
|
23
|
+
const scaleArray = [scale.x, scale.y, scale.z];
|
|
24
|
+
return newArgs.map((arg, index) => scaleArray[index] * arg);
|
|
25
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { Vector3 } from 'three';
|
|
2
|
+
export const scaleToVector3 = (scale, v3) => {
|
|
3
|
+
if (v3) {
|
|
4
|
+
if (typeof scale === 'number') {
|
|
5
|
+
v3.set(scale, scale, scale);
|
|
6
|
+
}
|
|
7
|
+
else {
|
|
8
|
+
v3.set(scale?.x ?? 1, scale?.y ?? 1, scale?.z ?? 1);
|
|
9
|
+
}
|
|
10
|
+
return v3;
|
|
11
|
+
}
|
|
12
|
+
if (typeof scale === 'number') {
|
|
13
|
+
return new Vector3(scale, scale, scale);
|
|
14
|
+
}
|
|
15
|
+
return new Vector3(scale?.x ?? 1, scale?.y ?? 1, scale?.z ?? 1);
|
|
16
|
+
};
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
<script>import { Group, useFrame, useThrelte } from '@threlte/core';
|
|
2
|
+
import { createEventDispatcher } from 'svelte';
|
|
3
|
+
import { Vector2, Vector3 } from 'three';
|
|
4
|
+
import Collider from '../components/Colliders/Collider.svelte';
|
|
5
|
+
import CollisionGroups from '../components/CollisionGroups/CollisionGroups.svelte';
|
|
6
|
+
import RigidBody from '../components/RigidBody/RigidBody.svelte';
|
|
7
|
+
export let position = undefined;
|
|
8
|
+
export let height = 1.7;
|
|
9
|
+
export let radius = 0.3;
|
|
10
|
+
export let speed = 1;
|
|
11
|
+
export let jumpStrength = 3;
|
|
12
|
+
export let playerCollisionGroups = [0];
|
|
13
|
+
export let groundCollisionGroups = [15];
|
|
14
|
+
let rigidBody;
|
|
15
|
+
const { renderer } = useThrelte();
|
|
16
|
+
if (!renderer)
|
|
17
|
+
throw new Error();
|
|
18
|
+
const keys = {
|
|
19
|
+
up: false,
|
|
20
|
+
down: false,
|
|
21
|
+
left: false,
|
|
22
|
+
right: false
|
|
23
|
+
};
|
|
24
|
+
const t = new Vector3();
|
|
25
|
+
const t2 = new Vector2();
|
|
26
|
+
const dispatch = createEventDispatcher();
|
|
27
|
+
let grounded = false;
|
|
28
|
+
let groundsSensored = 0;
|
|
29
|
+
$: {
|
|
30
|
+
if (groundsSensored === 0)
|
|
31
|
+
grounded = false;
|
|
32
|
+
else
|
|
33
|
+
grounded = true;
|
|
34
|
+
}
|
|
35
|
+
$: grounded ? dispatch('groundenter') : dispatch('groundexit');
|
|
36
|
+
useFrame(() => {
|
|
37
|
+
if (!rigidBody)
|
|
38
|
+
return;
|
|
39
|
+
t.fromArray([0, 0, 0]);
|
|
40
|
+
if (keys.down)
|
|
41
|
+
t.x += 1;
|
|
42
|
+
if (keys.up)
|
|
43
|
+
t.x -= 1;
|
|
44
|
+
if (keys.left)
|
|
45
|
+
t.z += 1;
|
|
46
|
+
if (keys.right)
|
|
47
|
+
t.z -= 1;
|
|
48
|
+
const l = t.length();
|
|
49
|
+
const xzLength = t2.set(t.x, t.z).length();
|
|
50
|
+
if (l > 0)
|
|
51
|
+
t.divideScalar(l).multiplyScalar(speed);
|
|
52
|
+
if (xzLength > 0) {
|
|
53
|
+
rigidBody.resetForces(true);
|
|
54
|
+
rigidBody.resetTorques(true);
|
|
55
|
+
}
|
|
56
|
+
const linVel = rigidBody.linvel();
|
|
57
|
+
t.y = linVel.y;
|
|
58
|
+
rigidBody.setLinvel(t, true);
|
|
59
|
+
});
|
|
60
|
+
const onKeyDown = (e) => {
|
|
61
|
+
switch (e.key) {
|
|
62
|
+
case 'ArrowDown':
|
|
63
|
+
keys.down = true;
|
|
64
|
+
break;
|
|
65
|
+
case 'ArrowUp':
|
|
66
|
+
keys.up = true;
|
|
67
|
+
break;
|
|
68
|
+
case 'ArrowLeft':
|
|
69
|
+
keys.left = true;
|
|
70
|
+
break;
|
|
71
|
+
case 'ArrowRight':
|
|
72
|
+
keys.right = true;
|
|
73
|
+
break;
|
|
74
|
+
case ' ':
|
|
75
|
+
if (!rigidBody || !grounded)
|
|
76
|
+
break;
|
|
77
|
+
rigidBody.applyImpulse({ x: 0, y: jumpStrength, z: 0 }, true);
|
|
78
|
+
default:
|
|
79
|
+
break;
|
|
80
|
+
}
|
|
81
|
+
};
|
|
82
|
+
const onKeyUp = (e) => {
|
|
83
|
+
switch (e.key) {
|
|
84
|
+
case 'ArrowDown':
|
|
85
|
+
keys.down = false;
|
|
86
|
+
break;
|
|
87
|
+
case 'ArrowUp':
|
|
88
|
+
keys.up = false;
|
|
89
|
+
break;
|
|
90
|
+
case 'ArrowLeft':
|
|
91
|
+
keys.left = false;
|
|
92
|
+
break;
|
|
93
|
+
case 'ArrowRight':
|
|
94
|
+
keys.right = false;
|
|
95
|
+
break;
|
|
96
|
+
default:
|
|
97
|
+
break;
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
</script>
|
|
101
|
+
|
|
102
|
+
<svelte:window on:keydown|preventDefault={onKeyDown} on:keyup|preventDefault={onKeyUp} />
|
|
103
|
+
|
|
104
|
+
<RigidBody
|
|
105
|
+
dominance={127}
|
|
106
|
+
enabledRotations={[false, false, false]}
|
|
107
|
+
bind:rigidBody
|
|
108
|
+
{position}
|
|
109
|
+
type={'dynamic'}
|
|
110
|
+
>
|
|
111
|
+
<CollisionGroups groups={playerCollisionGroups}>
|
|
112
|
+
<Collider shape={'capsule'} args={[height / 2 - radius, radius]} />
|
|
113
|
+
</CollisionGroups>
|
|
114
|
+
|
|
115
|
+
<CollisionGroups groups={groundCollisionGroups}>
|
|
116
|
+
<Collider
|
|
117
|
+
sensor
|
|
118
|
+
on:sensorenter={() => (groundsSensored += 1)}
|
|
119
|
+
on:sensorexit={() => (groundsSensored -= 1)}
|
|
120
|
+
shape={'ball'}
|
|
121
|
+
args={[radius * 1.2]}
|
|
122
|
+
position={{ y: -height / 2 + radius }}
|
|
123
|
+
/>
|
|
124
|
+
</CollisionGroups>
|
|
125
|
+
|
|
126
|
+
<Group position={{ y: -height / 2 }}>
|
|
127
|
+
<slot />
|
|
128
|
+
</Group>
|
|
129
|
+
</RigidBody>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { SvelteComponentTyped } from "svelte";
|
|
2
|
+
import { type Position } from '@threlte/core';
|
|
3
|
+
import type { CollisionGroupsBitMask } from '../types/types';
|
|
4
|
+
declare const __propDef: {
|
|
5
|
+
props: {
|
|
6
|
+
position?: Position | undefined;
|
|
7
|
+
height?: number | undefined;
|
|
8
|
+
radius?: number | undefined;
|
|
9
|
+
speed?: number | undefined;
|
|
10
|
+
jumpStrength?: number | undefined;
|
|
11
|
+
playerCollisionGroups?: CollisionGroupsBitMask | undefined;
|
|
12
|
+
groundCollisionGroups?: CollisionGroupsBitMask | undefined;
|
|
13
|
+
};
|
|
14
|
+
events: {
|
|
15
|
+
groundenter: CustomEvent<void>;
|
|
16
|
+
groundexit: CustomEvent<void>;
|
|
17
|
+
} & {
|
|
18
|
+
[evt: string]: CustomEvent<any>;
|
|
19
|
+
};
|
|
20
|
+
slots: {
|
|
21
|
+
default: {};
|
|
22
|
+
};
|
|
23
|
+
};
|
|
24
|
+
export declare type BasicPlayerControllerProps = typeof __propDef.props;
|
|
25
|
+
export declare type BasicPlayerControllerEvents = typeof __propDef.events;
|
|
26
|
+
export declare type BasicPlayerControllerSlots = typeof __propDef.slots;
|
|
27
|
+
export default class BasicPlayerController extends SvelteComponentTyped<BasicPlayerControllerProps, BasicPlayerControllerEvents, BasicPlayerControllerSlots> {
|
|
28
|
+
}
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import type { CoefficientCombineRule, ColliderDesc } from '@dimforge/rapier3d-compat';
|
|
2
|
+
import type { RawBroadPhase, RawCCDSolver, RawColliderSet, RawDebugRenderPipeline, RawImpulseJointSet, RawIntegrationParameters, RawIslandManager, RawMultibodyJointSet, RawNarrowPhase, RawPhysicsPipeline, RawQueryPipeline, RawRigidBodySet, RawSerializationPipeline } from '@dimforge/rapier3d-compat/raw';
|
|
3
|
+
import type { Position, Rotation, TransformableObjectProperties } from '@threlte/core';
|
|
4
|
+
import type { RigidBodyTypeString } from '../lib/parseRigidBodyType';
|
|
5
|
+
import type { AutoCollidersShapes, ColliderShapes, CollisionGroupsBitMask } from './types';
|
|
6
|
+
export declare type Boolean3Array = [x: boolean, y: boolean, z: boolean];
|
|
7
|
+
export declare type Vector3Array = [x: number, y: number, z: number];
|
|
8
|
+
export declare type RigidBodyProperties = Omit<TransformableObjectProperties, 'object'> & {
|
|
9
|
+
/**
|
|
10
|
+
* Specify the type of this rigid body
|
|
11
|
+
*/
|
|
12
|
+
type?: RigidBodyTypeString;
|
|
13
|
+
/** Whether or not this body can sleep.
|
|
14
|
+
* default: true
|
|
15
|
+
*/
|
|
16
|
+
canSleep?: boolean;
|
|
17
|
+
/** The linear velocity of this body.
|
|
18
|
+
* default: zero velocity
|
|
19
|
+
*/
|
|
20
|
+
linearVelocity?: Position;
|
|
21
|
+
/** The angular velocity of this body.
|
|
22
|
+
* Default: zero velocity.
|
|
23
|
+
*/
|
|
24
|
+
angularVelocity?: Rotation;
|
|
25
|
+
/**
|
|
26
|
+
* The scaling factor applied to the gravity affecting the rigid-body.
|
|
27
|
+
* Default: 1.0
|
|
28
|
+
*/
|
|
29
|
+
gravityScale?: number;
|
|
30
|
+
/**
|
|
31
|
+
* Whether or not Continous Collision Detection is enabled for this rigid-body.
|
|
32
|
+
* https://rapier.rs/docs/user_guides/javascript/rigid_bodies#continuous-collision-detection
|
|
33
|
+
* @default false
|
|
34
|
+
*/
|
|
35
|
+
ccd?: boolean;
|
|
36
|
+
/**
|
|
37
|
+
* Locks all rotations that would have resulted from forces on the created rigid-body.
|
|
38
|
+
*/
|
|
39
|
+
lockRotations?: boolean;
|
|
40
|
+
/**
|
|
41
|
+
* Locks all translations that would have resulted from forces on the created rigid-body.
|
|
42
|
+
*/
|
|
43
|
+
lockTranslations?: boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Allow rotation of this rigid-body only along specific axes.
|
|
46
|
+
*/
|
|
47
|
+
enabledRotations?: Boolean3Array;
|
|
48
|
+
/**
|
|
49
|
+
* Allow rotation of this rigid-body only along specific axes.
|
|
50
|
+
*/
|
|
51
|
+
enabledTranslations?: Boolean3Array;
|
|
52
|
+
/**
|
|
53
|
+
* Dominance is a non-realistic, but sometimes useful, feature.
|
|
54
|
+
* It can be used to make one rigid-body immune to forces
|
|
55
|
+
* originating from contacts with some other bodies.
|
|
56
|
+
*
|
|
57
|
+
* Number in the range -127 to 127, default is 0
|
|
58
|
+
*/
|
|
59
|
+
dominance?: number;
|
|
60
|
+
};
|
|
61
|
+
export declare type ColliderProperties<Shape extends ColliderShapes> = Omit<TransformableObjectProperties, 'object'> & {
|
|
62
|
+
shape: Shape;
|
|
63
|
+
/**
|
|
64
|
+
* Arguments to pass to the collider specific to shape
|
|
65
|
+
*/
|
|
66
|
+
args: Parameters<typeof ColliderDesc[Shape]>;
|
|
67
|
+
/**
|
|
68
|
+
* The mass of this rigid body.
|
|
69
|
+
* The mass and density is automatically calculated based on the shape of the collider.
|
|
70
|
+
* Generally, it's not recommended to adjust the mass properties as it could lead to
|
|
71
|
+
* unexpected behaviors.
|
|
72
|
+
* More info https://rapier.rs/docs/user_guides/javascript/colliders#mass-properties
|
|
73
|
+
*/
|
|
74
|
+
mass?: number;
|
|
75
|
+
/**
|
|
76
|
+
* The center of mass of this rigid body
|
|
77
|
+
*/
|
|
78
|
+
centerOfMass?: Position;
|
|
79
|
+
/**
|
|
80
|
+
* Principal angular inertia of this rigid body
|
|
81
|
+
*/
|
|
82
|
+
principalAngularInertia?: Position;
|
|
83
|
+
/**
|
|
84
|
+
* Restitution controls how elastic (aka. bouncy) a contact is. Le elasticity of a contact is controlled by the restitution coefficient
|
|
85
|
+
*/
|
|
86
|
+
restitution?: number;
|
|
87
|
+
/**
|
|
88
|
+
* What happens when two bodies meet. See https://rapier.rs/docs/user_guides/javascript/colliders#friction.
|
|
89
|
+
*/
|
|
90
|
+
restitutionCombineRule?: CoefficientCombineRule;
|
|
91
|
+
/**
|
|
92
|
+
* Friction is a force that opposes the relative tangential motion between two rigid-bodies with colliders in contact.
|
|
93
|
+
* A friction coefficient of 0 implies no friction at all (completely sliding contact) and a coefficient
|
|
94
|
+
* greater or equal to 1 implies a very strong friction. Values greater than 1 are allowed.
|
|
95
|
+
*/
|
|
96
|
+
friction?: number;
|
|
97
|
+
/**
|
|
98
|
+
* What happens when two bodies meet. See https://rapier.rs/docs/user_guides/javascript/colliders#friction.
|
|
99
|
+
*/
|
|
100
|
+
frictionCombineRule?: CoefficientCombineRule;
|
|
101
|
+
/**
|
|
102
|
+
* A sensor does not participate in physics simulation and is
|
|
103
|
+
* used as a trigger e.g. to check whether another RigidBody
|
|
104
|
+
* entered an area.
|
|
105
|
+
*/
|
|
106
|
+
sensor?: boolean;
|
|
107
|
+
};
|
|
108
|
+
export declare type AutoCollidersProperties = Omit<ColliderProperties<AutoCollidersShapes>, 'args'>;
|
|
109
|
+
export declare type InnerWorldProperties = {
|
|
110
|
+
gravity?: Position;
|
|
111
|
+
rawIntegrationParameters?: RawIntegrationParameters;
|
|
112
|
+
rawIslands?: RawIslandManager;
|
|
113
|
+
rawBroadPhase?: RawBroadPhase;
|
|
114
|
+
rawNarrowPhase?: RawNarrowPhase;
|
|
115
|
+
rawBodies?: RawRigidBodySet;
|
|
116
|
+
rawColliders?: RawColliderSet;
|
|
117
|
+
rawImpulseJoints?: RawImpulseJointSet;
|
|
118
|
+
rawMultibodyJoints?: RawMultibodyJointSet;
|
|
119
|
+
rawCCDSolver?: RawCCDSolver;
|
|
120
|
+
rawQueryPipeline?: RawQueryPipeline;
|
|
121
|
+
rawPhysicsPipeline?: RawPhysicsPipeline;
|
|
122
|
+
rawSerializationPipeline?: RawSerializationPipeline;
|
|
123
|
+
rawDebugRenderPipeline?: RawDebugRenderPipeline;
|
|
124
|
+
};
|
|
125
|
+
export declare type WorldProperties = InnerWorldProperties;
|
|
126
|
+
export declare type CollisionGroupsProperties = {
|
|
127
|
+
groups: CollisionGroupsBitMask;
|
|
128
|
+
} | {
|
|
129
|
+
filter: CollisionGroupsBitMask;
|
|
130
|
+
memberships: CollisionGroupsBitMask;
|
|
131
|
+
};
|