import * as RAPIER from '@dimforge/rapier3d' import { Vector3 } from 'three'; class Physics{ constructor(engine){ this.engine = engine } init = async ()=>{ let gravity = { x: 0.0, y: -9.81, z: 0.0 }; let world = new RAPIER.World(gravity); // Create Ground. let bodyDesc = RAPIER.RigidBodyDesc.fixed(); let body = world.createRigidBody(bodyDesc); let colliderDesc = RAPIER.ColliderDesc.cuboid(100, 0, 100); //bodyDesc.setTranslation(-50,0,-50); world.createCollider(colliderDesc, body.handle); this.world = world; this.physicsObjects = []; this.eventQueue = new RAPIER.EventQueue(true); return this; } add = (mesh, rigidBodyType, autoAnimate = true, postPhysicsFn, colliderType, colliderSettings = {}) => { const rigidBodyDesc = RAPIER.RigidBodyDesc[rigidBodyType]() rigidBodyDesc.setTranslation(mesh.position.x, mesh.position.y, mesh.position.z) mesh.quaternion && rigidBodyDesc.setRotation(mesh.quaternion) // * Responsible for collision response const rigidBody = this.world.createRigidBody(rigidBodyDesc) rigidBody.userData = colliderSettings.userData || {}; let colliderDesc switch (colliderType) { case 'cuboid':{ const { width, height, depth } = colliderSettings colliderDesc = RAPIER.ColliderDesc.cuboid(width, height, depth) } break case 'ball':{ const { radius } = colliderSettings colliderDesc = RAPIER.ColliderDesc.ball(radius) } break case 'capsule':{ const { halfHeight, radius } = colliderSettings colliderDesc = RAPIER.ColliderDesc.capsule(halfHeight, radius) } break default:{ const vertices = []; const vertex = new Vector3(); const position = mesh.geometry.getAttribute( 'position' ); for ( let i = 0; i < position.count; i ++ ) { vertex.fromBufferAttribute( position, i ); vertices.push( vertex.x, vertex.y, vertex.z ); } // if the buffer is non-indexed, generate an index buffer const indices = mesh.geometry.getIndex() === null ? Uint32Array.from( Array( parseInt( vertices.length / 3 ) ).keys() ) : mesh.geometry.getIndex().array; colliderDesc = RAPIER.ColliderDesc.trimesh( vertices, indices ); } break } if (!colliderDesc) { console.error('Collider Mesh Error: convex mesh creation failed.') } if (colliderSettings.isSensor){ colliderDesc.setSensor(true); colliderDesc.setActiveEvents(RAPIER.ActiveEvents.COLLISION_EVENTS); colliderDesc.setActiveCollisionTypes(RAPIER.ActiveCollisionTypes.KINEMATIC_FIXED); } // * Responsible for collision detection const collider = this.world.createCollider(colliderDesc, rigidBody) mesh.quaternion && collider.setRotationWrtParent(mesh.quaternion) const physicsObject = { mesh, collider, rigidBody, fn: postPhysicsFn, autoAnimate } this.physicsObjects.push(physicsObject) return physicsObject } clear(){ this.physicsObjects.forEach(po=>{ po.characterController && this.world.removeCharacterController(po.characterController) this.world.removeCollider(po.collider); this.world.removeRigidBody(po.rigidBody); }) this.physicsObjects = []; } step(){ this.world.step(this.eventQueue) for (let po of this.physicsObjects) { if (po.autoAnimate) { po.mesh.position.copy(po.rigidBody.translation()) po.mesh.quaternion.copy(po.rigidBody.rotation() ) } po.fn?.() } this.eventQueue.drainCollisionEvents((handle1, handle2, started) => { /* Handle the collision event. */ //console.log(this.world.getCollider(handle2), handle1, started) this.engine.dispatchEvent({ type: 'collision', handle1, handle2, started }) }); } } export { Physics }