Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions playground/components.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export {}
/* prettier-ignore */
declare module 'vue' {
export interface GlobalComponents {
Ragdoll: typeof import('./src/components/Ragdoll.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
}
Expand Down
182 changes: 182 additions & 0 deletions playground/src/components/Ragdoll.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
<script lang="ts" setup>
// eslint-disable-next-line ts/ban-ts-comment
// @ts-ignore
import { CuboidCollider, type ExposedRigidBody, RigidBody, SphericalJoint } from '@tresjs/rapier'
import { onMounted, shallowRef, type ShallowRef } from 'vue'

const headRef: ShallowRef<ExposedRigidBody> = shallowRef(null)
const torsoRef: ShallowRef<ExposedRigidBody> = shallowRef(null)
const upperArmL: ShallowRef<ExposedRigidBody> = shallowRef(null)
const lowerArmL: ShallowRef<ExposedRigidBody> = shallowRef(null)

const upperArmR: ShallowRef<ExposedRigidBody> = shallowRef(null)
const lowerArmR: ShallowRef<ExposedRigidBody> = shallowRef(null)

const upperLegL: ShallowRef<ExposedRigidBody> = shallowRef(null)
const lowerLegL: ShallowRef<ExposedRigidBody> = shallowRef(null)

const upperLegR: ShallowRef<ExposedRigidBody> = shallowRef(null)
const lowerLegR: ShallowRef<ExposedRigidBody> = shallowRef(null)

// Adjust this to make it more flexible
const stiffness = 0.02

const torsoWidth = 0.4
const torsoHeight = 0.4

const headSize = 0.2

const armLength = 0.25
const armThickness = 0.15

const legSegmentHeight = torsoHeight * 0.8
const legthickness = 0.16
Copy link

Copilot AI Aug 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Variable name contains a spelling error: 'legthickness' should be 'legThickness' to follow consistent camelCase naming.

Suggested change
const legthickness = 0.16
const legThickness = 0.16

Copilot uses AI. Check for mistakes.

const localAnchorHead = [0, -headSize / 2 - stiffness, 0]
const localAnchorNeck = [0, torsoHeight / 2, 0]

const localAnchorLTorso = [(torsoWidth / 2) + stiffness, 0.1, 0]
const localAnchorLArm = [-armLength / 2, 0, 0]

const localAnchorLArmBottom = [(armLength / 2) + stiffness, 0 / 2, 0.0]
const localAnchorLArmLower = [-armLength / 2, 0 / 2, 0]

const localAnchorRTorso = [-(torsoWidth / 2) - stiffness, 0.1, 0]
const localAnchorRArm = [armLength / 2, 0, 0]

const localAnchorRArmBottom = [-(armLength / 2) - stiffness, 0 / 2, 0.0]
const localAnchorRArmLower = [armLength / 2, 0 / 2, 0]

const localAnchorLTorsoBottom = [-(torsoWidth / 2) + legthickness / 2, -torsoHeight / 2 - stiffness, 0]
const localAnchorLLegUpper = [0, legSegmentHeight / 2, 0]

const localAnchorLLegUpperLower = [0, -legSegmentHeight / 2 - stiffness, 0]
const localAnchorLLegLowerTop = [0, legSegmentHeight / 2, 0]

const localAnchorRTorsoBottom = [+(torsoWidth / 2) - legthickness / 2, -torsoHeight / 2 - stiffness, 0]
Copy link

Copilot AI Aug 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Variable reference contains a spelling error: 'legthickness' should be 'legThickness' to match the corrected variable name.

Suggested change
const localAnchorRTorsoBottom = [+(torsoWidth / 2) - legthickness / 2, -torsoHeight / 2 - stiffness, 0]
const localAnchorLTorsoBottom = [-(torsoWidth / 2) + legThickness / 2, -torsoHeight / 2 - stiffness, 0]
const localAnchorLLegUpper = [0, legSegmentHeight / 2, 0]
const localAnchorLLegUpperLower = [0, -legSegmentHeight / 2 - stiffness, 0]
const localAnchorLLegLowerTop = [0, legSegmentHeight / 2, 0]
const localAnchorRTorsoBottom = [+(torsoWidth / 2) - legThickness / 2, -torsoHeight / 2 - stiffness, 0]

Copilot uses AI. Check for mistakes.
Copy link

Copilot AI Aug 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Variable reference contains a spelling error: 'legthickness' should be 'legThickness' to match the corrected variable name.

Suggested change
const localAnchorRTorsoBottom = [+(torsoWidth / 2) - legthickness / 2, -torsoHeight / 2 - stiffness, 0]
const localAnchorLTorsoBottom = [-(torsoWidth / 2) + legThickness / 2, -torsoHeight / 2 - stiffness, 0]
const localAnchorLLegUpper = [0, legSegmentHeight / 2, 0]
const localAnchorLLegUpperLower = [0, -legSegmentHeight / 2 - stiffness, 0]
const localAnchorLLegLowerTop = [0, legSegmentHeight / 2, 0]
const localAnchorRTorsoBottom = [+(torsoWidth / 2) - legThickness / 2, -torsoHeight / 2 - stiffness, 0]

Copilot uses AI. Check for mistakes.
const localAnchorRLegUpper = [0, legSegmentHeight / 2, 0]

const localAnchorRLegUpperLower = [0, -legSegmentHeight / 2 - stiffness, 0]
const localAnchorRLegLowerTop = [0, legSegmentHeight / 2, 0]

onMounted(() => {
document.addEventListener('click', () => {
if (!headRef.value) { return }

headRef.value.instance?.applyImpulse({ x: 0, y: 10, z: 0 }, true)
})
Copy link

Copilot AI Aug 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The click event listener is added to the document without being removed on component unmount, which could cause memory leaks. Consider using onUnmounted to clean up the event listener.

Suggested change
})
const handleDocumentClick = () => {
if (!headRef.value) { return }
headRef.value.instance?.applyImpulse({ x: 0, y: 10, z: 0 }, true)
}
onMounted(() => {
document.addEventListener('click', handleDocumentClick)
})
onUnmounted(() => {
document.removeEventListener('click', handleDocumentClick)

Copilot uses AI. Check for mistakes.
})
</script>

<template>
<RigidBody ref="headRef">
<CuboidCollider :args="[headSize / 2, headSize / 2, headSize / 2]" />
</RigidBody>

<SphericalJoint
:bodies="[headRef?.instance, torsoRef?.instance]"
:params="[
localAnchorHead,
localAnchorNeck,
]"
/>
<RigidBody ref="torsoRef">
<CuboidCollider :args="[torsoWidth / 2, torsoHeight / 2, .1]" />
</RigidBody>

<SphericalJoint
:bodies="[torsoRef?.instance, upperArmL?.instance]"
:params="[
localAnchorLTorso,
localAnchorLArm,
]"
/>

