Skip to content

Commit

Permalink
feat(app): 105 First stage of Collision event
Browse files Browse the repository at this point in the history
  • Loading branch information
JaimeTorrealba committed Oct 2, 2024
1 parent 1e2d7e3 commit 0bfbb5b
Show file tree
Hide file tree
Showing 8 changed files with 235 additions and 17 deletions.
88 changes: 88 additions & 0 deletions playground/src/pages/basics/CollisionDemo.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<script setup lang="ts">
import { OrbitControls } from '@tresjs/cientos'
import { TresCanvas } from '@tresjs/core'
import { BallCollider, Physics, RigidBody } from '@tresjs/rapier'
import { ACESFilmicToneMapping, SRGBColorSpace } from 'three'
import { shallowRef } from 'vue'
const gl = {
clearColor: '#82DBC5',
shadows: true,
alpha: false,
outputColorSpace: SRGBColorSpace,
toneMapping: ACESFilmicToneMapping,
}
const rigidTorusRef = shallowRef()
const ballRef = shallowRef()
const jump = () => {
if (!rigidTorusRef.value) { return }
rigidTorusRef.value.instance.applyImpulse({ x: 0, y: 5, z: 0 }, true)
}
const jumpBall = () => {
if (!ballRef.value) { return }
ballRef.value.instance.applyImpulse({ x: 0, y: 5, z: 0 }, true)
}
const onCollisionEnter = (event: any) => {
// eslint-disable-next-line no-console
console.log('jaime ~ ENTER', event)
}
const onCollisionEnterBall = (event: any) => {
// eslint-disable-next-line no-console
console.log('jaime ~ ENTER', event.source.rapierGroup.collider.collisionGroups())
}
const onCollisionExit = (event: any) => {
// eslint-disable-next-line no-console
console.log('jaime ~ EXIT', event)
}
</script>

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

<Suspense>
<Physics debug>
<RigidBody
ref="rigidTorusRef"
name="rigidTorus"
enableCcd
activeCollision
@collision-enter="onCollisionEnter"
@collision-exit="onCollisionExit"
>
<TresMesh :position="[0, 8, 0]" @click="jump">
<TresTorusGeometry />
<TresMeshNormalMaterial />
</TresMesh>
<TresMesh :position="[-5, 7, 0]">
<TresSphereGeometry />
<TresMeshNormalMaterial />
</TresMesh>
</RigidBody>

<RigidBody
@collision-enter="onCollisionEnterBall"
>
<BallCollider
ref="ballRef"
activeCollision
:args="[1, 1, 1]"
:position="[8, 15, 0]"
@click="jumpBall"
/>
</RigidBody>

<RigidBody type="fixed" name="fixedFloor">
<TresMesh :position="[0, 0, 0]">
<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 @@ -29,4 +29,9 @@ export const basicsRoutes = [
name: 'Props',
component: () => import('../../pages/basics/RigidBodyProps.vue'),
},
{
path: '/basics/collision',
name: 'Collision',
component: () => import('../../pages/basics/CollisionDemo.vue'),
},
]
24 changes: 21 additions & 3 deletions src/components/Physics.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
<script setup lang="ts">
import { useLoop } from '@tresjs/core'
import { EventQueue } from '@dimforge/rapier3d-compat'
import { useLoop, useTresContext } from '@tresjs/core'
import { Vector3 } from 'three'
import { watch } from 'vue'
import type { VectorCoordinates } from '@tresjs/core'
import { useRapierContextProvider } from '../composables/useRapier'
import { GRAVITY } from '../constants/physics'
import { collisionEmisor, get3DGroupFromSource, getSourceFromColliderHandle } from '../utils/collisions'
import Debug from './Debug.vue'
import type { PhysicsProps } from '../types'
Expand Down Expand Up @@ -34,6 +36,9 @@ const setGravity = (gravity: PhysicsProps['gravity']) => {
}
}
const eventQueue = new EventQueue(true)
const { scene } = useTresContext()
watch(() => props.gravity, (gravity) => {
setGravity(gravity)
}, { immediate: true })
Expand All @@ -46,7 +51,20 @@ onBeforeRender(() => {
world.timestep = props.timestep
}
world.step()
world.step(eventQueue)
eventQueue.drainCollisionEvents((handle1, handle2, started) => {
const source1 = getSourceFromColliderHandle(world, handle1)
const source2 = getSourceFromColliderHandle(world, handle2)
const group1 = get3DGroupFromSource(source1, scene)
const group2 = get3DGroupFromSource(source2, scene)
if (group1 && group2) {
collisionEmisor(
{ group: group1, rapierGroup: source1 },
{ group: group2, rapierGroup: source2 },
started,
)
}
})
})
</script>

Expand Down
13 changes: 12 additions & 1 deletion src/components/RigidBody.vue
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
<script setup lang="ts">
import { ActiveCollisionTypes } from '@dimforge/rapier3d-compat'
import { useLoop } from '@tresjs/core'
import { Object3D } from 'three'
import { nextTick, onUnmounted, onUpdated, provide, shallowRef, watch } from 'vue'
Expand All @@ -24,12 +25,15 @@ const props = withDefaults(defineProps<Partial<RigidBodyProps>>(), {
enabledTranslations: () => ({ x: true, y: true, z: true }),
lockTranslations: false,
lockRotations: false,
enableCcd: false,
// Automatic collider props
friction: 0.5,
mass: 1,
restitution: 0,
density: 1,
activeCollision: false,
activeCollisionTypes: ActiveCollisionTypes.DEFAULT,
collisionGroups: undefined, // this is not working
})
const { onBeforeRender } = useLoop()
const { world } = useRapierContext()
Expand Down Expand Up @@ -101,6 +105,10 @@ watch([() => props.lockRotations, instance], ([_lockRotations, _]) => {
if (!instance.value) { return }
instance.value.lockRotations(_lockRotations, true)
})
watch([() => props.enableCcd, instance], ([_enableCcd, _]) => {
if (!instance.value) { return }
instance.value.enableCcd(_enableCcd)
})
onBeforeRender(() => {
const context = bodyContext.value
Expand Down Expand Up @@ -142,6 +150,9 @@ onUnmounted(() => {
:mass="props.mass"
:restitution="props.restitution"
:density="props.density"
:activeCollision="props.activeCollision"
:activeCollisionTypes="activeCollisionTypes"
:collisionGroups="collisionGroups"
/>
<slot v-once></slot>
</TresGroup>
Expand Down
19 changes: 17 additions & 2 deletions src/components/colliders/BaseCollider.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script setup lang="ts">
import { inject, nextTick, onUnmounted, type ShallowRef, shallowRef, watch } from 'vue'
import { ActiveCollisionTypes, ActiveEvents } from '@dimforge/rapier3d-compat'
import { inject, nextTick, onUnmounted, type ShallowRef, shallowRef, watch } from 'vue'
import { useRapierContext } from '../../composables'
import { createCollider } from '../../core/collider'
import { makePropsWatcherCL } from '../../utils/props'
Expand All @@ -13,6 +14,9 @@ const props = withDefaults(defineProps<Partial<ColliderProps>>(), {
mass: 1,
restitution: 0,
density: 1,
activeCollision: false,
activeCollisionTypes: ActiveCollisionTypes.DEFAULT,
collisionGroups: undefined,
})
const { world } = useRapierContext()
Expand Down Expand Up @@ -54,7 +58,18 @@ watch(bodyContext, async (state) => {
state.colliders.push(infos)
}, { immediate: true })
makePropsWatcherCL(props, ['friction', 'restitution', 'density', 'mass'], colliderInfos)
// TODO: collisionGroups
makePropsWatcherCL(props, ['friction', 'restitution', 'density', 'mass', 'activeCollisionTypes'], colliderInfos)
watch([() => props.activeCollision, colliderInfos], ([_activeCollision]) => {
if (!colliderInfos.value?.collider) { return }
if (_activeCollision) {
colliderInfos.value.collider.setActiveEvents(ActiveEvents.COLLISION_EVENTS)
}
else {
colliderInfos.value.collider.setActiveEvents(ActiveEvents.NONE)
}
})
onUnmounted(() => {
if (!bodyContext.value || !colliderInfos.value?.collider) { return }
Expand Down
16 changes: 16 additions & 0 deletions src/types/collider.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import type {
ActiveCollisionTypes,
Collider,
ColliderDesc,
RigidBody,
Expand Down Expand Up @@ -67,6 +68,21 @@ export interface ColliderProps {
* @default 1.0
*/
density?: number
/**
* @description Enables collisions event.
* @default false
*/
activeCollision?: boolean
/**
* @description To set the collision type.
* @default ActiveCollisionTypes.DEFAULT
*/
activeCollisionTypes?: ActiveCollisionTypes.DEFAULT
/**
* @description To set the collision group.
* @default undefined
*/
collisionGroups?: undefined | number
}

export interface ExposedCollider {
Expand Down
43 changes: 32 additions & 11 deletions src/types/rigid-body.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type { Collider, ColliderDesc, RigidBody, RigidBodyDesc, World } from '@dimforge/rapier3d-compat'
import type { ActiveCollisionTypes, Collider, ColliderDesc, RigidBody, RigidBodyDesc, World } from '@dimforge/rapier3d-compat'
import type { TresObject3D, TresVector3, VectorCoordinates } from '@tresjs/core'

import type { enableBolean } from './boolean'
Expand Down Expand Up @@ -76,29 +76,50 @@ export interface RigidBodyProps {
* @default false
*/
lockRotations?: boolean
/**
* @description Enables continuous collisions detection.
* @default false
*/
enableCcd?: boolean

// AUTOMATIC COLLIDERS

/**
* @description The friction coefficient of this collider.
* @default 0.5
*/
*/
friction?: number
/**
* @description mass.
* @default 1
*/
* @description mass.
* @default 1
*/
mass?: number
/**
* @description Restitution controls how elastic (aka. bouncy) a contact is.
* @default 0
*/
* @description Restitution controls how elastic (aka. bouncy) a contact is.
* @default 0
*/
restitution?: number
/**
* @description The collider density. If non-zero the collider's mass and angular inertia will be added.
* @default 1.0
*/
* @description The collider density. If non-zero the collider's mass and angular inertia will be added.
* @default 1.0
*/
density?: number
/**
* @description Enables collisions event.
* @default false
*/
activeCollision?: boolean
/**
* @description To set the collision type.
* @default ActiveCollisionTypes.DEFAULT
*/
activeCollisionTypes?: ActiveCollisionTypes.DEFAULT
/**
* @description To set the collision group.
* @default undefined
*/
collisionGroups?: undefined | number

}

export interface ExposedRigidBody {
Expand Down
44 changes: 44 additions & 0 deletions src/utils/collisions.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import type { Collider, ColliderHandle, RigidBody, World } from '@dimforge/rapier3d-compat'
import type { Group, Scene } from 'three'
import type { Ref } from 'vue'

interface CollisionSource {
collider: Collider
rigidBody: RigidBody | undefined
};

interface sourceTarget {
group: Group
rapierGroup: CollisionSource
}

export const getSourceFromColliderHandle = (world: World, handle: ColliderHandle) => {
const collider = world.getCollider(handle)
const rigidBodyHandle = collider?.parent()?.handle
const rigidBody
= rigidBodyHandle !== undefined
? world.getRigidBody(rigidBodyHandle)
: undefined
const source: CollisionSource = {
collider,
rigidBody,
}

return source
}

export const get3DGroupFromSource = (source: CollisionSource, scene: Ref<Scene>) => {
const uuid = (source.rigidBody?.userData as { uuid?: string })?.uuid
const currentRigidBodyNode = scene.value.getObjectByProperty('uuid', uuid)

return currentRigidBodyNode
}

export const collisionEmisor = (
source: sourceTarget,
target: sourceTarget,
started: boolean,
) => {
const collisionType = started ? 'enter' : 'exit'
source.group?.__vnode?.ctx.emit(`collision-${collisionType}`, { source, target })
}

0 comments on commit 0bfbb5b

Please sign in to comment.