@c-frame/aframe-physics-system
Version:
Physics system for A-Frame VR, built on Cannon.js & Ammo.js
129 lines (103 loc) • 4.15 kB
JavaScript
var CANNON = require("cannon-es");
module.exports = AFRAME.registerComponent("constraint", {
multiple: true,
schema: {
// Type of constraint.
type: { default: "lock", oneOf: ["coneTwist", "distance", "hinge", "lock", "pointToPoint"] },
// Target (other) body for the constraint.
target: { type: "selector" },
// Maximum force that should be applied to constraint the bodies.
maxForce: { default: 1e6, min: 0 },
// If true, bodies can collide when they are connected.
collideConnected: { default: true },
// Wake up bodies when connected.
wakeUpBodies: { default: true },
// The distance to be kept between the bodies. If 0, will be set to current distance.
distance: { default: 0, min: 0 },
// Offset of the hinge or point-to-point constraint, defined locally in the body.
pivot: { type: "vec3" },
targetPivot: { type: "vec3" },
// An axis that each body can rotate around, defined locally to that body.
axis: { type: "vec3", default: { x: 0, y: 0, z: 1 } },
targetAxis: { type: "vec3", default: { x: 0, y: 0, z: 1 } }
},
init: function() {
this.system = this.el.sceneEl.systems.physics;
this.constraint = /* {CANNON.Constraint} */ null;
},
remove: function() {
if (!this.constraint) return;
this.system.removeConstraint(this.constraint);
this.constraint = null;
},
update: function() {
var el = this.el,
data = this.data;
this.remove();
if (!el.body || !data.target.body) {
(el.body ? data.target : el).addEventListener("body-loaded", this.update.bind(this, {}));
return;
}
this.constraint = this.createConstraint();
this.system.addConstraint(this.constraint);
},
/**
* Creates a new constraint, given current component data. The CANNON.js constructors are a bit
* different for each constraint type. A `.type` property is added to each constraint, because
* `instanceof` checks are not reliable for some types. These types are needed for serialization.
* @return {CANNON.Constraint}
*/
createConstraint: function() {
var constraint,
data = this.data,
pivot = new CANNON.Vec3(data.pivot.x, data.pivot.y, data.pivot.z),
targetPivot = new CANNON.Vec3(data.targetPivot.x, data.targetPivot.y, data.targetPivot.z),
axis = new CANNON.Vec3(data.axis.x, data.axis.y, data.axis.z),
targetAxis = new CANNON.Vec3(data.targetAxis.x, data.targetAxis.y, data.targetAxis.z);
var constraint;
switch (data.type) {
case "lock":
constraint = new CANNON.LockConstraint(this.el.body, data.target.body, { maxForce: data.maxForce });
constraint.type = "LockConstraint";
break;
case "distance":
constraint = new CANNON.DistanceConstraint(this.el.body, data.target.body, data.distance, data.maxForce);
constraint.type = "DistanceConstraint";
break;
case "hinge":
constraint = new CANNON.HingeConstraint(this.el.body, data.target.body, {
pivotA: pivot,
pivotB: targetPivot,
axisA: axis,
axisB: targetAxis,
maxForce: data.maxForce
});
constraint.type = "HingeConstraint";
break;
case "coneTwist":
constraint = new CANNON.ConeTwistConstraint(this.el.body, data.target.body, {
pivotA: pivot,
pivotB: targetPivot,
axisA: axis,
axisB: targetAxis,
maxForce: data.maxForce
});
constraint.type = "ConeTwistConstraint";
break;
case "pointToPoint":
constraint = new CANNON.PointToPointConstraint(
this.el.body,
pivot,
data.target.body,
targetPivot,
data.maxForce
);
constraint.type = "PointToPointConstraint";
break;
default:
throw new Error("[constraint] Unexpected type: " + data.type);
}
constraint.collideConnected = data.collideConnected;
return constraint;
}
});