@c-frame/aframe-physics-system
Version:
Physics system for A-Frame VR, built on Cannon.js & Ammo.js
123 lines (104 loc) • 3.65 kB
JavaScript
var CANNON = require('cannon-es');
var Shape = {
schema: {
shape: {default: 'box', oneOf: ['box', 'sphere', 'cylinder']},
offset: {type: 'vec3', default: {x: 0, y: 0, z: 0}},
orientation: {type: 'vec4', default: {x: 0, y: 0, z: 0, w: 1}},
// sphere
radius: {type: 'number', default: 1, if: {shape: ['sphere']}},
// box
halfExtents: {type: 'vec3', default: {x: 0.5, y: 0.5, z: 0.5}, if: {shape: ['box']}},
// cylinder
radiusTop: {type: 'number', default: 1, if: {shape: ['cylinder']}},
radiusBottom: {type: 'number', default: 1, if: {shape: ['cylinder']}},
height: {type: 'number', default: 1, if: {shape: ['cylinder']}},
numSegments: {type: 'int', default: 8, if: {shape: ['cylinder']}}
},
multiple: true,
init: function() {
if (this.el.sceneEl.hasLoaded) {
this.initShape();
} else {
this.el.sceneEl.addEventListener('loaded', this.initShape.bind(this));
}
},
initShape: function() {
this.bodyEl = this.el;
var bodyType = this._findType(this.bodyEl);
var data = this.data;
while (!bodyType && this.bodyEl.parentNode != this.el.sceneEl) {
this.bodyEl = this.bodyEl.parentNode;
bodyType = this._findType(this.bodyEl);
}
if (!bodyType) {
console.warn('body not found');
return;
}
var scale = new THREE.Vector3();
this.bodyEl.object3D.getWorldScale(scale);
var shape, offset, orientation;
if (data.hasOwnProperty('offset')) {
offset = new CANNON.Vec3(
data.offset.x * scale.x,
data.offset.y * scale.y,
data.offset.z * scale.z
);
}
if (data.hasOwnProperty('orientation')) {
orientation = new CANNON.Quaternion();
orientation.copy(data.orientation);
}
switch(data.shape) {
case 'sphere':
shape = new CANNON.Sphere(data.radius * scale.x);
break;
case 'box':
var halfExtents = new CANNON.Vec3(
data.halfExtents.x * scale.x,
data.halfExtents.y * scale.y,
data.halfExtents.z * scale.z
);
shape = new CANNON.Box(halfExtents);
break;
case 'cylinder':
shape = new CANNON.Cylinder(
data.radiusTop * scale.x,
data.radiusBottom * scale.x,
data.height * scale.y,
data.numSegments
);
//rotate by 90 degrees similar to mesh2shape:createCylinderShape
var quat = new CANNON.Quaternion();
quat.setFromEuler(90 * THREE.MathUtils.DEG2RAD, 0, 0, 'XYZ').normalize();
orientation.mult(quat, orientation);
break;
default:
console.warn(data.shape + ' shape not supported');
return;
}
if (this.bodyEl.body) {
this.bodyEl.components[bodyType].addShape(shape, offset, orientation);
} else {
this.bodyEl.addEventListener('body-loaded', function() {
this.bodyEl.components[bodyType].addShape(shape, offset, orientation);
}, {once: true});
}
},
_findType: function(el) {
if (el.hasAttribute('body')) {
return 'body';
} else if (el.hasAttribute('dynamic-body')) {
return 'dynamic-body';
} else if (el.hasAttribute('static-body')) {
return'static-body';
}
return null;
},
remove: function() {
if (this.bodyEl.parentNode) {
console.warn('removing shape component not currently supported');
}
}
};
module.exports.definition = Shape;
module.exports.Component = AFRAME.registerComponent('shape', Shape);