Skip to content

Commit 0646935

Browse files
authored
Merge pull request #127 from wmurphyrd/aframe080
WIP A-Frame v0.8.0 support
2 parents da9a295 + f0ad636 commit 0646935

36 files changed

+15155
-186
lines changed

README.md

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ Install and use by directly including the [browser files](dist):
8383
```html
8484
<head>
8585
<title>Most Basic Super-Hands Example</title>
86-
<script src="https://aframe.io/releases/0.7.1/aframe.min.js"></script>
86+
<script src="https://aframe.io/releases/0.8.0/aframe.min.js"></script>
8787
<script src="//cdn.rawgit.com/donmccurdy/aframe-extras/v3.12.4/dist/aframe-extras.min.js"></script>
8888
<script src="https://unpkg.com/[email protected]/dist/super-hands.min.js"></script>
8989
</head>
@@ -117,6 +117,7 @@ require('super-hands');
117117

118118
Master branch
119119

120+
* Prioritize the nearest intersected entity when using raycaster
120121
* Improved nested entity handling: only one component can react to each
121122
gesture event.
122123
* Improved stretching of complex physics bodies: all shapes, child entity
@@ -257,7 +258,7 @@ If needed, use `event.target` instead.
257258
and the reaction component on the parent
258259
(e.g., a door with the handle as a collidable child and a `grabable` parent
259260
door so the whole door moves only when the handle is grabbed). To prevent
260-
a gesture form bubbling, trap it on the child by giving it reaction components
261+
a gesture from bubbling, trap it on the child by giving it reaction components
261262
or listening-for and cancelling the gesture events
262263
(see [Gesture acceptance and rejection](#Gesture-acceptance-and-rejection]))
263264

@@ -336,7 +337,7 @@ configuration and the raycaster or collider (e.g. the
336337
replaces the default collider with a different component).
337338
If you need to change or add entities,
338339
you can manually create the player avatar structure using classes to tag
339-
the controller and raycaster entities for `progressice-controls` (e.g., the
340+
the controller and raycaster entities for `progressive-controls` (e.g., the
340341
[Global Event Handlers example](examples/events/index.html)
341342
adds children to the controllers and raycaster). The complete
342343
default configuration created by `progressive-controls` is below
@@ -429,9 +430,7 @@ super-hands gestures.
429430
### hoverable component
430431

431432
Used to indicate when the controller is within range to interact with an entity
432-
by adding the 'hovered' state. When using a mixin, including another mixin
433-
in the assets withe same id + '-hovered' will activate automatically, as in
434-
[the examples](https://wmurphyrd.github.io/aframe-super-hands-component/examples/).
433+
by adding the 'hovered' state.
435434

436435
#### States
437436

dist/super-hands.js

Lines changed: 89 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@ AFRAME.registerComponent('super-hands', {
8080

8181
// state tracking - reaction components
8282
this.hoverEls = [];
83+
this.hoverElsDist = [];
8384
this.state = new Map();
8485
this.dragging = false;
8586

@@ -185,9 +186,9 @@ AFRAME.registerComponent('super-hands', {
185186
},
186187
onStretchEndButton: function (evt) {
187188
const stretched = this.state.get(this.STRETCH_EVENT);
188-
const endEvt = { hand: this.el, buttonEvent: evt
189-
// check if end event accepted
190-
};if (stretched && !this.emitCancelable(stretched, this.UNSTRETCH_EVENT, endEvt)) {
189+
const endEvt = { hand: this.el, buttonEvent: evt };
190+
// check if end event accepted
191+
if (stretched && !this.emitCancelable(stretched, this.UNSTRETCH_EVENT, endEvt)) {
191192
this.promoteHoveredEl(stretched);
192193
this.state.delete(this.STRETCH_EVENT);
193194
this.hover();
@@ -253,11 +254,23 @@ AFRAME.registerComponent('super-hands', {
253254
},
254255
onHit: function (evt) {
255256
const hitEl = evt.detail[this.data.colliderEventProperty];
256-
var processHitEl = hitEl => {
257+
var processHitEl = (hitEl, distance) => {
257258
let hitElIndex;
258259
hitElIndex = this.hoverEls.indexOf(hitEl);
259260
if (hitElIndex === -1) {
260-
this.hoverEls.push(hitEl);
261+
// insert in order of distance when available
262+
if (distance) {
263+
let i = 0;
264+
const dists = this.hoverElsDist;
265+
while (distance < dists[i] && i < dists.length) {
266+
i++;
267+
}
268+
this.hoverEls.splice(i, 0, hitEl);
269+
this.hoverElsDist.splice(i, 0, distance);
270+
} else {
271+
this.hoverEls.push(hitEl);
272+
this.hoverElsDist.push(null);
273+
}
261274
// later loss of collision will remove from hoverEls
262275
hitEl.addEventListener('stateremoved', this.unWatch);
263276
this.dispatchMouseEvent(hitEl, 'mouseover', this.el);
@@ -274,9 +287,13 @@ AFRAME.registerComponent('super-hands', {
274287
return;
275288
}
276289
if (Array.isArray(hitEl)) {
290+
for (let i = 0, dist; i < hitEl.length; i++) {
291+
dist = evt.detail.intersections && evt.detail.intersections[i].distance;
292+
processHitEl(hitEl[i], dist);
293+
}
277294
hitEl.forEach(processHitEl);
278295
} else {
279-
processHitEl(hitEl);
296+
processHitEl(hitEl, null);
280297
}
281298
},
282299
/* search collided entities for target to hover/dragover */
@@ -372,6 +389,7 @@ AFRAME.registerComponent('super-hands', {
372389
target.removeEventListener('stateremoved', this.unWatch);
373390
if (hoverIndex !== -1) {
374391
this.hoverEls.splice(hoverIndex, 1);
392+
this.hoverElsDist.splice(hoverIndex, 1);
375393
}
376394
this.gehDragged.forEach(dragged => {
377395
this.dispatchMouseEvent(target, 'dragleave', dragged);
@@ -384,24 +402,26 @@ AFRAME.registerComponent('super-hands', {
384402
this.el.addEventListener(this.data.colliderEndEvent, this.unWatch);
385403
this.el.addEventListener(this.data.colliderEndEvent, this.unHover);
386404

405+
// binding order to keep grabEnd from triggering dragover
406+
// again before dragDropEnd can delete its carried state
387407
this.data.grabStartButtons.forEach(b => {
388408
this.el.addEventListener(b, this.onGrabStartButton);
389409
});
390-
this.data.grabEndButtons.forEach(b => {
391-
this.el.addEventListener(b, this.onGrabEndButton);
392-
});
393410
this.data.stretchStartButtons.forEach(b => {
394411
this.el.addEventListener(b, this.onStretchStartButton);
395412
});
396-
this.data.stretchEndButtons.forEach(b => {
397-
this.el.addEventListener(b, this.onStretchEndButton);
398-
});
399413
this.data.dragDropStartButtons.forEach(b => {
400414
this.el.addEventListener(b, this.onDragDropStartButton);
401415
});
402416
this.data.dragDropEndButtons.forEach(b => {
403417
this.el.addEventListener(b, this.onDragDropEndButton);
404418
});
419+
this.data.stretchEndButtons.forEach(b => {
420+
this.el.addEventListener(b, this.onStretchEndButton);
421+
});
422+
this.data.grabEndButtons.forEach(b => {
423+
this.el.addEventListener(b, this.onGrabEndButton);
424+
});
405425
},
406426
unRegisterListeners: function (data) {
407427
data = data || this.data;
@@ -473,16 +493,20 @@ AFRAME.registerComponent('super-hands', {
473493
}
474494
return null;
475495
},
496+
// Helper to ensure dropping and regrabbing finds the same target for
497+
// for order-sorted hoverEls (grabbing; no-op for distance-sorted (pointing)
476498
promoteHoveredEl: function (el) {
477499
var hoverIndex = this.hoverEls.indexOf(el);
478-
if (hoverIndex !== -1) {
500+
if (hoverIndex !== -1 && this.hoverElsDist[hoverIndex] == null) {
479501
this.hoverEls.splice(hoverIndex, 1);
502+
this.hoverElsDist.splice(hoverIndex, 1);
480503
this.hoverEls.push(el);
504+
this.hoverElsDist.push(null);
481505
}
482506
}
483507
});
484508

485-
},{"./misc_components/locomotor-auto-config.js":2,"./misc_components/progressive-controls.js":3,"./primitives/a-locomotor.js":4,"./reaction_components/clickable.js":5,"./reaction_components/drag-droppable.js":6,"./reaction_components/draggable.js":7,"./reaction_components/droppable.js":8,"./reaction_components/grabbable.js":9,"./reaction_components/hoverable.js":10,"./reaction_components/stretchable.js":13,"./systems/super-hands-system.js":14}],2:[function(require,module,exports){
509+
},{"./misc_components/locomotor-auto-config.js":2,"./misc_components/progressive-controls.js":3,"./primitives/a-locomotor.js":4,"./reaction_components/clickable.js":5,"./reaction_components/drag-droppable.js":6,"./reaction_components/draggable.js":7,"./reaction_components/droppable.js":8,"./reaction_components/grabbable.js":9,"./reaction_components/hoverable.js":10,"./reaction_components/stretchable.js":14,"./systems/super-hands-system.js":15}],2:[function(require,module,exports){
486510
'use strict';
487511

488512
/* global AFRAME */
@@ -498,6 +522,7 @@ AFRAME.registerComponent('locomotor-auto-config', {
498522
if (this.data.camera) {
499523
if (!document.querySelector('a-camera, [camera]')) {
500524
let cam = document.createElement('a-camera');
525+
cam.setAttribute('position', '0 1.6 0');
501526
this.el.appendChild(cam);
502527
}
503528
}
@@ -523,7 +548,14 @@ AFRAME.registerComponent('locomotor-auto-config', {
523548
}
524549
},
525550
remove: function () {
526-
this.el.removeState(this.colliderState);
551+
this.el.getChildEntities().forEach(el => {
552+
let sh = el.getAttribute('super-hands');
553+
if (sh) {
554+
let evtDetails = {};
555+
evtDetails[sh.colliderEndEventProperty] = this.el;
556+
el.emit(sh.colliderEndEvent, evtDetails);
557+
}
558+
});
527559
this.el.removeEventListener('controllerconnected', this.fakeCollisionsB);
528560
},
529561
announceReady: function () {
@@ -543,8 +575,8 @@ AFRAME.registerComponent('locomotor-auto-config', {
543575
this.colliderState = sh.colliderState;
544576
this.el.addState(this.colliderState);
545577
}
546-
this.announceReady();
547578
});
579+
this.announceReady();
548580
}
549581
});
550582

@@ -609,7 +641,11 @@ AFRAME.registerComponent('progressive-controls', {
609641
assets.appendChild(pointDefault);
610642
assets.appendChild(touchDefault);
611643

612-
this.camera = this.el.querySelector('a-camera,[camera]') || this.el.appendChild(document.createElement('a-camera'));
644+
this.camera = this.el.querySelector('a-camera,[camera]');
645+
if (!this.camera) {
646+
this.camera = this.el.appendChild(document.createElement('a-camera'));
647+
this.camera.setAttribute('position', '0 1.6 0');
648+
}
613649
this.caster = this.camera.querySelector('.gazecaster') || this.camera.appendChild(document.createElement('a-entity'));
614650
['left', 'right'].forEach(hand => {
615651
// find controller by left-controller/right-controller class or create one
@@ -1067,7 +1103,10 @@ AFRAME.registerComponent('droppable', {
10671103
const inherit = AFRAME.utils.extendDeep;
10681104
const physicsCore = require('./prototypes/physics-grab-proto.js');
10691105
const buttonsCore = require('./prototypes/buttons-proto.js');
1070-
AFRAME.registerComponent('grabbable', inherit({}, physicsCore, buttonsCore, {
1106+
const networkedCore = require('./prototypes/networked-proto.js');
1107+
// new object with all core modules
1108+
const base = inherit({}, physicsCore, buttonsCore, networkedCore);
1109+
AFRAME.registerComponent('grabbable', inherit(base, {
10711110
schema: {
10721111
maxGrabbers: { type: 'int', default: NaN },
10731112
invert: { default: false },
@@ -1083,9 +1122,9 @@ AFRAME.registerComponent('grabbable', inherit({}, physicsCore, buttonsCore, {
10831122
this.deltaPositionIsValid = false;
10841123
this.grabDistance = undefined;
10851124
this.grabDirection = { x: 0, y: 0, z: -1 };
1086-
this.grabOffset = { x: 0, y: 0, z: 0
1087-
// persistent object speeds up repeat setAttribute calls
1088-
};this.destPosition = { x: 0, y: 0, z: 0 };
1125+
this.grabOffset = { x: 0, y: 0, z: 0 };
1126+
// persistent object speeds up repeat setAttribute calls
1127+
this.destPosition = { x: 0, y: 0, z: 0 };
10891128
this.deltaPosition = new THREE.Vector3();
10901129
this.targetPosition = new THREE.Vector3();
10911130
this.physicsInit();
@@ -1132,7 +1171,7 @@ AFRAME.registerComponent('grabbable', inherit({}, physicsCore, buttonsCore, {
11321171
// room for more grabbers?
11331172
const grabAvailable = !Number.isFinite(this.data.maxGrabbers) || this.grabbers.length < this.data.maxGrabbers;
11341173

1135-
if (this.grabbers.indexOf(evt.detail.hand) === -1 && grabAvailable) {
1174+
if (this.grabbers.indexOf(evt.detail.hand) === -1 && grabAvailable && this.networkedOk()) {
11361175
if (!evt.detail.hand.object3D) {
11371176
console.warn('grabbable entities must have an object3D');
11381177
return;
@@ -1192,7 +1231,7 @@ AFRAME.registerComponent('grabbable', inherit({}, physicsCore, buttonsCore, {
11921231
}
11931232
}));
11941233

1195-
},{"./prototypes/buttons-proto.js":11,"./prototypes/physics-grab-proto.js":12}],10:[function(require,module,exports){
1234+
},{"./prototypes/buttons-proto.js":11,"./prototypes/networked-proto.js":12,"./prototypes/physics-grab-proto.js":13}],10:[function(require,module,exports){
11961235
'use strict';
11971236

11981237
/* global AFRAME */
@@ -1263,6 +1302,25 @@ module.exports = function () {
12631302
}();
12641303

12651304
},{}],12:[function(require,module,exports){
1305+
"use strict";
1306+
1307+
// integration with networked-aframe
1308+
module.exports = {
1309+
schema: {
1310+
takeOwnership: { default: false }
1311+
},
1312+
networkedOk: function () {
1313+
if (!window.NAF || window.NAF.utils.isMine(this.el)) {
1314+
return true;
1315+
}
1316+
if (this.data.takeOwnership) {
1317+
return window.NAF.utils.takeOwnership(this.el);
1318+
}
1319+
return false;
1320+
}
1321+
};
1322+
1323+
},{}],13:[function(require,module,exports){
12661324
'use strict';
12671325

12681326
// base code used by grabbable for physics interactions
@@ -1320,13 +1378,16 @@ module.exports = {
13201378
}
13211379
};
13221380

1323-
},{}],13:[function(require,module,exports){
1381+
},{}],14:[function(require,module,exports){
13241382
'use strict';
13251383

13261384
/* global AFRAME, THREE */
13271385
const inherit = AFRAME.utils.extendDeep;
1328-
const buttonCore = require('./prototypes/buttons-proto.js');
1329-
AFRAME.registerComponent('stretchable', inherit({}, buttonCore, {
1386+
const buttonsCore = require('./prototypes/buttons-proto.js');
1387+
const networkedCore = require('./prototypes/networked-proto.js');
1388+
// new object with all core modules
1389+
const base = inherit({}, buttonsCore, networkedCore);
1390+
AFRAME.registerComponent('stretchable', inherit(base, {
13301391
schema: {
13311392
usePhysics: { default: 'ifavailable' },
13321393
invert: { default: false },
@@ -1379,7 +1440,7 @@ AFRAME.registerComponent('stretchable', inherit({}, buttonCore, {
13791440
this.el.removeEventListener(this.UNSTRETCH_EVENT, this.end);
13801441
},
13811442
start: function (evt) {
1382-
if (this.stretched || this.stretchers.includes(evt.detail.hand) || !this.startButtonOk(evt) || evt.defaultPrevented) {
1443+
if (this.stretched || this.stretchers.includes(evt.detail.hand) || !this.startButtonOk(evt) || evt.defaultPrevented || !this.networkedOk()) {
13831444
return;
13841445
} // already stretched or already captured this hand or wrong button
13851446
this.stretchers.push(evt.detail.hand);
@@ -1453,7 +1514,7 @@ AFRAME.registerComponent('stretchable', inherit({}, buttonCore, {
14531514
}
14541515
}));
14551516

1456-
},{"./prototypes/buttons-proto.js":11}],14:[function(require,module,exports){
1517+
},{"./prototypes/buttons-proto.js":11,"./prototypes/networked-proto.js":12}],15:[function(require,module,exports){
14571518
'use strict';
14581519

14591520
/* global AFRAME */

0 commit comments

Comments
 (0)