Skip to content

Commit 99f9f5d

Browse files
committed
Add Vive demo.
1 parent c713daf commit 99f9f5d

File tree

4 files changed

+197
-3
lines changed

4 files changed

+197
-3
lines changed

‎examples/vive/index.html‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
<html>
2+
<head>
3+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
4+
<meta http-equiv="content-type" content="text/html; charset=utf-8">
5+
<meta name="viewport" content="width=device-width,initial-scale=1,shrink-to-fit=no,user-scalable=no,maximum-scale=1">
6+
<title>Examples • Vive</title>
7+
<script src="../aframe-extras.js"></script>
8+
</head>
9+
<body>
10+
<a-scene physics="debug: true">
11+
<!-- Player -->
12+
<a-entity camera look-controls></a-entity>
13+
<a-entity static-body="shape: sphere; sphereRadius: 0.02;" vive-controls="hand: left" sphere-collider="objects: .cube;" grab></a-entity>
14+
<a-entity static-body="shape: sphere; sphereRadius: 0.02;" vive-controls="hand: right" sphere-collider="objects: .cube;" grab></a-entity>
15+
16+
<a-box class="cube" dynamic-body position="0 0.25 -1" width="0.5" height="0.5" depth="0.5" color="red"></a-box>
17+
<a-box class="cube" dynamic-body position="-1 0.25 -1" width="0.5" height="0.5" depth="0.5" color="green"></a-box>
18+
<a-box class="cube" dynamic-body position="1 0.25 -1" width="0.5" height="0.5" depth="0.5" color="blue"></a-box>
19+
20+
<!-- Terrain -->
21+
<a-grid static-body></a-grid>
22+
23+
<!-- Lighting -->
24+
<a-entity light="type: point; color: #f4f4f4; intensity: 0.2; distance: 0" position="8 10 18"></a-entity>
25+
<a-entity light="type: point; color: #f4f4f4; intensity: 0.6; distance: 0" position="-8 10 -18"></a-entity>
26+
<a-entity light="type: ambient; color: #f4f4f4; intensity: 0.4;" position="-8 10 -18"></a-entity>
27+
</a-scene>
28+
</body>
29+
</html>

‎src/misc/grab.js‎

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/**
2+
* Based on aframe/examples/showcase/tracked-controls.
3+
*
4+
* Handles events coming from the hand-controls.
5+
* Determines if the entity is grabbed or released.
6+
* Updates its position to move along the controller.
7+
*/
8+
module.exports = {
9+
init: function () {
10+
this.GRABBED_STATE = 'grabbed';
11+
12+
this.grabbing = false;
13+
this.hitEl = /** @type {AFRAME.Element} */ null;
14+
this.physics = /** @type {AFRAME.System} */ this.el.sceneEl.systems.physics;
15+
this.constraint = /** @type {CANNON.Constraint} */ null;
16+
17+
// Bind event handlers
18+
this.onHit = this.onHit.bind(this);
19+
this.onGripOpen = this.onGripOpen.bind(this);
20+
this.onGripClose = this.onGripClose.bind(this);
21+
},
22+
23+
play: function () {
24+
var el = this.el;
25+
el.addEventListener('hit', this.onHit);
26+
el.addEventListener('gripdown', this.onGripClose);
27+
el.addEventListener('gripup', this.onGripOpen);
28+
el.addEventListener('trackpaddown', this.onGripClose);
29+
el.addEventListener('trackpadup', this.onGripOpen);
30+
el.addEventListener('triggerdown', this.onGripClose);
31+
el.addEventListener('triggerup', this.onGripOpen);
32+
},
33+
34+
pause: function () {
35+
var el = this.el;
36+
el.removeEventListener('hit', this.onHit);
37+
el.removeEventListener('gripdown', this.onGripClose);
38+
el.removeEventListener('gripup', this.onGripOpen);
39+
el.removeEventListener('trackpaddown', this.onGripClose);
40+
el.removeEventListener('trackpadup', this.onGripOpen);
41+
el.removeEventListener('triggerdown', this.onGripClose);
42+
el.removeEventListener('triggerup', this.onGripOpen);
43+
},
44+
45+
onGripClose: function (evt) {
46+
this.grabbing = true;
47+
},
48+
49+
onGripOpen: function (evt) {
50+
var hitEl = this.hitEl;
51+
this.grabbing = false;
52+
if (!hitEl) { return; }
53+
hitEl.removeState(this.GRABBED_STATE);
54+
this.hitEl = undefined;
55+
this.physics.world.removeConstraint(this.constraint);
56+
this.constraint = null;
57+
},
58+
59+
onHit: function (evt) {
60+
var hitEl = evt.detail.el;
61+
// If the element is already grabbed (it could be grabbed by another controller).
62+
// If the hand is not grabbing the element does not stick.
63+
// If we're already grabbing something you can't grab again.
64+
if (!hitEl || hitEl.is(this.GRABBED_STATE) || !this.grabbing || this.hitEl) { return; }
65+
hitEl.addState(this.GRABBED_STATE);
66+
this.hitEl = hitEl;
67+
this.constraint = new CANNON.LockConstraint(this.el.body, hitEl.body);
68+
this.physics.world.addConstraint(this.constraint);
69+
}
70+
};

