From 27e0abc303f8273754ec3c2a14f8c0d04417e082 Mon Sep 17 00:00:00 2001 From: Nathan Mande Date: Wed, 20 Nov 2024 01:57:47 +0200 Subject: [PATCH] feat(core): implement all the supported `Joint`s --- .vscode/settings.json | 5 +- playground/src/pages/basics/JointsDemo.vue | 5 +- src/components/Joint.vue | 89 ---------- src/components/index.ts | 2 +- src/components/joints/BaseJoint.vue | 185 +++++++++++++++++++++ src/components/joints/index.ts | 96 +++++++++++ src/types/joint.ts | 10 +- 7 files changed, 297 insertions(+), 95 deletions(-) delete mode 100644 src/components/Joint.vue create mode 100644 src/components/joints/BaseJoint.vue create mode 100644 src/components/joints/index.ts diff --git a/.vscode/settings.json b/.vscode/settings.json index 65aa9d3..ff4e00d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -54,5 +54,8 @@ "cSpell.words": [ "cientos", "tresjs" - ] + ], + "[typescript]": { + "editor.defaultFormatter": "dbaeumer.vscode-eslint" + } } diff --git a/playground/src/pages/basics/JointsDemo.vue b/playground/src/pages/basics/JointsDemo.vue index c6c7cd0..4ed40f6 100644 --- a/playground/src/pages/basics/JointsDemo.vue +++ b/playground/src/pages/basics/JointsDemo.vue @@ -3,7 +3,7 @@ import { OrbitControls } from '@tresjs/cientos' import { TresCanvas } from '@tresjs/core' // eslint-disable-next-line ts/ban-ts-comment // @ts-ignore -import { type ExposedRigidBody, Joint, Physics, RigidBody } from '@tresjs/rapier' +import { type ExposedRigidBody, Physics, RigidBody, SphericalJoint } from '@tresjs/rapier' import { ACESFilmicToneMapping, Quaternion, SRGBColorSpace } from 'three' import { shallowRef } from 'vue' import type { ShallowRef } from 'vue' @@ -52,10 +52,9 @@ setInterval(() => { - -import { type ImpulseJoint, type JointData, Quaternion, Vector3 } from '@dimforge/rapier3d-compat' -import { shallowRef, watch } from 'vue' - -import { useRapier } from '../composables' -import type { JointProps, QuaternionArray, VectorArray } from '../types' - -const { - type = 'fixed', - bodies = [], - params = [ - [0, 0, 0], - [0, 0, 0, 0], - [0, 0, 0], - [0, 0, 0, 0], - ], -} = defineProps() - -const { world, rapier } = useRapier() - -const joins = shallowRef() - -watch(() => bodies, (bodies) => { - if ( - !(bodies?.[0] instanceof rapier.RigidBody) - || !(bodies?.[1] instanceof rapier.RigidBody) - || !Array.isArray(params) - ) { - return - } - - let jointParams: JointData | undefined - - if (type === 'fixed') { - jointParams = rapier.JointData.fixed( - new Vector3(0, 8, 2), - new Quaternion(0, 0, 0, 0), - new Vector3(0, 8, -2), - new Quaternion(0, 0, 0, 0), - ) - } - - if ( - type === 'rope' - && params.length >= 3 - && typeof params[0] === 'number' - && (Array.isArray(params[1]) && params[1].length >= 3) - && (Array.isArray(params[2]) && params[2].length >= 4) - ) { - jointParams = rapier.JointData.rope( - params[0], - new Vector3(...params[1] as VectorArray), - new Quaternion(...params[2] as QuaternionArray), - ) - } - else if (type === 'rope') { - throw new Error(`Invalid "${type}" joint parameters`) - } - - if ( - type === 'spherical' - && params.length >= 2 - && (Array.isArray(params[0]) && params[0].length >= 3) - && (Array.isArray(params[1]) && params[1].length >= 3) - ) { - jointParams = rapier.JointData.spherical( - new Vector3(...params[0] as VectorArray), - new Vector3(...params[1] as VectorArray), - ) - } - else if (type === 'spherical') { - throw new Error(`Invalid "${type}" joint parameters`) - } - - if (!jointParams) { - throw new Error(`Unsupported joint type. If you think this is a bug or the "${type}" type should be implemented, please open an issue.`) - } - - joins.value = world.createImpulseJoint(jointParams, bodies[0], bodies[1], true) -}) - -defineExpose({ - joins, -}) - - - diff --git a/src/components/index.ts b/src/components/index.ts index 19e09fe..ac36a87 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -1,5 +1,5 @@ export * from './colliders' export { default as InstancedRigidBody } from './InstancedRigidBody.vue' -export { default as Joint } from './Joint.vue' +export * from './joints' export { default as Physics } from './Physics.vue' export { default as RigidBody } from './RigidBody.vue' diff --git a/src/components/joints/BaseJoint.vue b/src/components/joints/BaseJoint.vue new file mode 100644 index 0000000..9f4426a --- /dev/null +++ b/src/components/joints/BaseJoint.vue @@ -0,0 +1,185 @@ + + + diff --git a/src/components/joints/index.ts b/src/components/joints/index.ts new file mode 100644 index 0000000..a10a076 --- /dev/null +++ b/src/components/joints/index.ts @@ -0,0 +1,96 @@ +import type { JointAxesMask } from '@dimforge/rapier3d-compat' +import type { Component } from 'vue' +import NativeBaseJoint from './BaseJoint.vue' +import type { + JointProps, + JointType, + QuaternionArray, + VectorArray, +} from '../../types' + +const createJoint = >(type: JointType): Component => ({ + __name: `${type.charAt(0).toUpperCase() + type.slice(1)}Joint`, + extends: NativeBaseJoint, + props: { + ...NativeBaseJoint.props, + type: { + type: String, + default: type, + validator: (value: typeof type) => value === type, + }, + }, + setup: (_props, ctx) => NativeBaseJoint?.setup?.( + _props as unknown as Parameters< + Exclude<(typeof NativeBaseJoint)['setup'], undefined> + >['0'], + ctx, + ), +}) + +/** @description Joint set as `Fixed` */ +export const FixedJoint = createJoint & { + params: [ + anchor1: VectorArray, + frame1: QuaternionArray, + anchor2: VectorArray, + frame2: QuaternionArray, + ] +}>('fixed') + +/** @description Joint set as `Generic` */ +export const GenericJoint = createJoint & { + params: [ + anchor1: VectorArray, + anchor2: VectorArray, + axis: VectorArray, + axesMask: JointAxesMask, + ] +}>('generic') + +/** @description Joint set as ` Prismatic` */ +export const PrismaticJoint = createJoint & { + params: [ + anchor1: VectorArray, + anchor2: VectorArray, + axis: VectorArray, + ] +}>('prismatic') + +/** @description Joint set as `Revolute` */ +export const RevoluteJoint = createJoint & { + params: [ + anchor1: VectorArray, + anchor2: VectorArray, + axis: VectorArray, + ] +}>('revolute') + +/** @description Joint set as `Rope` */ +export const RopeJoint = createJoint & { + params: [ + length: number, + anchor1: VectorArray, + anchor2: VectorArray, + ] +}>('rope') + +/** @description Joint set as `Spherical` */ +export const SphericalJoint = createJoint & { + params: [ + anchor1: VectorArray, + anchor2: VectorArray, + ] +}>('spherical') + +/** @description Joint set as `Spring` */ +export const SpringJoint = createJoint & { + params: [ + rest_length: number, + stiffness: number, + damping: number, + anchor1: VectorArray, + anchor2: VectorArray, + ] +}>('spring') + +export const BaseJoint = NativeBaseJoint diff --git a/src/types/joint.ts b/src/types/joint.ts index e518fba..7446f0b 100644 --- a/src/types/joint.ts +++ b/src/types/joint.ts @@ -9,8 +9,16 @@ export interface JointProps { type: JointType /** @description Bodies to connect with the joint. */ - bodies?: RigidBody[] + bodies?: [RigidBody, RigidBody] /** @description {@link JointData} parameters. */ params?: (number | number[])[] + + /** + * @description + * If the joint should wake up the bodies when a lifecycle hook (mount, unmount, on update, ...) occurs. + * + * @default true + */ + wakeUpOnChanges?: boolean }