three-game-engine
Version:
Simple light-weight game engine using three.js, three-mesh-ui and rapier
139 lines (138 loc) • 8.07 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const Component_1 = require("../Component");
const rapier3d_compat_1 = require("@dimforge/rapier3d-compat");
class RigidBodyComponent extends Component_1.default {
constructor(gameObject, jsonData) {
super(gameObject, jsonData);
this.rapierRigidBody = null;
}
load() {
const scene = this.gameObject.getScene();
if (!scene) {
throw new Error('setupPhysicsForGameObject: must be called on a GameObject that is attached to a scene, with a Rapier world associated with it');
}
const rigidBodyDesc = this._createRigidBodyDesc(this.jsonData.type);
this.rapierRigidBody = scene.rapierWorld.createRigidBody(rigidBodyDesc);
// Position the RigidBody within the Physics World, at the (world) position
// it should be based on the world position of the threeJS group representing the GameObject
// TODO: get world position of threeJSGroup not local
const x = this.gameObject.threeJSGroup.position.x;
const y = this.gameObject.threeJSGroup.position.y;
const z = this.gameObject.threeJSGroup.position.z;
const rigidBodyTranslation = new rapier3d_compat_1.default.Vector3(x, y, z);
this.rapierRigidBody.setTranslation(rigidBodyTranslation, true);
const worldRotation = this.gameObject.threeJSGroup.quaternion.clone();
this.rapierRigidBody.setRotation(worldRotation, true);
if (this.jsonData.enabledTranslations) {
const enabledTrans = Object.assign({ x: true, y: true, z: true }, this.jsonData.enabledTranslations);
this.rapierRigidBody.setEnabledTranslations(enabledTrans.x, enabledTrans.y, enabledTrans.z, true);
}
if (this.jsonData.enabledRotations) {
const enabledRots = Object.assign({ x: true, y: true, z: true }, this.jsonData.enabledRotations);
this.rapierRigidBody.setEnabledRotations(enabledRots.x, enabledRots.y, enabledRots.z, true);
}
(this.jsonData.colliders || []).forEach(colliderData => {
const colliderDesc = this._createColliderDesc(colliderData);
const collider = scene.rapierWorld.createCollider(colliderDesc, this.rapierRigidBody);
if (typeof colliderData.density !== 'undefined') {
collider.setDensity(colliderData.density);
}
if (typeof colliderData.friction !== 'undefined') {
collider.setFriction(colliderData.friction);
}
if (typeof colliderData.sensor !== 'undefined') {
collider.setSensor(colliderData.sensor);
}
});
}
_createRigidBodyDesc(type) {
switch (type) {
case 'fixed':
return rapier3d_compat_1.default.RigidBodyDesc.fixed();
case 'dynamic':
return rapier3d_compat_1.default.RigidBodyDesc.dynamic();
case 'kinematicPositionBased':
return rapier3d_compat_1.default.RigidBodyDesc.kinematicPositionBased();
case 'kinematicVelocityBased':
return rapier3d_compat_1.default.RigidBodyDesc.kinematicVelocityBased();
default:
throw new Error(`GameObject: load(): invalid rigidBody.type: ${type}`);
}
}
_createColliderDesc(colliderData) {
const propsByColliderType = {
ball: ['radius'],
capsule: ['halfHeight', 'radius'],
cone: ['halfHeight', 'radius'],
convexHull: ['points'],
convexMesh: ['vertices', 'indices'],
cuboid: ['hx', 'hy', 'hz'],
cylinder: ['halfHeight', 'radius'],
polyline: ['vertices', 'indices'],
roundCone: ['halfHeight', 'radius', 'borderRadius'],
roundConvexHull: ['points', 'borderRadius'],
roundConvexMesh: ['vertices', 'indices', 'borderRadius'],
roundCuboid: ['hx', 'hy', 'hz', 'borderRadius'],
roundCylinder: ['halfHeight', 'radius', 'borderRadius'],
roundTriangle: ['a', 'b', 'c', 'borderRadius'],
trimesh: ['vertices', 'indices'],
heightfield: ['nrows', 'ncols', 'heights', 'scale']
};
const requiredProps = propsByColliderType[colliderData.type];
if (typeof requiredProps === 'undefined') {
throw new Error(`PhysicsHelpers.createColliderDesc(): invalid collider type: ${colliderData.type}`);
}
const missingProps = requiredProps.filter(prop => typeof colliderData[prop] == 'undefined');
if (missingProps.length) {
throw new Error(`PhysicsHelpers.createColliderDesc(): the following require props are missing: ${missingProps} for a collider of type ${colliderData.type}`);
}
switch (colliderData.type) {
case 'ball':
return rapier3d_compat_1.default.ColliderDesc.ball(colliderData.radius);
case 'capsule':
return rapier3d_compat_1.default.ColliderDesc.capsule(colliderData.halfHeight, colliderData.radius);
case 'cone':
return rapier3d_compat_1.default.ColliderDesc.cone(colliderData.halfHeight, colliderData.radius);
case 'convexHull':
return rapier3d_compat_1.default.ColliderDesc.convexHull(colliderData.points);
case 'convexMesh':
return rapier3d_compat_1.default.ColliderDesc.convexMesh(colliderData.vertices, colliderData.indices);
case 'cuboid':
return rapier3d_compat_1.default.ColliderDesc.cuboid(colliderData.hx, colliderData.hy, colliderData.hz);
case 'cylinder':
return rapier3d_compat_1.default.ColliderDesc.cylinder(colliderData.halfHeight, colliderData.radius);
case 'polyline':
return rapier3d_compat_1.default.ColliderDesc.polyline(colliderData.vertices, colliderData.indices);
case 'roundCone':
return rapier3d_compat_1.default.ColliderDesc.roundCone(colliderData.halfHeight, colliderData.radius, colliderData.borderRadius);
case 'roundConvexHull':
return rapier3d_compat_1.default.ColliderDesc.roundConvexHull(colliderData.points, colliderData.borderRadius);
case 'roundConvexMesh':
return rapier3d_compat_1.default.ColliderDesc.roundConvexMesh(colliderData.vertices, colliderData.indices, colliderData.borderRadius);
case 'roundCuboid':
return rapier3d_compat_1.default.ColliderDesc.roundCuboid(colliderData.hx, colliderData.hy, colliderData.hz, colliderData.borderRadius);
case 'roundCylinder':
return rapier3d_compat_1.default.ColliderDesc.roundCylinder(colliderData.halfHeight, colliderData.radius, colliderData.borderRadius);
case 'roundTriangle':
return rapier3d_compat_1.default.ColliderDesc.roundTriangle(colliderData.a, colliderData.b, colliderData.c, colliderData.borderRadius);
case 'trimesh':
return rapier3d_compat_1.default.ColliderDesc.trimesh(colliderData.vertices, colliderData.indices);
case 'heightfield':
return rapier3d_compat_1.default.ColliderDesc.heightfield(colliderData.nrows, colliderData.ncols, colliderData.heights, colliderData.scale);
default:
throw new Error(`GameObject: load(): invalid collider type: ${colliderData.type}`);
}
}
beforeRender() {
// console.log('==> syncing gameObjec with rigid body position')
// const threeJSGroup = this.gameObject.threeJSGroup;
// // TODO: set world position of threeJSGroup, not local
// threeJSGroup.position.copy(this.rapierRigidBody.translation() as THREE.Vector3);
// threeJSGroup.quaternion.copy(this.rapierRigidBody.rotation() as THREE.Quaternion);
}
getRapierRigidBody() {
return this.rapierRigidBody;
}
}
exports.default = RigidBodyComponent;