122 lines
4.3 KiB
JavaScript
122 lines
4.3 KiB
JavaScript
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 } |