<RigidBody ref="upperArmL">
<CuboidCollider :args="[armLength / 2, armThickness / 2, armThickness / 2]" />
</RigidBody>

<SphericalJoint
:bodies="[upperArmL?.instance, lowerArmL?.instance]"
:params="[
localAnchorLArmBottom,
localAnchorLArmLower,
]"
/>

<RigidBody ref="lowerArmL">
<CuboidCollider :args="[armLength / 2, armThickness / 2, armThickness / 2]" />
</RigidBody>

<SphericalJoint
:bodies="[torsoRef?.instance, upperArmR?.instance]"
:params="[
localAnchorRTorso,
localAnchorRArm,
]"
/>

<RigidBody ref="upperArmR">
<CuboidCollider :args="[armLength / 2, armThickness / 2, armThickness / 2]" />
</RigidBody>

<SphericalJoint
:bodies="[upperArmR?.instance, lowerArmR?.instance]"
:params="[
localAnchorRArmBottom,
localAnchorRArmLower,
]"
/>

<RigidBody ref="lowerArmR">
<CuboidCollider :args="[armLength / 2, armThickness / 2, armThickness / 2]" />
</RigidBody>

<SphericalJoint
:bodies="[torsoRef?.instance, upperLegL?.instance]"
:params="[
localAnchorLTorsoBottom,
localAnchorLLegUpper,
]"
/>

<RigidBody ref="upperLegL">
<CuboidCollider :args="[legthickness / 2, legSegmentHeight / 2, legthickness / 2]" />
Copy link

Copilot AI Aug 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Variable reference contains a spelling error: 'legthickness' should be 'legThickness' to match the corrected variable name.

Suggested change
<CuboidCollider :args="[legthickness / 2, legSegmentHeight / 2, legthickness / 2]" />
<CuboidCollider :args="[legThickness / 2, legSegmentHeight / 2, legThickness / 2]" />

Copilot uses AI. Check for mistakes.
</RigidBody>

<SphericalJoint
:bodies="[upperLegL?.instance, lowerLegL?.instance]"
:params="[
localAnchorLLegUpperLower,
localAnchorLLegLowerTop,
]"
/>

<RigidBody ref="lowerLegL">
<CuboidCollider :args="[legthickness / 2, legSegmentHeight / 2, legthickness / 2]" />
Copy link

Copilot AI Aug 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Variable reference contains a spelling error: 'legthickness' should be 'legThickness' to match the corrected variable name.

Suggested change
<CuboidCollider :args="[legthickness / 2, legSegmentHeight / 2, legthickness / 2]" />
<CuboidCollider :args="[legThickness / 2, legSegmentHeight / 2, legThickness / 2]" />

Copilot uses AI. Check for mistakes.
</RigidBody>

<SphericalJoint
:bodies="[torsoRef?.instance, upperLegR?.instance]"
:params="[
localAnchorRTorsoBottom,
localAnchorRLegUpper,
]"
/>

<RigidBody ref="upperLegR">
<CuboidCollider :args="[legthickness / 2, legSegmentHeight / 2, legthickness / 2]" />
Copy link

Copilot AI Aug 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Variable reference contains a spelling error: 'legthickness' should be 'legThickness' to match the corrected variable name.

Suggested change
<CuboidCollider :args="[legthickness / 2, legSegmentHeight / 2, legthickness / 2]" />
<CuboidCollider :args="[legThickness / 2, legSegmentHeight / 2, legThickness / 2]" />

Copilot uses AI. Check for mistakes.
</RigidBody>

<SphericalJoint
:bodies="[upperLegR?.instance, lowerLegR?.instance]"
:params="[
localAnchorRLegUpperLower,
localAnchorRLegLowerTop,
]"
/>

<RigidBody ref="lowerLegR">
<CuboidCollider :args="[legthickness / 2, legSegmentHeight / 2, legthickness / 2]" />
Copy link

Copilot AI Aug 12, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Variable reference contains a spelling error: 'legthickness' should be 'legThickness' to match the corrected variable name.

Suggested change
<CuboidCollider :args="[legthickness / 2, legSegmentHeight / 2, legthickness / 2]" />
<CuboidCollider :args="[legThickness / 2, legSegmentHeight / 2, legThickness / 2]" />

Copilot uses AI. Check for mistakes.
</RigidBody>
</template>
45 changes: 45 additions & 0 deletions playground/src/pages/basics/Ragdoll.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<script lang="ts" setup>
import { OrbitControls } from '@tresjs/cientos'
import { TresCanvas } from '@tresjs/core'
import { TresLeches, useControls } from '@tresjs/leches'
// eslint-disable-next-line ts/ban-ts-comment
// @ts-ignore
import { Physics, RigidBody } from '@tresjs/rapier'
import { ACESFilmicToneMapping, SRGBColorSpace } from 'three'
import '@tresjs/leches/styles'

import Ragdoll from './../../components/Ragdoll.vue'

const gl = {
clearColor: '#82DBC5',
shadows: true,
alpha: false,
outputColorSpace: SRGBColorSpace,
toneMapping: ACESFilmicToneMapping,
}

const { gravityY } = useControls({
gravityY: { value: -9.81, min: -20, max: 20, step: 0.1 },
})
</script>

<template>
<TresLeches />
<TresCanvas v-bind="gl" window-size>
<TresPerspectiveCamera :position="[-4, 1, -4]" :look-at="[0, 0, 0]" />
<OrbitControls />

<Suspense>
<Physics debug :gravity="[0, gravityY, 0]">
<Ragdoll />

<RigidBody type="fixed" :position="[0, -1, 0]">
<TresMesh>
<TresPlaneGeometry :args="[20, 20, 20]" :rotate-x="-Math.PI / 2" />
<TresMeshBasicMaterial color="#f4f4f4" />
</TresMesh>
</RigidBody>
</Physics>
</Suspense>
</TresCanvas>
</template>
5 changes: 5 additions & 0 deletions playground/src/router/routes/basics.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,9 @@ export const basicsRoutes = [
name: 'Advanced Joints',
component: () => import('../../pages/basics/JointsAdvancedDemo.vue'),
},
{
path: '/basics/ragdoll',
name: 'Basic Ragdoll',
component: () => import('../../pages/basics/Ragdoll.vue'),
},
]
33 changes: 21 additions & 12 deletions src/components/RigidBody.vue
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import type {
ExposedRigidBody,
RigidBodyContext,
RigidBodyProps,
TresVNodeObject,
} from '../types'

const props = withDefaults(defineProps<Partial<RigidBodyProps>>(), {
Expand Down Expand Up @@ -82,12 +83,20 @@ watch(bodyGroup, async (group) => {
}),
group,
colliders: [],

}

if (props.collider !== false) {
const collidersProps: ColliderProps[] = []

for (const child of group.children) {
const vNode = (child as TresVNodeObject).__vnode
const vNodeExposed = (vNode.ctx as TresVNodeObject['__vnode']['ctx'] & { exposed: TresVNodeObject })?.exposed

if (vNode.type === 'TresObject3D' && vNodeExposed?.instance?.__v_isRef) {
continue
}

const _props = createColliderPropsFromObject(child, props.collider)
_props.friction = props.friction
_props.mass = props.mass
Expand All @@ -109,18 +118,6 @@ watch(bodyGroup, async (group) => {
bodyContext.value = newPhysicsState
}, { once: true })

makePropsWatcherRB(props, [
'gravityScale',
'additionalMass',
'linearDamping',
'angularDamping',
'dominanceGroup',
'linvel',
'angvel',
'enabledRotations',
'enabledTranslations',
], instance)

watch([() => props.lockTranslations, instance], ([_lockTranslations, _]) => {
if (!instance.value) { return }
instance.value.lockTranslations(_lockTranslations, true)
Expand Down Expand Up @@ -160,6 +157,18 @@ onUnmounted(() => {

bodyContext.value = undefined
})

makePropsWatcherRB(props, [
'gravityScale',
'additionalMass',
'linearDamping',
'angularDamping',
'dominanceGroup',
'linvel',
'angvel',
'enabledRotations',
'enabledTranslations',
], instance)
</script>

<template>
Expand Down
Loading