‎src/misc/index.js‎

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@ var math = require('../math'),
33

44
module.exports = {
55
'checkpoint': require('./checkpoint'),
6+
'grab': require('./grab'),
67
'jump-ability': require('./jump-ability'),
8+
'sphere-collider': require('./sphere-collider'),
79
'toggle-velocity': require('./toggle-velocity'),
810

911
registerAll: function (AFRAME) {
@@ -14,9 +16,11 @@ module.exports = {
1416

1517
math.registerAll();
1618
physics.registerAll();
17-
if (!AFRAME.components['checkpoint']) AFRAME.registerComponent('checkpoint', this['checkpoint']);
18-
if (!AFRAME.components['jump-ability']) AFRAME.registerComponent('jump-ability', this['jump-ability']);
19-
if (!AFRAME.components['toggle-velocity']) AFRAME.registerComponent('toggle-velocity', this['toggle-velocity']);
19+
if (!AFRAME.components['checkpoint']) AFRAME.registerComponent('checkpoint', this['checkpoint']);
20+
if (!AFRAME.components['grab']) AFRAME.registerComponent('grab', this['grab']);
21+
if (!AFRAME.components['jump-ability']) AFRAME.registerComponent('jump-ability', this['jump-ability']);
22+
if (!AFRAME.components['sphere-collider']) AFRAME.registerComponent('sphere-collider', this['sphere-collider']);
23+
if (!AFRAME.components['toggle-velocity']) AFRAME.registerComponent('toggle-velocity', this['toggle-velocity']);
2024

2125
this._registered = true;
2226
}

‎src/misc/sphere-collider.js‎

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
/**
2+
* Based on aframe/examples/showcase/tracked-controls.
3+
*
4+
* Implement bounding sphere collision detection for entities with a mesh.
5+
* Sets the specified state on the intersected entities.
6+
*
7+
* @property {string} objects - Selector of the entities to test for collision.
8+
* @property {string} state - State to set on collided entities.
9+
*
10+
*/
11+
module.exports = {
12+
schema: {
13+
objects: {default: ''},
14+
state: {default: 'collided'},
15+
radius: {default: 0.05}
16+
},
17+
18+
init: function () {
19+
this.els = [];
20+
this.collisions = [];
21+
},
22+
23+
/**
24+
* Update list of entities to test for collision.
25+
*/
26+
update: function () {
27+
var data = this.data;
28+
var objectEls;
29+
30+
// Push entities into list of els to intersect.
31+
if (data.objects) {
32+
objectEls = this.el.sceneEl.querySelectorAll(data.objects);
33+
} else {
34+
// If objects not defined, intersect with everything.
35+
objectEls = this.el.sceneEl.children;
36+
}
37+
// Convert from NodeList to Array
38+
this.els = Array.prototype.slice.call(objectEls);
39+
},
40+
41+
tick: (function () {
42+
var position = new THREE.Vector3(),
43+
meshPosition = new THREE.Vector3();
44+
return function () {
45+
var el = this.el,
46+
data = this.data,
47+
mesh = el.getObject3D('mesh'),
48+
collisions = [];
49+
50+
if (!mesh) { return; }
51+
52+
position.copy(el.getComputedAttribute('position'));
53+
54+
// Update collisions.
55+
this.els.forEach(intersect);
56+
// Emit events.
57+
collisions.forEach(handleHit);
58+
// No collisions.
59+
if (collisions.length === 0) { el.emit('hit', {el: null}); }
60+
// Updated the state of the elements that are not intersected anymore.
61+
this.collisions.filter(function (el) {
62+
return collisions.indexOf(el) === -1;
63+
}).forEach(function removeState (el) {
64+
el.removeState(data.state);
65+
});
66+
// Store new collisions
67+
this.collisions = collisions;
68+
69+
// AABB collision detection
70+
function intersect (el) {
71+
var radius,
72+
mesh = el.getObject3D('mesh');
73+
74+
if (!mesh) return;
75+
76+
mesh.getWorldPosition(meshPosition);
77+
mesh.geometry.computeBoundingSphere();
78+
radius = mesh.geometry.boundingSphere.radius;
79+
if (position.distanceTo(meshPosition) < radius + data.radius) {
80+
collisions.push(el);
81+
}
82+
}
83+
84+
function handleHit (hitEl) {
85+
hitEl.emit('hit');
86+
hitEl.addState(data.state);
87+
el.emit('hit', {el: hitEl});
88+
}
89+
};
90+
})()
91+
};

0 commit comments

Comments
 (0)