upgraded aframe to v1.6.0 + added check for duplicate movement-controls & touch-controls
This commit is contained in:
parent
c3b0636bf7
commit
4bc3d1c520
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -1,3 +1,43 @@
|
|||
/*
|
||||
* v0.5.1 generated at Mon Dec 9 15:41:10 UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
/*
|
||||
* v0.5.1 generated at Mon Dec 9 15:39:00 UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
/*
|
||||
* v0.5.1 generated at Mon Dec 9 15:38:50 UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
/*
|
||||
* v0.5.1 generated at Mon Dec 9 15:38:27 UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
/*
|
||||
* v0.5.1 generated at Mon Dec 9 15:37:05 UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
/*
|
||||
* v0.5.1 generated at Mon Dec 9 15:36:14 UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
/*
|
||||
* v0.5.1 generated at Mon Dec 9 15:35:39 UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
/*
|
||||
* v0.5.1 generated at Mon Dec 9 03:32:13 PM UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
/*
|
||||
* v0.5.1 generated at Mon Oct 14 11:39:48 AM CEST 2024
|
||||
* https://xrfragment.org
|
||||
|
@ -3064,10 +3104,6 @@ xrf.frag.pos = function(v, opts){
|
|||
if( pos.x == undefined ){
|
||||
let obj = scene.getObjectByName(v.string)
|
||||
if( !obj ) return console.warn("#pos="+v.string+" not found")
|
||||
//let worldPos = new THREE.Vector3()
|
||||
//obj.getWorldPosition(worldPos)
|
||||
//camera.position.copy(worldPos)
|
||||
//obj.attach(camera) // instead of add() [keeps camera animations intact]
|
||||
obj.add(camera)
|
||||
camera.position.set(0,0,0)
|
||||
let c = camera.rotation
|
||||
|
@ -4834,6 +4870,8 @@ window.AFRAME.registerComponent('xrf', {
|
|||
},
|
||||
init: async function () {
|
||||
|
||||
this.data = Object.values(this.attrValue)[0]
|
||||
|
||||
// override this.data when URL has passed (`://....com/?https://foo.com/index.glb` e.g.)
|
||||
if( typeof this.data == "string" ){
|
||||
let searchIsUri = document.location.search &&
|
||||
|
@ -5048,216 +5086,219 @@ const MAX_DELTA = 0.2; // ms
|
|||
const EPS = 10e-6;
|
||||
const MOVED = 'moved';
|
||||
|
||||
AFRAME.registerComponent('movement-controls', {
|
||||
if( !AFRAME.components['movement-controls'] ){
|
||||
|
||||
/*******************************************************************
|
||||
* Schema
|
||||
*/
|
||||
AFRAME.registerComponent('movement-controls', {
|
||||
|
||||
dependencies: ['rotation'],
|
||||
/*******************************************************************
|
||||
* Schema
|
||||
*/
|
||||
|
||||
schema: {
|
||||
enabled: { default: true },
|
||||
controls: { default: ['gamepad', 'trackpad', 'keyboard', 'touch'] },
|
||||
speed: { default: 0.3, min: 0 },
|
||||
fly: { default: false },
|
||||
constrainToNavMesh: { default: false },
|
||||
camera: { default: '[movement-controls] [camera]', type: 'selector' }
|
||||
},
|
||||
dependencies: ['rotation'],
|
||||
|
||||
/*******************************************************************
|
||||
* Lifecycle
|
||||
*/
|
||||
schema: {
|
||||
enabled: { default: true },
|
||||
controls: { default: ['gamepad', 'trackpad', 'keyboard', 'touch'] },
|
||||
speed: { default: 0.3, min: 0 },
|
||||
fly: { default: false },
|
||||
constrainToNavMesh: { default: false },
|
||||
camera: { default: '[movement-controls] [camera]', type: 'selector' }
|
||||
},
|
||||
|
||||
init: function () {
|
||||
const el = this.el;
|
||||
if (!this.data.camera) {
|
||||
this.data.camera = el.querySelector('[camera]');
|
||||
}
|
||||
this.velocityCtrl = null;
|
||||
/*******************************************************************
|
||||
* Lifecycle
|
||||
*/
|
||||
|
||||
this.velocity = new THREE.Vector3();
|
||||
this.heading = new THREE.Quaternion();
|
||||
this.eventDetail = {};
|
||||
init: function () {
|
||||
const el = this.el;
|
||||
if (!this.data.camera) {
|
||||
this.data.camera = el.querySelector('[camera]');
|
||||
}
|
||||
this.velocityCtrl = null;
|
||||
|
||||
// Navigation
|
||||
this.navGroup = null;
|
||||
this.navNode = null;
|
||||
this.velocity = new THREE.Vector3();
|
||||
this.heading = new THREE.Quaternion();
|
||||
this.eventDetail = {};
|
||||
|
||||
if (el.sceneEl.hasLoaded) {
|
||||
this.injectControls();
|
||||
} else {
|
||||
el.sceneEl.addEventListener('loaded', this.injectControls.bind(this));
|
||||
}
|
||||
},
|
||||
// Navigation
|
||||
this.navGroup = null;
|
||||
this.navNode = null;
|
||||
|
||||
if (el.sceneEl.hasLoaded) {
|
||||
this.injectControls();
|
||||
} else {
|
||||
el.sceneEl.addEventListener('loaded', this.injectControls.bind(this));
|
||||
}
|
||||
},
|
||||
|
||||
update: function (prevData) {
|
||||
const el = this.el;
|
||||
const data = this.data;
|
||||
const nav = el.sceneEl.systems.nav;
|
||||
if (el.sceneEl.hasLoaded) {
|
||||
this.injectControls();
|
||||
}
|
||||
if (nav && data.constrainToNavMesh !== prevData.constrainToNavMesh) {
|
||||
data.constrainToNavMesh
|
||||
? nav.addAgent(this)
|
||||
: nav.removeAgent(this);
|
||||
}
|
||||
if (data.enabled !== prevData.enabled) {
|
||||
// Propagate the enabled change to all controls
|
||||
for (let i = 0; i < data.controls.length; i++) {
|
||||
const name = data.controls[i] + COMPONENT_SUFFIX;
|
||||
this.el.setAttribute(name, { enabled: this.data.enabled });
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
injectControls: function () {
|
||||
const data = this.data;
|
||||
|
||||
update: function (prevData) {
|
||||
const el = this.el;
|
||||
const data = this.data;
|
||||
const nav = el.sceneEl.systems.nav;
|
||||
if (el.sceneEl.hasLoaded) {
|
||||
this.injectControls();
|
||||
}
|
||||
if (nav && data.constrainToNavMesh !== prevData.constrainToNavMesh) {
|
||||
data.constrainToNavMesh
|
||||
? nav.addAgent(this)
|
||||
: nav.removeAgent(this);
|
||||
}
|
||||
if (data.enabled !== prevData.enabled) {
|
||||
// Propagate the enabled change to all controls
|
||||
for (let i = 0; i < data.controls.length; i++) {
|
||||
const name = data.controls[i] + COMPONENT_SUFFIX;
|
||||
this.el.setAttribute(name, { enabled: this.data.enabled });
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
injectControls: function () {
|
||||
const data = this.data;
|
||||
updateNavLocation: function () {
|
||||
this.navGroup = null;
|
||||
this.navNode = null;
|
||||
},
|
||||
|
||||
for (let i = 0; i < data.controls.length; i++) {
|
||||
const name = data.controls[i] + COMPONENT_SUFFIX;
|
||||
this.el.setAttribute(name, { enabled: this.data.enabled });
|
||||
}
|
||||
},
|
||||
/*******************************************************************
|
||||
* Tick
|
||||
*/
|
||||
|
||||
updateNavLocation: function () {
|
||||
this.navGroup = null;
|
||||
this.navNode = null;
|
||||
},
|
||||
tick: (function () {
|
||||
const start = new THREE.Vector3();
|
||||
const end = new THREE.Vector3();
|
||||
const clampedEnd = new THREE.Vector3();
|
||||
|
||||
/*******************************************************************
|
||||
* Tick
|
||||
*/
|
||||
return function (t, dt) {
|
||||
if (!dt) return;
|
||||
|
||||
tick: (function () {
|
||||
const start = new THREE.Vector3();
|
||||
const end = new THREE.Vector3();
|
||||
const clampedEnd = new THREE.Vector3();
|
||||
const el = this.el;
|
||||
const data = this.data;
|
||||
|
||||
return function (t, dt) {
|
||||
if (!dt) return;
|
||||
if (!data.enabled) return;
|
||||
|
||||
const el = this.el;
|
||||
const data = this.data;
|
||||
this.updateVelocityCtrl();
|
||||
const velocityCtrl = this.velocityCtrl;
|
||||
const velocity = this.velocity;
|
||||
|
||||
if (!data.enabled) return;
|
||||
if (!velocityCtrl) return;
|
||||
|
||||
this.updateVelocityCtrl();
|
||||
const velocityCtrl = this.velocityCtrl;
|
||||
const velocity = this.velocity;
|
||||
|
||||
if (!velocityCtrl) return;
|
||||
|
||||
// Update velocity. If FPS is too low, reset.
|
||||
if (dt / 1000 > MAX_DELTA) {
|
||||
velocity.set(0, 0, 0);
|
||||
} else {
|
||||
this.updateVelocity(dt);
|
||||
}
|
||||
|
||||
if (data.constrainToNavMesh
|
||||
&& velocityCtrl.isNavMeshConstrained !== false) {
|
||||
|
||||
if (velocity.lengthSq() < EPS) return;
|
||||
|
||||
start.copy(el.object3D.position);
|
||||
end
|
||||
.copy(velocity)
|
||||
.multiplyScalar(dt / 1000)
|
||||
.add(start);
|
||||
|
||||
const nav = el.sceneEl.systems.nav;
|
||||
this.navGroup = this.navGroup === null ? nav.getGroup(start) : this.navGroup;
|
||||
this.navNode = this.navNode || nav.getNode(start, this.navGroup);
|
||||
this.navNode = nav.clampStep(start, end, this.navGroup, this.navNode, clampedEnd);
|
||||
el.object3D.position.copy(clampedEnd);
|
||||
} else if (el.hasAttribute('velocity')) {
|
||||
el.setAttribute('velocity', velocity);
|
||||
} else {
|
||||
el.object3D.position.x += velocity.x * dt / 1000;
|
||||
el.object3D.position.y += velocity.y * dt / 1000;
|
||||
el.object3D.position.z += velocity.z * dt / 1000;
|
||||
}
|
||||
|
||||
};
|
||||
}()),
|
||||
|
||||
/*******************************************************************
|
||||
* Movement
|
||||
*/
|
||||
|
||||
updateVelocityCtrl: function () {
|
||||
const data = this.data;
|
||||
if (data.enabled) {
|
||||
for (let i = 0, l = data.controls.length; i < l; i++) {
|
||||
const control = this.el.components[data.controls[i] + COMPONENT_SUFFIX];
|
||||
if (control && control.isVelocityActive()) {
|
||||
this.velocityCtrl = control;
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.velocityCtrl = null;
|
||||
}
|
||||
},
|
||||
|
||||
updateVelocity: (function () {
|
||||
const vector2 = new THREE.Vector2();
|
||||
const quaternion = new THREE.Quaternion();
|
||||
|
||||
return function (dt) {
|
||||
let dVelocity;
|
||||
const el = this.el;
|
||||
const control = this.velocityCtrl;
|
||||
const velocity = this.velocity;
|
||||
const data = this.data;
|
||||
|
||||
if (control) {
|
||||
if (control.getVelocityDelta) {
|
||||
dVelocity = control.getVelocityDelta(dt);
|
||||
} else if (control.getVelocity) {
|
||||
velocity.copy(control.getVelocity());
|
||||
return;
|
||||
} else if (control.getPositionDelta) {
|
||||
velocity.copy(control.getPositionDelta(dt).multiplyScalar(1000 / dt));
|
||||
return;
|
||||
// Update velocity. If FPS is too low, reset.
|
||||
if (dt / 1000 > MAX_DELTA) {
|
||||
velocity.set(0, 0, 0);
|
||||
} else {
|
||||
throw new Error('Incompatible movement controls: ', control);
|
||||
this.updateVelocity(dt);
|
||||
}
|
||||
}
|
||||
|
||||
if (el.hasAttribute('velocity') && !data.constrainToNavMesh) {
|
||||
velocity.copy(this.el.getAttribute('velocity'));
|
||||
}
|
||||
if (data.constrainToNavMesh
|
||||
&& velocityCtrl.isNavMeshConstrained !== false) {
|
||||
|
||||
if (dVelocity && data.enabled) {
|
||||
const cameraEl = data.camera;
|
||||
if (velocity.lengthSq() < EPS) return;
|
||||
|
||||
// Rotate to heading
|
||||
quaternion.copy(cameraEl.object3D.quaternion);
|
||||
quaternion.premultiply(el.object3D.quaternion);
|
||||
dVelocity.applyQuaternion(quaternion);
|
||||
start.copy(el.object3D.position);
|
||||
end
|
||||
.copy(velocity)
|
||||
.multiplyScalar(dt / 1000)
|
||||
.add(start);
|
||||
|
||||
const factor = dVelocity.length();
|
||||
if (data.fly) {
|
||||
velocity.copy(dVelocity);
|
||||
velocity.multiplyScalar(this.data.speed * 16.66667);
|
||||
const nav = el.sceneEl.systems.nav;
|
||||
this.navGroup = this.navGroup === null ? nav.getGroup(start) : this.navGroup;
|
||||
this.navNode = this.navNode || nav.getNode(start, this.navGroup);
|
||||
this.navNode = nav.clampStep(start, end, this.navGroup, this.navNode, clampedEnd);
|
||||
el.object3D.position.copy(clampedEnd);
|
||||
} else if (el.hasAttribute('velocity')) {
|
||||
el.setAttribute('velocity', velocity);
|
||||
} else {
|
||||
vector2.set(dVelocity.x, dVelocity.z);
|
||||
vector2.setLength(factor * this.data.speed * 16.66667);
|
||||
velocity.x = vector2.x;
|
||||
velocity.y = 0;
|
||||
velocity.z = vector2.y;
|
||||
el.object3D.position.x += velocity.x * dt / 1000;
|
||||
el.object3D.position.y += velocity.y * dt / 1000;
|
||||
el.object3D.position.z += velocity.z * dt / 1000;
|
||||
}
|
||||
if (velocity.x !== 0 || velocity.y !== 0 || velocity.z !== 0) {
|
||||
this.eventDetail.velocity = velocity;
|
||||
this.el.emit(MOVED, this.eventDetail);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}())
|
||||
});
|
||||
};
|
||||
}()),
|
||||
|
||||
/*******************************************************************
|
||||
* Movement
|
||||
*/
|
||||
|
||||
updateVelocityCtrl: function () {
|
||||
const data = this.data;
|
||||
if (data.enabled) {
|
||||
for (let i = 0, l = data.controls.length; i < l; i++) {
|
||||
const control = this.el.components[data.controls[i] + COMPONENT_SUFFIX];
|
||||
if (control && control.isVelocityActive()) {
|
||||
this.velocityCtrl = control;
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.velocityCtrl = null;
|
||||
}
|
||||
},
|
||||
|
||||
updateVelocity: (function () {
|
||||
const vector2 = new THREE.Vector2();
|
||||
const quaternion = new THREE.Quaternion();
|
||||
|
||||
return function (dt) {
|
||||
let dVelocity;
|
||||
const el = this.el;
|
||||
const control = this.velocityCtrl;
|
||||
const velocity = this.velocity;
|
||||
const data = this.data;
|
||||
|
||||
if (control) {
|
||||
if (control.getVelocityDelta) {
|
||||
dVelocity = control.getVelocityDelta(dt);
|
||||
} else if (control.getVelocity) {
|
||||
velocity.copy(control.getVelocity());
|
||||
return;
|
||||
} else if (control.getPositionDelta) {
|
||||
velocity.copy(control.getPositionDelta(dt).multiplyScalar(1000 / dt));
|
||||
return;
|
||||
} else {
|
||||
throw new Error('Incompatible movement controls: ', control);
|
||||
}
|
||||
}
|
||||
|
||||
if (el.hasAttribute('velocity') && !data.constrainToNavMesh) {
|
||||
velocity.copy(this.el.getAttribute('velocity'));
|
||||
}
|
||||
|
||||
if (dVelocity && data.enabled) {
|
||||
const cameraEl = data.camera;
|
||||
|
||||
// Rotate to heading
|
||||
quaternion.copy(cameraEl.object3D.quaternion);
|
||||
quaternion.premultiply(el.object3D.quaternion);
|
||||
dVelocity.applyQuaternion(quaternion);
|
||||
|
||||
const factor = dVelocity.length();
|
||||
if (data.fly) {
|
||||
velocity.copy(dVelocity);
|
||||
velocity.multiplyScalar(this.data.speed * 16.66667);
|
||||
} else {
|
||||
vector2.set(dVelocity.x, dVelocity.z);
|
||||
vector2.setLength(factor * this.data.speed * 16.66667);
|
||||
velocity.x = vector2.x;
|
||||
velocity.y = 0;
|
||||
velocity.z = vector2.y;
|
||||
}
|
||||
if (velocity.x !== 0 || velocity.y !== 0 || velocity.z !== 0) {
|
||||
this.eventDetail.velocity = velocity;
|
||||
this.el.emit(MOVED, this.eventDetail);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}())
|
||||
});
|
||||
}
|
||||
AFRAME.components['hand-tracking-controls'].Component.prototype.onModelLoaded = function(onModelLoaded){
|
||||
return function(e){
|
||||
onModelLoaded.apply(this);
|
||||
|
@ -5325,94 +5366,98 @@ AFRAME.components['look-controls'].Component.prototype.updateOrientation = funct
|
|||
/**
|
||||
* Touch-to-move-forward controls for mobile.
|
||||
*/
|
||||
AFRAME.registerComponent('touch-controls', {
|
||||
schema: {
|
||||
enabled: { default: true },
|
||||
reverseEnabled: { default: true }
|
||||
},
|
||||
|
||||
init: function () {
|
||||
this.dVelocity = new THREE.Vector3();
|
||||
this.bindMethods();
|
||||
this.direction = 0;
|
||||
},
|
||||
if( !AFRAME.components['touch-controls'] ){
|
||||
|
||||
play: function () {
|
||||
this.addEventListeners();
|
||||
},
|
||||
AFRAME.registerComponent('touch-controls', {
|
||||
schema: {
|
||||
enabled: { default: true },
|
||||
reverseEnabled: { default: true }
|
||||
},
|
||||
|
||||
pause: function () {
|
||||
this.removeEventListeners();
|
||||
this.dVelocity.set(0, 0, 0);
|
||||
},
|
||||
init: function () {
|
||||
this.dVelocity = new THREE.Vector3();
|
||||
this.bindMethods();
|
||||
this.direction = 0;
|
||||
},
|
||||
|
||||
remove: function () {
|
||||
this.pause();
|
||||
},
|
||||
play: function () {
|
||||
this.addEventListeners();
|
||||
},
|
||||
|
||||
addEventListeners: function () {
|
||||
const sceneEl = this.el.sceneEl;
|
||||
const canvasEl = sceneEl.canvas;
|
||||
pause: function () {
|
||||
this.removeEventListeners();
|
||||
this.dVelocity.set(0, 0, 0);
|
||||
},
|
||||
|
||||
if (!canvasEl) {
|
||||
sceneEl.addEventListener('render-target-loaded', this.addEventListeners.bind(this));
|
||||
return;
|
||||
remove: function () {
|
||||
this.pause();
|
||||
},
|
||||
|
||||
addEventListeners: function () {
|
||||
const sceneEl = this.el.sceneEl;
|
||||
const canvasEl = sceneEl.canvas;
|
||||
|
||||
if (!canvasEl) {
|
||||
sceneEl.addEventListener('render-target-loaded', this.addEventListeners.bind(this));
|
||||
return;
|
||||
}
|
||||
|
||||
canvasEl.addEventListener('touchstart', this.onTouchStart);
|
||||
canvasEl.addEventListener('touchend', this.onTouchEnd);
|
||||
const vrModeUI = sceneEl.getAttribute('vr-mode-ui');
|
||||
if (vrModeUI && vrModeUI.cardboardModeEnabled) {
|
||||
sceneEl.addEventListener('enter-vr', this.onEnterVR);
|
||||
}
|
||||
},
|
||||
|
||||
removeEventListeners: function () {
|
||||
const canvasEl = this.el.sceneEl && this.el.sceneEl.canvas;
|
||||
if (!canvasEl) { return; }
|
||||
|
||||
canvasEl.removeEventListener('touchstart', this.onTouchStart);
|
||||
canvasEl.removeEventListener('touchend', this.onTouchEnd);
|
||||
this.el.sceneEl.removeEventListener('enter-vr', this.onEnterVR)
|
||||
},
|
||||
|
||||
isVelocityActive: function () {
|
||||
return this.data.enabled && !!this.direction;
|
||||
},
|
||||
|
||||
getVelocityDelta: function () {
|
||||
this.dVelocity.z = this.direction;
|
||||
return this.dVelocity.clone();
|
||||
},
|
||||
|
||||
bindMethods: function () {
|
||||
this.onTouchStart = this.onTouchStart.bind(this);
|
||||
this.onTouchEnd = this.onTouchEnd.bind(this);
|
||||
this.onEnterVR = this.onEnterVR.bind(this);
|
||||
},
|
||||
|
||||
onTouchStart: function (e) {
|
||||
this.direction = 0;
|
||||
if (this.data.reverseEnabled && e.touches ){
|
||||
if( e.touches.length === 3) this.direction = 1;
|
||||
if( e.touches.length === 2) this.direction = -1;
|
||||
}
|
||||
//e.preventDefault();
|
||||
},
|
||||
|
||||
onTouchEnd: function (e) {
|
||||
this.direction = 0;
|
||||
//e.preventDefault();
|
||||
},
|
||||
|
||||
onEnterVR: function () {
|
||||
// This is to make the Cardboard button on Chrome Android working
|
||||
//const xrSession = this.el.sceneEl.xrSession;
|
||||
//if (!xrSession) { return; }
|
||||
//xrSession.addEventListener('selectstart', this.onTouchStart);
|
||||
//xrSession.addEventListener('selectend', this.onTouchEnd);
|
||||
}
|
||||
|
||||
canvasEl.addEventListener('touchstart', this.onTouchStart);
|
||||
canvasEl.addEventListener('touchend', this.onTouchEnd);
|
||||
const vrModeUI = sceneEl.getAttribute('vr-mode-ui');
|
||||
if (vrModeUI && vrModeUI.cardboardModeEnabled) {
|
||||
sceneEl.addEventListener('enter-vr', this.onEnterVR);
|
||||
}
|
||||
},
|
||||
|
||||
removeEventListeners: function () {
|
||||
const canvasEl = this.el.sceneEl && this.el.sceneEl.canvas;
|
||||
if (!canvasEl) { return; }
|
||||
|
||||
canvasEl.removeEventListener('touchstart', this.onTouchStart);
|
||||
canvasEl.removeEventListener('touchend', this.onTouchEnd);
|
||||
this.el.sceneEl.removeEventListener('enter-vr', this.onEnterVR)
|
||||
},
|
||||
|
||||
isVelocityActive: function () {
|
||||
return this.data.enabled && !!this.direction;
|
||||
},
|
||||
|
||||
getVelocityDelta: function () {
|
||||
this.dVelocity.z = this.direction;
|
||||
return this.dVelocity.clone();
|
||||
},
|
||||
|
||||
bindMethods: function () {
|
||||
this.onTouchStart = this.onTouchStart.bind(this);
|
||||
this.onTouchEnd = this.onTouchEnd.bind(this);
|
||||
this.onEnterVR = this.onEnterVR.bind(this);
|
||||
},
|
||||
|
||||
onTouchStart: function (e) {
|
||||
this.direction = 0;
|
||||
if (this.data.reverseEnabled && e.touches ){
|
||||
if( e.touches.length === 3) this.direction = 1;
|
||||
if( e.touches.length === 2) this.direction = -1;
|
||||
}
|
||||
//e.preventDefault();
|
||||
},
|
||||
|
||||
onTouchEnd: function (e) {
|
||||
this.direction = 0;
|
||||
//e.preventDefault();
|
||||
},
|
||||
|
||||
onEnterVR: function () {
|
||||
// This is to make the Cardboard button on Chrome Android working
|
||||
//const xrSession = this.el.sceneEl.xrSession;
|
||||
//if (!xrSession) { return; }
|
||||
//xrSession.addEventListener('selectstart', this.onTouchStart);
|
||||
//xrSession.addEventListener('selectend', this.onTouchEnd);
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
window.AFRAME.registerComponent('xrf-button', {
|
||||
schema: {
|
||||
label: {
|
||||
|
|
|
@ -1,3 +1,43 @@
|
|||
/*
|
||||
* v0.5.1 generated at Mon Dec 9 15:41:10 UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
/*
|
||||
* v0.5.1 generated at Mon Dec 9 15:39:00 UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
/*
|
||||
* v0.5.1 generated at Mon Dec 9 15:38:50 UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
/*
|
||||
* v0.5.1 generated at Mon Dec 9 15:38:27 UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
/*
|
||||
* v0.5.1 generated at Mon Dec 9 15:37:05 UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
/*
|
||||
* v0.5.1 generated at Mon Dec 9 15:36:14 UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
/*
|
||||
* v0.5.1 generated at Mon Dec 9 15:35:39 UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
/*
|
||||
* v0.5.1 generated at Mon Dec 9 03:32:13 PM UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
/*
|
||||
* v0.5.1 generated at Mon Oct 14 11:39:48 AM CEST 2024
|
||||
* https://xrfragment.org
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* v0.5.1 generated at Mon Oct 14 11:39:48 AM CEST 2024
|
||||
* v0.5.1 generated at Mon Dec 9 15:41:10 UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* v0.5.1 generated at Mon Oct 14 11:39:48 AM CEST 2024
|
||||
* v0.5.1 generated at Mon Dec 9 15:41:10 UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* v0.5.1 generated at Mon Oct 14 11:39:48 AM CEST 2024
|
||||
* v0.5.1 generated at Mon Dec 9 15:41:10 UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* v0.5.1 generated at Mon Oct 14 11:39:48 AM CEST 2024
|
||||
* v0.5.1 generated at Mon Dec 9 15:41:10 UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* v0.5.1 generated at Mon Oct 14 11:39:48 AM CEST 2024
|
||||
* v0.5.1 generated at Mon Dec 9 15:41:10 UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* v0.5.1 generated at Mon Oct 14 11:39:48 AM CEST 2024
|
||||
* v0.5.1 generated at Mon Dec 9 15:41:10 UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
|
|
|
@ -1,3 +1,43 @@
|
|||
/*
|
||||
* v0.5.1 generated at Mon Dec 9 15:41:10 UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
/*
|
||||
* v0.5.1 generated at Mon Dec 9 15:39:00 UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
/*
|
||||
* v0.5.1 generated at Mon Dec 9 15:38:50 UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
/*
|
||||
* v0.5.1 generated at Mon Dec 9 15:38:27 UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
/*
|
||||
* v0.5.1 generated at Mon Dec 9 15:37:05 UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
/*
|
||||
* v0.5.1 generated at Mon Dec 9 15:36:14 UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
/*
|
||||
* v0.5.1 generated at Mon Dec 9 15:35:39 UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
/*
|
||||
* v0.5.1 generated at Mon Dec 9 03:32:13 PM UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
/*
|
||||
* v0.5.1 generated at Mon Oct 14 11:39:48 AM CEST 2024
|
||||
* https://xrfragment.org
|
||||
|
@ -3064,10 +3104,6 @@ xrf.frag.pos = function(v, opts){
|
|||
if( pos.x == undefined ){
|
||||
let obj = scene.getObjectByName(v.string)
|
||||
if( !obj ) return console.warn("#pos="+v.string+" not found")
|
||||
//let worldPos = new THREE.Vector3()
|
||||
//obj.getWorldPosition(worldPos)
|
||||
//camera.position.copy(worldPos)
|
||||
//obj.attach(camera) // instead of add() [keeps camera animations intact]
|
||||
obj.add(camera)
|
||||
camera.position.set(0,0,0)
|
||||
let c = camera.rotation
|
||||
|
|
|
@ -1,3 +1,43 @@
|
|||
/*
|
||||
* v0.5.1 generated at Mon Dec 9 15:41:10 UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
/*
|
||||
* v0.5.1 generated at Mon Dec 9 15:39:00 UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
/*
|
||||
* v0.5.1 generated at Mon Dec 9 15:38:50 UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
/*
|
||||
* v0.5.1 generated at Mon Dec 9 15:38:27 UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
/*
|
||||
* v0.5.1 generated at Mon Dec 9 15:37:05 UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
/*
|
||||
* v0.5.1 generated at Mon Dec 9 15:36:14 UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
/*
|
||||
* v0.5.1 generated at Mon Dec 9 15:35:39 UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
/*
|
||||
* v0.5.1 generated at Mon Dec 9 03:32:13 PM UTC 2024
|
||||
* https://xrfragment.org
|
||||
* SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
*/
|
||||
/*
|
||||
* v0.5.1 generated at Mon Oct 14 11:39:48 AM CEST 2024
|
||||
* https://xrfragment.org
|
||||
|
@ -3064,10 +3104,6 @@ xrf.frag.pos = function(v, opts){
|
|||
if( pos.x == undefined ){
|
||||
let obj = scene.getObjectByName(v.string)
|
||||
if( !obj ) return console.warn("#pos="+v.string+" not found")
|
||||
//let worldPos = new THREE.Vector3()
|
||||
//obj.getWorldPosition(worldPos)
|
||||
//camera.position.copy(worldPos)
|
||||
//obj.attach(camera) // instead of add() [keeps camera animations intact]
|
||||
obj.add(camera)
|
||||
camera.position.set(0,0,0)
|
||||
let c = camera.rotation
|
||||
|
|
|
@ -5,6 +5,8 @@ window.AFRAME.registerComponent('xrf', {
|
|||
},
|
||||
init: async function () {
|
||||
|
||||
this.data = Object.values(this.attrValue)[0]
|
||||
|
||||
// override this.data when URL has passed (`://....com/?https://foo.com/index.glb` e.g.)
|
||||
if( typeof this.data == "string" ){
|
||||
let searchIsUri = document.location.search &&
|
||||
|
|
|
@ -9,213 +9,216 @@ const MAX_DELTA = 0.2; // ms
|
|||
const EPS = 10e-6;
|
||||
const MOVED = 'moved';
|
||||
|
||||
AFRAME.registerComponent('movement-controls', {
|
||||
if( !AFRAME.components['movement-controls'] ){
|
||||
|
||||
/*******************************************************************
|
||||
* Schema
|
||||
*/
|
||||
AFRAME.registerComponent('movement-controls', {
|
||||
|
||||
dependencies: ['rotation'],
|
||||
/*******************************************************************
|
||||
* Schema
|
||||
*/
|
||||
|
||||
schema: {
|
||||
enabled: { default: true },
|
||||
controls: { default: ['gamepad', 'trackpad', 'keyboard', 'touch'] },
|
||||
speed: { default: 0.3, min: 0 },
|
||||
fly: { default: false },
|
||||
constrainToNavMesh: { default: false },
|
||||
camera: { default: '[movement-controls] [camera]', type: 'selector' }
|
||||
},
|
||||
dependencies: ['rotation'],
|
||||
|
||||
/*******************************************************************
|
||||
* Lifecycle
|
||||
*/
|
||||
schema: {
|
||||
enabled: { default: true },
|
||||
controls: { default: ['gamepad', 'trackpad', 'keyboard', 'touch'] },
|
||||
speed: { default: 0.3, min: 0 },
|
||||
fly: { default: false },
|
||||
constrainToNavMesh: { default: false },
|
||||
camera: { default: '[movement-controls] [camera]', type: 'selector' }
|
||||
},
|
||||
|
||||
init: function () {
|
||||
const el = this.el;
|
||||
if (!this.data.camera) {
|
||||
this.data.camera = el.querySelector('[camera]');
|
||||
}
|
||||
this.velocityCtrl = null;
|
||||
/*******************************************************************
|
||||
* Lifecycle
|
||||
*/
|
||||
|
||||
this.velocity = new THREE.Vector3();
|
||||
this.heading = new THREE.Quaternion();
|
||||
this.eventDetail = {};
|
||||
init: function () {
|
||||
const el = this.el;
|
||||
if (!this.data.camera) {
|
||||
this.data.camera = el.querySelector('[camera]');
|
||||
}
|
||||
this.velocityCtrl = null;
|
||||
|
||||
// Navigation
|
||||
this.navGroup = null;
|
||||
this.navNode = null;
|
||||
this.velocity = new THREE.Vector3();
|
||||
this.heading = new THREE.Quaternion();
|
||||
this.eventDetail = {};
|
||||
|
||||
if (el.sceneEl.hasLoaded) {
|
||||
this.injectControls();
|
||||
} else {
|
||||
el.sceneEl.addEventListener('loaded', this.injectControls.bind(this));
|
||||
}
|
||||
},
|
||||
// Navigation
|
||||
this.navGroup = null;
|
||||
this.navNode = null;
|
||||
|
||||
if (el.sceneEl.hasLoaded) {
|
||||
this.injectControls();
|
||||
} else {
|
||||
el.sceneEl.addEventListener('loaded', this.injectControls.bind(this));
|
||||
}
|
||||
},
|
||||
|
||||
update: function (prevData) {
|
||||
const el = this.el;
|
||||
const data = this.data;
|
||||
const nav = el.sceneEl.systems.nav;
|
||||
if (el.sceneEl.hasLoaded) {
|
||||
this.injectControls();
|
||||
}
|
||||
if (nav && data.constrainToNavMesh !== prevData.constrainToNavMesh) {
|
||||
data.constrainToNavMesh
|
||||
? nav.addAgent(this)
|
||||
: nav.removeAgent(this);
|
||||
}
|
||||
if (data.enabled !== prevData.enabled) {
|
||||
// Propagate the enabled change to all controls
|
||||
for (let i = 0; i < data.controls.length; i++) {
|
||||
const name = data.controls[i] + COMPONENT_SUFFIX;
|
||||
this.el.setAttribute(name, { enabled: this.data.enabled });
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
injectControls: function () {
|
||||
const data = this.data;
|
||||
|
||||
update: function (prevData) {
|
||||
const el = this.el;
|
||||
const data = this.data;
|
||||
const nav = el.sceneEl.systems.nav;
|
||||
if (el.sceneEl.hasLoaded) {
|
||||
this.injectControls();
|
||||
}
|
||||
if (nav && data.constrainToNavMesh !== prevData.constrainToNavMesh) {
|
||||
data.constrainToNavMesh
|
||||
? nav.addAgent(this)
|
||||
: nav.removeAgent(this);
|
||||
}
|
||||
if (data.enabled !== prevData.enabled) {
|
||||
// Propagate the enabled change to all controls
|
||||
for (let i = 0; i < data.controls.length; i++) {
|
||||
const name = data.controls[i] + COMPONENT_SUFFIX;
|
||||
this.el.setAttribute(name, { enabled: this.data.enabled });
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
injectControls: function () {
|
||||
const data = this.data;
|
||||
updateNavLocation: function () {
|
||||
this.navGroup = null;
|
||||
this.navNode = null;
|
||||
},
|
||||
|
||||
for (let i = 0; i < data.controls.length; i++) {
|
||||
const name = data.controls[i] + COMPONENT_SUFFIX;
|
||||
this.el.setAttribute(name, { enabled: this.data.enabled });
|
||||
}
|
||||
},
|
||||
/*******************************************************************
|
||||
* Tick
|
||||
*/
|
||||
|
||||
updateNavLocation: function () {
|
||||
this.navGroup = null;
|
||||
this.navNode = null;
|
||||
},
|
||||
tick: (function () {
|
||||
const start = new THREE.Vector3();
|
||||
const end = new THREE.Vector3();
|
||||
const clampedEnd = new THREE.Vector3();
|
||||
|
||||
/*******************************************************************
|
||||
* Tick
|
||||
*/
|
||||
return function (t, dt) {
|
||||
if (!dt) return;
|
||||
|
||||
tick: (function () {
|
||||
const start = new THREE.Vector3();
|
||||
const end = new THREE.Vector3();
|
||||
const clampedEnd = new THREE.Vector3();
|
||||
const el = this.el;
|
||||
const data = this.data;
|
||||
|
||||
return function (t, dt) {
|
||||
if (!dt) return;
|
||||
if (!data.enabled) return;
|
||||
|
||||
const el = this.el;
|
||||
const data = this.data;
|
||||
this.updateVelocityCtrl();
|
||||
const velocityCtrl = this.velocityCtrl;
|
||||
const velocity = this.velocity;
|
||||
|
||||
if (!data.enabled) return;
|
||||
if (!velocityCtrl) return;
|
||||
|
||||
this.updateVelocityCtrl();
|
||||
const velocityCtrl = this.velocityCtrl;
|
||||
const velocity = this.velocity;
|
||||
|
||||
if (!velocityCtrl) return;
|
||||
|
||||
// Update velocity. If FPS is too low, reset.
|
||||
if (dt / 1000 > MAX_DELTA) {
|
||||
velocity.set(0, 0, 0);
|
||||
} else {
|
||||
this.updateVelocity(dt);
|
||||
}
|
||||
|
||||
if (data.constrainToNavMesh
|
||||
&& velocityCtrl.isNavMeshConstrained !== false) {
|
||||
|
||||
if (velocity.lengthSq() < EPS) return;
|
||||
|
||||
start.copy(el.object3D.position);
|
||||
end
|
||||
.copy(velocity)
|
||||
.multiplyScalar(dt / 1000)
|
||||
.add(start);
|
||||
|
||||
const nav = el.sceneEl.systems.nav;
|
||||
this.navGroup = this.navGroup === null ? nav.getGroup(start) : this.navGroup;
|
||||
this.navNode = this.navNode || nav.getNode(start, this.navGroup);
|
||||
this.navNode = nav.clampStep(start, end, this.navGroup, this.navNode, clampedEnd);
|
||||
el.object3D.position.copy(clampedEnd);
|
||||
} else if (el.hasAttribute('velocity')) {
|
||||
el.setAttribute('velocity', velocity);
|
||||
} else {
|
||||
el.object3D.position.x += velocity.x * dt / 1000;
|
||||
el.object3D.position.y += velocity.y * dt / 1000;
|
||||
el.object3D.position.z += velocity.z * dt / 1000;
|
||||
}
|
||||
|
||||
};
|
||||
}()),
|
||||
|
||||
/*******************************************************************
|
||||
* Movement
|
||||
*/
|
||||
|
||||
updateVelocityCtrl: function () {
|
||||
const data = this.data;
|
||||
if (data.enabled) {
|
||||
for (let i = 0, l = data.controls.length; i < l; i++) {
|
||||
const control = this.el.components[data.controls[i] + COMPONENT_SUFFIX];
|
||||
if (control && control.isVelocityActive()) {
|
||||
this.velocityCtrl = control;
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.velocityCtrl = null;
|
||||
}
|
||||
},
|
||||
|
||||
updateVelocity: (function () {
|
||||
const vector2 = new THREE.Vector2();
|
||||
const quaternion = new THREE.Quaternion();
|
||||
|
||||
return function (dt) {
|
||||
let dVelocity;
|
||||
const el = this.el;
|
||||
const control = this.velocityCtrl;
|
||||
const velocity = this.velocity;
|
||||
const data = this.data;
|
||||
|
||||
if (control) {
|
||||
if (control.getVelocityDelta) {
|
||||
dVelocity = control.getVelocityDelta(dt);
|
||||
} else if (control.getVelocity) {
|
||||
velocity.copy(control.getVelocity());
|
||||
return;
|
||||
} else if (control.getPositionDelta) {
|
||||
velocity.copy(control.getPositionDelta(dt).multiplyScalar(1000 / dt));
|
||||
return;
|
||||
// Update velocity. If FPS is too low, reset.
|
||||
if (dt / 1000 > MAX_DELTA) {
|
||||
velocity.set(0, 0, 0);
|
||||
} else {
|
||||
throw new Error('Incompatible movement controls: ', control);
|
||||
this.updateVelocity(dt);
|
||||
}
|
||||
}
|
||||
|
||||
if (el.hasAttribute('velocity') && !data.constrainToNavMesh) {
|
||||
velocity.copy(this.el.getAttribute('velocity'));
|
||||
}
|
||||
if (data.constrainToNavMesh
|
||||
&& velocityCtrl.isNavMeshConstrained !== false) {
|
||||
|
||||
if (dVelocity && data.enabled) {
|
||||
const cameraEl = data.camera;
|
||||
if (velocity.lengthSq() < EPS) return;
|
||||
|
||||
// Rotate to heading
|
||||
quaternion.copy(cameraEl.object3D.quaternion);
|
||||
quaternion.premultiply(el.object3D.quaternion);
|
||||
dVelocity.applyQuaternion(quaternion);
|
||||
start.copy(el.object3D.position);
|
||||
end
|
||||
.copy(velocity)
|
||||
.multiplyScalar(dt / 1000)
|
||||
.add(start);
|
||||
|
||||
const factor = dVelocity.length();
|
||||
if (data.fly) {
|
||||
velocity.copy(dVelocity);
|
||||
velocity.multiplyScalar(this.data.speed * 16.66667);
|
||||
const nav = el.sceneEl.systems.nav;
|
||||
this.navGroup = this.navGroup === null ? nav.getGroup(start) : this.navGroup;
|
||||
this.navNode = this.navNode || nav.getNode(start, this.navGroup);
|
||||
this.navNode = nav.clampStep(start, end, this.navGroup, this.navNode, clampedEnd);
|
||||
el.object3D.position.copy(clampedEnd);
|
||||
} else if (el.hasAttribute('velocity')) {
|
||||
el.setAttribute('velocity', velocity);
|
||||
} else {
|
||||
vector2.set(dVelocity.x, dVelocity.z);
|
||||
vector2.setLength(factor * this.data.speed * 16.66667);
|
||||
velocity.x = vector2.x;
|
||||
velocity.y = 0;
|
||||
velocity.z = vector2.y;
|
||||
el.object3D.position.x += velocity.x * dt / 1000;
|
||||
el.object3D.position.y += velocity.y * dt / 1000;
|
||||
el.object3D.position.z += velocity.z * dt / 1000;
|
||||
}
|
||||
if (velocity.x !== 0 || velocity.y !== 0 || velocity.z !== 0) {
|
||||
this.eventDetail.velocity = velocity;
|
||||
this.el.emit(MOVED, this.eventDetail);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}())
|
||||
});
|
||||
};
|
||||
}()),
|
||||
|
||||
/*******************************************************************
|
||||
* Movement
|
||||
*/
|
||||
|
||||
updateVelocityCtrl: function () {
|
||||
const data = this.data;
|
||||
if (data.enabled) {
|
||||
for (let i = 0, l = data.controls.length; i < l; i++) {
|
||||
const control = this.el.components[data.controls[i] + COMPONENT_SUFFIX];
|
||||
if (control && control.isVelocityActive()) {
|
||||
this.velocityCtrl = control;
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.velocityCtrl = null;
|
||||
}
|
||||
},
|
||||
|
||||
updateVelocity: (function () {
|
||||
const vector2 = new THREE.Vector2();
|
||||
const quaternion = new THREE.Quaternion();
|
||||
|
||||
return function (dt) {
|
||||
let dVelocity;
|
||||
const el = this.el;
|
||||
const control = this.velocityCtrl;
|
||||
const velocity = this.velocity;
|
||||
const data = this.data;
|
||||
|
||||
if (control) {
|
||||
if (control.getVelocityDelta) {
|
||||
dVelocity = control.getVelocityDelta(dt);
|
||||
} else if (control.getVelocity) {
|
||||
velocity.copy(control.getVelocity());
|
||||
return;
|
||||
} else if (control.getPositionDelta) {
|
||||
velocity.copy(control.getPositionDelta(dt).multiplyScalar(1000 / dt));
|
||||
return;
|
||||
} else {
|
||||
throw new Error('Incompatible movement controls: ', control);
|
||||
}
|
||||
}
|
||||
|
||||
if (el.hasAttribute('velocity') && !data.constrainToNavMesh) {
|
||||
velocity.copy(this.el.getAttribute('velocity'));
|
||||
}
|
||||
|
||||
if (dVelocity && data.enabled) {
|
||||
const cameraEl = data.camera;
|
||||
|
||||
// Rotate to heading
|
||||
quaternion.copy(cameraEl.object3D.quaternion);
|
||||
quaternion.premultiply(el.object3D.quaternion);
|
||||
dVelocity.applyQuaternion(quaternion);
|
||||
|
||||
const factor = dVelocity.length();
|
||||
if (data.fly) {
|
||||
velocity.copy(dVelocity);
|
||||
velocity.multiplyScalar(this.data.speed * 16.66667);
|
||||
} else {
|
||||
vector2.set(dVelocity.x, dVelocity.z);
|
||||
vector2.setLength(factor * this.data.speed * 16.66667);
|
||||
velocity.x = vector2.x;
|
||||
velocity.y = 0;
|
||||
velocity.z = vector2.y;
|
||||
}
|
||||
if (velocity.x !== 0 || velocity.y !== 0 || velocity.z !== 0) {
|
||||
this.eventDetail.velocity = velocity;
|
||||
this.el.emit(MOVED, this.eventDetail);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
}())
|
||||
});
|
||||
}
|
||||
|
|
|
@ -1,91 +1,95 @@
|
|||
/**
|
||||
* Touch-to-move-forward controls for mobile.
|
||||
*/
|
||||
AFRAME.registerComponent('touch-controls', {
|
||||
schema: {
|
||||
enabled: { default: true },
|
||||
reverseEnabled: { default: true }
|
||||
},
|
||||
|
||||
init: function () {
|
||||
this.dVelocity = new THREE.Vector3();
|
||||
this.bindMethods();
|
||||
this.direction = 0;
|
||||
},
|
||||
if( !AFRAME.components['touch-controls'] ){
|
||||
|
||||
play: function () {
|
||||
this.addEventListeners();
|
||||
},
|
||||
AFRAME.registerComponent('touch-controls', {
|
||||
schema: {
|
||||
enabled: { default: true },
|
||||
reverseEnabled: { default: true }
|
||||
},
|
||||
|
||||
pause: function () {
|
||||
this.removeEventListeners();
|
||||
this.dVelocity.set(0, 0, 0);
|
||||
},
|
||||
init: function () {
|
||||
this.dVelocity = new THREE.Vector3();
|
||||
this.bindMethods();
|
||||
this.direction = 0;
|
||||
},
|
||||
|
||||
remove: function () {
|
||||
this.pause();
|
||||
},
|
||||
play: function () {
|
||||
this.addEventListeners();
|
||||
},
|
||||
|
||||
addEventListeners: function () {
|
||||
const sceneEl = this.el.sceneEl;
|
||||
const canvasEl = sceneEl.canvas;
|
||||
pause: function () {
|
||||
this.removeEventListeners();
|
||||
this.dVelocity.set(0, 0, 0);
|
||||
},
|
||||
|
||||
if (!canvasEl) {
|
||||
sceneEl.addEventListener('render-target-loaded', this.addEventListeners.bind(this));
|
||||
return;
|
||||
remove: function () {
|
||||
this.pause();
|
||||
},
|
||||
|
||||
addEventListeners: function () {
|
||||
const sceneEl = this.el.sceneEl;
|
||||
const canvasEl = sceneEl.canvas;
|
||||
|
||||
if (!canvasEl) {
|
||||
sceneEl.addEventListener('render-target-loaded', this.addEventListeners.bind(this));
|
||||
return;
|
||||
}
|
||||
|
||||
canvasEl.addEventListener('touchstart', this.onTouchStart);
|
||||
canvasEl.addEventListener('touchend', this.onTouchEnd);
|
||||
const vrModeUI = sceneEl.getAttribute('vr-mode-ui');
|
||||
if (vrModeUI && vrModeUI.cardboardModeEnabled) {
|
||||
sceneEl.addEventListener('enter-vr', this.onEnterVR);
|
||||
}
|
||||
},
|
||||
|
||||
removeEventListeners: function () {
|
||||
const canvasEl = this.el.sceneEl && this.el.sceneEl.canvas;
|
||||
if (!canvasEl) { return; }
|
||||
|
||||
canvasEl.removeEventListener('touchstart', this.onTouchStart);
|
||||
canvasEl.removeEventListener('touchend', this.onTouchEnd);
|
||||
this.el.sceneEl.removeEventListener('enter-vr', this.onEnterVR)
|
||||
},
|
||||
|
||||
isVelocityActive: function () {
|
||||
return this.data.enabled && !!this.direction;
|
||||
},
|
||||
|
||||
getVelocityDelta: function () {
|
||||
this.dVelocity.z = this.direction;
|
||||
return this.dVelocity.clone();
|
||||
},
|
||||
|
||||
bindMethods: function () {
|
||||
this.onTouchStart = this.onTouchStart.bind(this);
|
||||
this.onTouchEnd = this.onTouchEnd.bind(this);
|
||||
this.onEnterVR = this.onEnterVR.bind(this);
|
||||
},
|
||||
|
||||
onTouchStart: function (e) {
|
||||
this.direction = 0;
|
||||
if (this.data.reverseEnabled && e.touches ){
|
||||
if( e.touches.length === 3) this.direction = 1;
|
||||
if( e.touches.length === 2) this.direction = -1;
|
||||
}
|
||||
//e.preventDefault();
|
||||
},
|
||||
|
||||
onTouchEnd: function (e) {
|
||||
this.direction = 0;
|
||||
//e.preventDefault();
|
||||
},
|
||||
|
||||
onEnterVR: function () {
|
||||
// This is to make the Cardboard button on Chrome Android working
|
||||
//const xrSession = this.el.sceneEl.xrSession;
|
||||
//if (!xrSession) { return; }
|
||||
//xrSession.addEventListener('selectstart', this.onTouchStart);
|
||||
//xrSession.addEventListener('selectend', this.onTouchEnd);
|
||||
}
|
||||
|
||||
canvasEl.addEventListener('touchstart', this.onTouchStart);
|
||||
canvasEl.addEventListener('touchend', this.onTouchEnd);
|
||||
const vrModeUI = sceneEl.getAttribute('vr-mode-ui');
|
||||
if (vrModeUI && vrModeUI.cardboardModeEnabled) {
|
||||
sceneEl.addEventListener('enter-vr', this.onEnterVR);
|
||||
}
|
||||
},
|
||||
|
||||
removeEventListeners: function () {
|
||||
const canvasEl = this.el.sceneEl && this.el.sceneEl.canvas;
|
||||
if (!canvasEl) { return; }
|
||||
|
||||
canvasEl.removeEventListener('touchstart', this.onTouchStart);
|
||||
canvasEl.removeEventListener('touchend', this.onTouchEnd);
|
||||
this.el.sceneEl.removeEventListener('enter-vr', this.onEnterVR)
|
||||
},
|
||||
|
||||
isVelocityActive: function () {
|
||||
return this.data.enabled && !!this.direction;
|
||||
},
|
||||
|
||||
getVelocityDelta: function () {
|
||||
this.dVelocity.z = this.direction;
|
||||
return this.dVelocity.clone();
|
||||
},
|
||||
|
||||
bindMethods: function () {
|
||||
this.onTouchStart = this.onTouchStart.bind(this);
|
||||
this.onTouchEnd = this.onTouchEnd.bind(this);
|
||||
this.onEnterVR = this.onEnterVR.bind(this);
|
||||
},
|
||||
|
||||
onTouchStart: function (e) {
|
||||
this.direction = 0;
|
||||
if (this.data.reverseEnabled && e.touches ){
|
||||
if( e.touches.length === 3) this.direction = 1;
|
||||
if( e.touches.length === 2) this.direction = -1;
|
||||
}
|
||||
//e.preventDefault();
|
||||
},
|
||||
|
||||
onTouchEnd: function (e) {
|
||||
this.direction = 0;
|
||||
//e.preventDefault();
|
||||
},
|
||||
|
||||
onEnterVR: function () {
|
||||
// This is to make the Cardboard button on Chrome Android working
|
||||
//const xrSession = this.el.sceneEl.xrSession;
|
||||
//if (!xrSession) { return; }
|
||||
//xrSession.addEventListener('selectstart', this.onTouchStart);
|
||||
//xrSession.addEventListener('selectend', this.onTouchEnd);
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue