Newer
Older
/* global THREE, CANNON, AFRAME */
AFRAME.registerComponent("sticky-object", {
schema: {
autoLockOnLoad: { default: false },
autoLockOnRelease: { default: false },
autoLockSpeedLimit: { default: 0.5 } // Set to 0 to always autolock on release
},
init() {
this._onGrab = this._onGrab.bind(this);
this._onRelease = this._onRelease.bind(this);
this._onBodyLoaded = this._onBodyLoaded.bind(this);
this.el.addEventListener("grab-start", this._onGrab);
this.el.addEventListener("grab-end", this._onRelease);
if (this.hasSetupBodyLoaded) return;
this.hasSetupBodyLoaded = true;
if (this.el.body) {
this._onBodyLoaded();
} else {
this.el.addEventListener("body-loaded", this._onBodyLoaded, { once: true });
}
pause() {
this.el.removeEventListener("grab-start", this._onGrab);
this.el.removeEventListener("grab-end", this._onRelease);
if (this.el.components.networked && !NAF.utils.isMine(this.el)) return;
this.el.setAttribute("body", { type: locked ? "static" : "dynamic" });
},
_onBodyLoaded() {
if (this.data.autoLockOnLoad) {
this.setLocked(true);
}
},
if (this.el.is("grabbed")) return;
(this.data.autoLockSpeedLimit === 0 ||
this.el.body.velocity.lengthSquared() < this.data.autoLockSpeedLimit * this.data.autoLockSpeedLimit)
this.el.body.collisionResponse = true;
if (!this.el.components.grabbable || this.el.components.grabbable.data.maxGrabbers === 0) return;
this.el.body.collisionResponse = false;
this.el.removeEventListener("body-loaded", this._onBodyLoaded);
const stuckTo = this.stuckTo;
delete this.stuckTo;
stuckTo._unstickObject();
}
});
AFRAME.registerComponent("sticky-object-zone", {
dependencies: ["physics"],
init() {
// TODO: position/rotation/impulse need to get updated if the sticky-object-zone moves
this.worldQuaternion = new THREE.Quaternion();
this.worldPosition = new THREE.Vector3();
this.el.object3D.getWorldQuaternion(this.worldQuaternion);
this.el.object3D.getWorldPosition(this.worldPosition);
const dir = new THREE.Vector3(0, 0, 5).applyQuaternion(this.el.object3D.quaternion);
this.bootImpulsePosition = new CANNON.Vec3(0, 0, 0);
this.bootImpulse = new CANNON.Vec3();
this.bootImpulse.copy(dir);
this._onCollisions = this._onCollisions.bind(this);
this.el.addEventListener("collisions", this._onCollisions);
},
remove() {
this.el.removeEventListener("collisions", this._onCollisions);
},
_onCollisions(e) {
e.detail.els.forEach(el => {
const stickyObject = el.components["sticky-object"];
if (!stickyObject) return;
this._setStuckObject(stickyObject);
if (this.stuckObject) {
e.detail.clearedEls.forEach(el => {
if (this.stuckObject && this.stuckObject.el === el) {
this._unstickObject();
}
});
}
},
_setStuckObject(stickyObject) {
stickyObject.setLocked(true);
stickyObject.el.object3D.position.copy(this.worldPosition);
stickyObject.el.object3D.quaternion.copy(this.worldQuaternion);
stickyObject.el.body.collisionResponse = false;
stickyObject.stuckTo = this;
if (this.stuckObject && NAF.utils.isMine(this.stuckObject.el)) {
this._unstickObject();
el.body.applyImpulse(this.bootImpulse, this.bootImpulsePosition);
}
this.stuckObject = stickyObject;
},
_unstickObject() {
// this condition will be false when dragging an object directly from one sticky zone to another
if (this.stuckObject.stuckTo === this) {
this.stuckObject.setLocked(false);
this.stuckObject.el.body.collisionResponse = true;
delete this.stuckObject.stuckTo;
}