UNPKG

three-game-engine

Version:

Simple light-weight game engine using three.js, three-mesh-ui and rapier

139 lines (138 loc) 8.07 kB
"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;