From 7a58f91c0c57f63168ccf8560c35f3e9c8e6ab88 Mon Sep 17 00:00:00 2001 From: johnshaughnessy Date: Sat, 2 Mar 2019 16:14:15 -0800 Subject: [PATCH 01/96] Remove super-hands --- package-lock.json | 4 ---- package.json | 1 - src/hub.js | 1 - 3 files changed, 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4f2473ba7f..42b332e67f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17320,10 +17320,6 @@ "resolved": "https://registry.npmjs.org/super-animejs/-/super-animejs-3.0.0.tgz", "integrity": "sha512-sU+zS5zBFIfiZLswckLAiTV1wuWAm3O34sC1SfwFiHv8zVkpzGmntjwjwq6JUd34x/6vSset7gWZRmBiWkrLUA==" }, - "super-hands": { - "version": "github:mozillareality/aframe-super-hands-component#68d022fd24c6c986ec3af09a3e88b75323e9803f", - "from": "github:mozillareality/aframe-super-hands-component#feature/drawing" - }, "supertap": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/supertap/-/supertap-1.0.0.tgz", diff --git a/package.json b/package.json index 3a4674be1c..86bd9f2eb2 100644 --- a/package.json +++ b/package.json @@ -76,7 +76,6 @@ "react-router-dom": "^4.3.1", "react-youtube": "^7.8.0", "screenfull": "^3.3.2", - "super-hands": "github:mozillareality/aframe-super-hands-component#feature/drawing", "three": "github:mozillareality/three.js#hubs/master", "three-mesh-bvh": "github:mquander/three-mesh-bvh#global-three", "three-pathfinding": "github:mozillareality/three-pathfinding#hubs/master", diff --git a/src/hub.js b/src/hub.js index 062857b328..d76f10d8b7 100644 --- a/src/hub.js +++ b/src/hub.js @@ -136,7 +136,6 @@ window.APP.quality = qs.get("quality") || isMobile ? "low" : "high"; import "aframe-physics-system"; import "aframe-physics-extras"; -import "super-hands"; import "./components/super-networked-interactable"; import "./components/networked-counter"; import "./components/event-repeater"; From 569a4d2461556cb2a000783cd483add2b37cef28 Mon Sep 17 00:00:00 2001 From: johnshaughnessy Date: Sat, 2 Mar 2019 16:15:17 -0800 Subject: [PATCH 02/96] Remove references to super-hands component --- src/components/cursor-controller.js | 2 +- src/components/hover-visuals.js | 2 +- src/systems/userinput/devices/app-aware-touchscreen.js | 2 +- src/systems/userinput/devices/vive-controller.js | 4 ++-- src/systems/userinput/resolve-action-sets.js | 6 +++--- 5 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/components/cursor-controller.js b/src/components/cursor-controller.js index 75b6f935fb..5e78a1878e 100644 --- a/src/components/cursor-controller.js +++ b/src/components/cursor-controller.js @@ -209,7 +209,7 @@ AFRAME.registerComponent("cursor-controller", { } let intersection; - const isGrabbing = this.data.cursor.components["super-hands"].state.has("grab-start"); + const isGrabbing = false; // this.data.cursor.components["super-hands"].state.has("grab-start"); if (!isGrabbing) { rawIntersections.length = 0; this.raycaster.ray.origin = cursorPose.position; diff --git a/src/components/hover-visuals.js b/src/components/hover-visuals.js index 11396eef51..a17da11b17 100644 --- a/src/components/hover-visuals.js +++ b/src/components/hover-visuals.js @@ -19,7 +19,7 @@ AFRAME.registerComponent("hover-visuals", { if (!this.uniforms || !this.uniforms.size) return; const elements = this.el.object3D.matrixWorld.elements; - const hovering = this.data.controller.components["super-hands"].state.has("hover-start"); + const hovering = false; //this.data.controller.components["super-hands"].state.has("hover-start"); for (const uniform of this.uniforms.values()) { if (this.data.hand === "left") { diff --git a/src/systems/userinput/devices/app-aware-touchscreen.js b/src/systems/userinput/devices/app-aware-touchscreen.js index 1f832eba37..48922d02b9 100644 --- a/src/systems/userinput/devices/app-aware-touchscreen.js +++ b/src/systems/userinput/devices/app-aware-touchscreen.js @@ -27,7 +27,7 @@ const getPlayerCamera = (() => { function shouldMoveCursor(touch, raycaster) { const cursorController = document.querySelector("[cursor-controller]").components["cursor-controller"]; - const isCursorGrabbing = cursorController.data.cursor.components["super-hands"].state.has("grab-start"); + const isCursorGrabbing = false;//cursorController.data.cursor.components["super-hands"].state.has("grab-start"); if (isCursorGrabbing) { return true; } diff --git a/src/systems/userinput/devices/vive-controller.js b/src/systems/userinput/devices/vive-controller.js index e8d410bbb2..afe547a774 100644 --- a/src/systems/userinput/devices/vive-controller.js +++ b/src/systems/userinput/devices/vive-controller.js @@ -31,7 +31,7 @@ export class ViveControllerDevice { if (!gamepad.hand) { console.warn("gamepad detected without hand specified"); } else { - this.selector = `[super-hands]#player-${gamepad.hand}-controller`; + this.selector = `#player-${gamepad.hand}-controller`; } this.sittingToStandingMatrix = new THREE.Matrix4().makeTranslation(0, 1.6, 0); copySittingToStandingTransform(this.sittingToStandingMatrix); @@ -67,7 +67,7 @@ export class ViveControllerDevice { if (!this.selector) { if (this.gamepad.hand) { this.path = paths.device.vive[this.gamepad.hand]; - this.selector = `[super-hands]#player-${this.gamepad.hand}-controller`; + this.selector = `#player-${this.gamepad.hand}-controller`; console.warn("gamepad hand eventually specified"); } else { return; diff --git a/src/systems/userinput/resolve-action-sets.js b/src/systems/userinput/resolve-action-sets.js index 323d6cf018..5ecb9414b4 100644 --- a/src/systems/userinput/resolve-action-sets.js +++ b/src/systems/userinput/resolve-action-sets.js @@ -8,9 +8,9 @@ let rightTeleporter; let cursorController; export function resolveActionSets() { - rightHandState = rightHandState || document.querySelector("#player-right-controller").components["super-hands"].state; - leftHandState = leftHandState || document.querySelector("#player-left-controller").components["super-hands"].state; - cursorHand = cursorHand || document.querySelector("#cursor").components["super-hands"].state; + rightHandState = new Map(); //rightHandState || document.querySelector("#player-right-controller").components["super-hands"].state; + leftHandState = new Map(); //leftHandState || document.querySelector("#player-left-controller").components["super-hands"].state; + cursorHand = new Map(); //cursorHand || document.querySelector("#cursor").components["super-hands"].state; leftTeleporter = leftTeleporter || document.querySelector("#player-left-controller").components["teleporter"]; rightTeleporter = rightTeleporter || document.querySelector("#player-right-controller").components["teleporter"]; cursorController = cursorController || document.querySelector("#cursor-controller").components["cursor-controller"]; From 5054f418f715b9173d2c524ae0eaf281f877494d Mon Sep 17 00:00:00 2001 From: johnshaughnessy Date: Sat, 2 Mar 2019 16:15:32 -0800 Subject: [PATCH 03/96] Remove functionality related to reaction components --- src/components/camera-tool.js | 2 +- src/components/hoverable-visuals.js | 1 + src/components/super-networked-interactable.js | 1 + src/components/tools/pen.js | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/camera-tool.js b/src/components/camera-tool.js index 85ad30eea6..bc2baa7d95 100644 --- a/src/components/camera-tool.js +++ b/src/components/camera-tool.js @@ -151,7 +151,7 @@ AFRAME.registerComponent("camera-tool", { }, tick() { - const grabber = this.el.components.grabbable.grabbers[0]; + const grabber = undefined; //this.el.components.grabbable.grabbers[0]; if (grabber && !!pathsMap[grabber.id]) { const paths = pathsMap[grabber.id]; if (AFRAME.scenes[0].systems.userinput.get(paths.takeSnapshot)) { diff --git a/src/components/hoverable-visuals.js b/src/components/hoverable-visuals.js index 4b33603fdf..3ebcbd0a0f 100644 --- a/src/components/hoverable-visuals.js +++ b/src/components/hoverable-visuals.js @@ -25,6 +25,7 @@ AFRAME.registerComponent("hoverable-visuals", { tick(time) { if (!this.uniforms || !this.uniforms.size) return; + return; // replace-super-hands const { hoverers } = this.el.components["hoverable"]; const isFrozen = this.el.sceneEl.is("frozen"); diff --git a/src/components/super-networked-interactable.js b/src/components/super-networked-interactable.js index 62b6e128e8..7e9f61ade5 100644 --- a/src/components/super-networked-interactable.js +++ b/src/components/super-networked-interactable.js @@ -112,6 +112,7 @@ AFRAME.registerComponent("super-networked-interactable", { }, tick: function() { + return; // replace-super-hands const grabber = this.el.components.grabbable.grabbers[0]; if (!(grabber && pathsMap[grabber.id])) return; diff --git a/src/components/tools/pen.js b/src/components/tools/pen.js index 1a656fa670..afdc2556cc 100644 --- a/src/components/tools/pen.js +++ b/src/components/tools/pen.js @@ -103,6 +103,7 @@ AFRAME.registerComponent("pen", { }, tick(t, dt) { + return; // replace-super-hands const grabber = this.el.parentNode.components.grabbable.grabbers[0]; const userinput = AFRAME.scenes[0].systems.userinput; From ca515a116928df3d164275684e20244c8abe3ec6 Mon Sep 17 00:00:00 2001 From: johnshaughnessy Date: Sat, 2 Mar 2019 17:28:06 -0800 Subject: [PATCH 04/96] Attempt to recognize hovering --- src/components/cursor-controller.js | 3 +- src/hub.html | 1 + src/hub.js | 1 + src/systems/interactions.js | 31 ++++++++++++++++++++ src/systems/userinput/resolve-action-sets.js | 2 +- 5 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 src/systems/interactions.js diff --git a/src/components/cursor-controller.js b/src/components/cursor-controller.js index 5e78a1878e..5bb3260ab7 100644 --- a/src/components/cursor-controller.js +++ b/src/components/cursor-controller.js @@ -216,7 +216,8 @@ AFRAME.registerComponent("cursor-controller", { this.raycaster.ray.direction = cursorPose.direction; this.raycaster.intersectObjects(this.targets, true, rawIntersections); intersection = rawIntersections.find(x => x.object.el); - this.emitIntersectionEvents(this.prevIntersection, intersection); + AFRAME.scenes[0].systems.interaction.updateCursorIntersections(intersection, this.prevIntersection, rawIntersections); +// this.emitIntersectionEvents(this.prevIntersection, intersection); this.prevIntersection = intersection; this.distance = intersection ? intersection.distance : this.data.far; } diff --git a/src/hub.html b/src/hub.html index 8210720690..eefb7c8ba2 100644 --- a/src/hub.html +++ b/src/hub.html @@ -216,6 +216,7 @@ class="interactable" super-networked-interactable="counter: #media-counter;" body="type: dynamic; shape: none; mass: 1;" + prep-grab grabbable stretchable="useWorldPosition: true; usePhysics: never" hoverable diff --git a/src/hub.js b/src/hub.js index d76f10d8b7..75086adaa5 100644 --- a/src/hub.js +++ b/src/hub.js @@ -114,6 +114,7 @@ import "./systems/userinput/userinput-debug"; import "./systems/frame-scheduler"; import "./systems/ui-hotkeys"; import "./systems/tips"; +import "./systems/interactions"; import "./gltf-component-mappings"; diff --git a/src/systems/interactions.js b/src/systems/interactions.js new file mode 100644 index 0000000000..7106905d99 --- /dev/null +++ b/src/systems/interactions.js @@ -0,0 +1,31 @@ +// Goal 1: When the cursor intersects an object, I want to change action sets depending on the component on the object. +import { sets } from "./userinput/sets"; + +const PREP_GRAB = "prep-grab"; +AFRAME.registerComponent(PREP_GRAB, { + init: function() { + this.prepped = false; + } +}); + +AFRAME.registerSystem("interaction", { + updateCursorIntersections: function(current, previous, raw) { + if (previous && previous.object.el.components[PREP_GRAB]) { + previous.components[PREP_GRAB].prepped = false; + AFRAME.scenes[0].systems.userinput.toggleSet(sets.cursorHoveringOnInteractable, false); + } + + if (!current) return; + + // For the ducky, the object we intersect is assigned an entity, + // but not the interactable-media entity with the relevant PREP_GRAB component assigned in the html. + // We have to climb to that el's parentEl.parentEl.parentEl. + // However, it's not like we can always do this. For spawned images, such an el is undefined. + // I have not found a way to reconcile this. + const prepGrab = current && (current.object.el.parentEl.parentEl.parentEl.components[PREP_GRAB]); + if (prepGrab) { + AFRAME.scenes[0].systems.userinput.toggleSet(sets.cursorHoveringOnInteractable, true); + prepGrab.prepped = true; + } + } +}); diff --git a/src/systems/userinput/resolve-action-sets.js b/src/systems/userinput/resolve-action-sets.js index 5ecb9414b4..2c68dac867 100644 --- a/src/systems/userinput/resolve-action-sets.js +++ b/src/systems/userinput/resolve-action-sets.js @@ -137,7 +137,7 @@ export function resolveActionSets() { userinput.toggleSet(sets.cursorHoveringOnPen, cursorHoveringOnPen); userinput.toggleSet(sets.cursorHoveringOnCamera, cursorHoveringOnCamera); - userinput.toggleSet(sets.cursorHoveringOnInteractable, cursorHoveringOnInteractable); +// userinput.toggleSet(sets.cursorHoveringOnInteractable, cursorHoveringOnInteractable); userinput.toggleSet(sets.cursorHoveringOnUI, cursorHoveringOnUI); userinput.toggleSet(sets.cursorHoveringOnVideo, cursorHoveringOnVideo); userinput.toggleSet(sets.cursorHoveringOnNothing, cursorHoveringOnNothing); From 8b6e76946e71c51555fd745b3c3b74feca380ec4 Mon Sep 17 00:00:00 2001 From: johnshaughnessy Date: Sat, 2 Mar 2019 17:47:14 -0800 Subject: [PATCH 05/96] Write down notes about what I'm thinking --- notes.txt | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 notes.txt diff --git a/notes.txt b/notes.txt new file mode 100644 index 0000000000..84671fd0a5 --- /dev/null +++ b/notes.txt @@ -0,0 +1,5 @@ +I would like to replace super-hands with a system that handles interactions. +I want the replacement to make minimal use of aframe, so that we can eventually drop it. +I want the replacement to make minimal use of events, both because of performance reasons and because of the additional complexity dealing with the dom brings to the problem. + +The first attempt can be seen in ca515a116928df3d164275684e20244c8abe3ec6 . The problem I encountered in this attempt is in trying to match the three.js object deep within th duck model's hierarchy that the cursor intersects with the aframe element as defined in the `interactable-media` template. This approach feels extremely error prone and confusing, so I want to think of another. From a9fb0fca8a01414241f51f8e0bd17f824c8bae40 Mon Sep 17 00:00:00 2001 From: johnshaughnessy Date: Sat, 2 Mar 2019 20:45:04 -0800 Subject: [PATCH 06/96] Implement hovering on any object3D beneath the entity. --- notes.txt | 2 +- src/components/cursor-controller.js | 2 +- src/hub.html | 2 +- src/systems/interactions.js | 81 +++++++++++++++----- src/systems/userinput/resolve-action-sets.js | 2 +- 5 files changed, 66 insertions(+), 23 deletions(-) diff --git a/notes.txt b/notes.txt index 84671fd0a5..3a4813a6fd 100644 --- a/notes.txt +++ b/notes.txt @@ -1,5 +1,5 @@ I would like to replace super-hands with a system that handles interactions. I want the replacement to make minimal use of aframe, so that we can eventually drop it. -I want the replacement to make minimal use of events, both because of performance reasons and because of the additional complexity dealing with the dom brings to the problem. +I want the replacement to make minimal use of events, both because of performance reasons and to avoid the additional complexity dealing with the DOM brings to the problem. The first attempt can be seen in ca515a116928df3d164275684e20244c8abe3ec6 . The problem I encountered in this attempt is in trying to match the three.js object deep within th duck model's hierarchy that the cursor intersects with the aframe element as defined in the `interactable-media` template. This approach feels extremely error prone and confusing, so I want to think of another. diff --git a/src/components/cursor-controller.js b/src/components/cursor-controller.js index 5bb3260ab7..2219910dde 100644 --- a/src/components/cursor-controller.js +++ b/src/components/cursor-controller.js @@ -216,7 +216,7 @@ AFRAME.registerComponent("cursor-controller", { this.raycaster.ray.direction = cursorPose.direction; this.raycaster.intersectObjects(this.targets, true, rawIntersections); intersection = rawIntersections.find(x => x.object.el); - AFRAME.scenes[0].systems.interaction.updateCursorIntersections(intersection, this.prevIntersection, rawIntersections); + AFRAME.scenes[0].systems.interaction.updateCursorIntersections(rawIntersections); // this.emitIntersectionEvents(this.prevIntersection, intersection); this.prevIntersection = intersection; this.distance = intersection ? intersection.distance : this.data.far; diff --git a/src/hub.html b/src/hub.html index eefb7c8ba2..5e386cb436 100644 --- a/src/hub.html +++ b/src/hub.html @@ -216,7 +216,7 @@ class="interactable" super-networked-interactable="counter: #media-counter;" body="type: dynamic; shape: none; mass: 1;" - prep-grab + aggregate-and-mark-objects="offerConstraintWhenHovered: true;" grabbable stretchable="useWorldPosition: true; usePhysics: never" hoverable diff --git a/src/systems/interactions.js b/src/systems/interactions.js index 7106905d99..6da2e30d89 100644 --- a/src/systems/interactions.js +++ b/src/systems/interactions.js @@ -1,31 +1,74 @@ -// Goal 1: When the cursor intersects an object, I want to change action sets depending on the component on the object. +// Goal : Collect all of the threejs objects that we might care about hovering onto. +// Notice when we hover on or off them. + import { sets } from "./userinput/sets"; -const PREP_GRAB = "prep-grab"; -AFRAME.registerComponent(PREP_GRAB, { +const AGGREGATE_AND_MARK_THREEJS_OBJECTS_FOR_INTERACTION = "aggregate-and-mark-objects"; +AFRAME.registerComponent(AGGREGATE_AND_MARK_THREEJS_OBJECTS_FOR_INTERACTION, { + schema: { + offerConstraintWhenHovered: { type: "boolean" } + }, + init: function() { - this.prepped = false; + this.onObjectAdded = this.onObjectAdded.bind(this); + this.kids = new Set(); + this.el.object3D.traverse(o => { + this.kids.add(o.uuid); + o.addEventListener("added", this.onObjectAdded); + o.el.addEventListener("object3dset", this.onObjectAdded); + }); + + if (!AFRAME.scenes[0].systems.interaction) { + console.warn("no interaction system yet. setting timeout because yolo."); + window.setTimeout(() => { + AFRAME.scenes[0].systems.interaction.register(this.el.object3D.uuid, this.kids); + }, 3000); + } else { + AFRAME.scenes[0].systems.interaction.register(this.el.object3D.uuid, this.kids); + } + }, + + onObjectAdded: function() { + this.el.object3D.traverse(o => { + if (!this.kids.has(o.uuid)) { + this.kids.add(o.uuid); + o.addEventListener("added", this.onObjectAdded); + o.el.addEventListener("object3dset", this.onObjectAdded); + } + }); + AFRAME.scenes[0].systems.interaction.register(this.el.object3D.uuid, this.kids); } }); AFRAME.registerSystem("interaction", { - updateCursorIntersections: function(current, previous, raw) { - if (previous && previous.object.el.components[PREP_GRAB]) { - previous.components[PREP_GRAB].prepped = false; - AFRAME.scenes[0].systems.userinput.toggleSet(sets.cursorHoveringOnInteractable, false); + init() { + this.rootToKids = new Map(); + this.kidsToRoot = new Map(); + }, + register(root, kids) { + this.rootToKids.set(root, kids); + for (let kid of kids.keys()) { + this.kidsToRoot.set(kid, root); } + }, - if (!current) return; - - // For the ducky, the object we intersect is assigned an entity, - // but not the interactable-media entity with the relevant PREP_GRAB component assigned in the html. - // We have to climb to that el's parentEl.parentEl.parentEl. - // However, it's not like we can always do this. For spawned images, such an el is undefined. - // I have not found a way to reconcile this. - const prepGrab = current && (current.object.el.parentEl.parentEl.parentEl.components[PREP_GRAB]); - if (prepGrab) { - AFRAME.scenes[0].systems.userinput.toggleSet(sets.cursorHoveringOnInteractable, true); - prepGrab.prepped = true; + updateCursorIntersections: function(raw) { + const userinput = AFRAME.scenes[0].systems.userinput; + if (!raw[0]) { + userinput.toggleSet(sets.cursorHoveringOnInteractable, false); + userinput.toggleSet(sets.cursorHoveringOnNothing, true); + this.currentlyHoveredRoot = null; + return; + } + const root = this.kidsToRoot.get(raw[0].object.uuid); + if (!root) { + userinput.toggleSet(sets.cursorHoveringOnInteractable, false); + userinput.toggleSet(sets.cursorHoveringOnNothing, true); + this.currentlyHoveredRoot = null; + return; } + userinput.toggleSet(sets.cursorHoveringOnInteractable, true); + userinput.toggleSet(sets.cursorHoveringOnNothing, false); + this.currentlyHoveredRoot = root; } }); diff --git a/src/systems/userinput/resolve-action-sets.js b/src/systems/userinput/resolve-action-sets.js index 2c68dac867..f2e7a3e5df 100644 --- a/src/systems/userinput/resolve-action-sets.js +++ b/src/systems/userinput/resolve-action-sets.js @@ -140,7 +140,7 @@ export function resolveActionSets() { // userinput.toggleSet(sets.cursorHoveringOnInteractable, cursorHoveringOnInteractable); userinput.toggleSet(sets.cursorHoveringOnUI, cursorHoveringOnUI); userinput.toggleSet(sets.cursorHoveringOnVideo, cursorHoveringOnVideo); - userinput.toggleSet(sets.cursorHoveringOnNothing, cursorHoveringOnNothing); +// userinput.toggleSet(sets.cursorHoveringOnNothing, cursorHoveringOnNothing); userinput.toggleSet(sets.cursorHoldingPen, cursorHoldingPen); userinput.toggleSet(sets.cursorHoldingCamera, cursorHoldingCamera); userinput.toggleSet(sets.cursorHoldingInteractable, cursorHoldingInteractable); From e5fcccfed5892fb65f0839be4ad4135b5e314631 Mon Sep 17 00:00:00 2001 From: johnshaughnessy Date: Sat, 2 Mar 2019 20:51:47 -0800 Subject: [PATCH 07/96] Record observations and progress in notes.txt --- notes.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/notes.txt b/notes.txt index 3a4813a6fd..04a802d69a 100644 --- a/notes.txt +++ b/notes.txt @@ -3,3 +3,5 @@ I want the replacement to make minimal use of aframe, so that we can eventually I want the replacement to make minimal use of events, both because of performance reasons and to avoid the additional complexity dealing with the DOM brings to the problem. The first attempt can be seen in ca515a116928df3d164275684e20244c8abe3ec6 . The problem I encountered in this attempt is in trying to match the three.js object deep within th duck model's hierarchy that the cursor intersects with the aframe element as defined in the `interactable-media` template. This approach feels extremely error prone and confusing, so I want to think of another. + +The second attempt can be seen in a9fb0fca8a01414241f51f8e0bd17f824c8bae40 . I "solved" the problem above by grouping all threejs object3D's beneath the one associated with an entity with a given "aggregator" component on it. This works for the simple case of hovering, but I suspect that I will quickly have to change the menu systems such that the menus are not children of the object in order to continue this way. Alternatively I can keep track of which object3D's are associated with a menu and disallow the aggregation of those object3D's when trying to hover on the duck rather than the duck's menu buttons, but this seems complicated and error prone, so I am not sure I want to go down that route. I think the next steps are to start naively implementing some of the features we like that super-hands helps us provide and pay attention to and try to fix any issues that come up as I go along. From 0488efe211481bba39926290a7c68829bdbf89c1 Mon Sep 17 00:00:00 2001 From: johnshaughnessy Date: Sat, 2 Mar 2019 20:58:35 -0800 Subject: [PATCH 08/96] Update notes --- notes.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/notes.txt b/notes.txt index 04a802d69a..62700ab032 100644 --- a/notes.txt +++ b/notes.txt @@ -5,3 +5,5 @@ I want the replacement to make minimal use of events, both because of performanc The first attempt can be seen in ca515a116928df3d164275684e20244c8abe3ec6 . The problem I encountered in this attempt is in trying to match the three.js object deep within th duck model's hierarchy that the cursor intersects with the aframe element as defined in the `interactable-media` template. This approach feels extremely error prone and confusing, so I want to think of another. The second attempt can be seen in a9fb0fca8a01414241f51f8e0bd17f824c8bae40 . I "solved" the problem above by grouping all threejs object3D's beneath the one associated with an entity with a given "aggregator" component on it. This works for the simple case of hovering, but I suspect that I will quickly have to change the menu systems such that the menus are not children of the object in order to continue this way. Alternatively I can keep track of which object3D's are associated with a menu and disallow the aggregation of those object3D's when trying to hover on the duck rather than the duck's menu buttons, but this seems complicated and error prone, so I am not sure I want to go down that route. I think the next steps are to start naively implementing some of the features we like that super-hands helps us provide and pay attention to and try to fix any issues that come up as I go along. + +I have an unused schema property in this attempt called `offerConstraintWhenHovered`. The thinking here is that I don't want to have a generic "hovering" -- I want the state of the interaction system to be more granular than that. What you're hovering on (rotation button vs volume slider vs duck) and how you're "hovering" (via pointing a cursor at something or intersecting it with your hand) DOES matter to us and to the input system's action sets, so I'd like to model the replacement for "hovering" to respect that. Here the (unimplemented) idea I had is that one kind of hovering will be for changing the action sets to be in a state where creating a physics constraint is a button press away. Thus when you "hover" onto something marked as offerConstraintWhenHovered, well, that's what the thing will do -- you'll end up activating an action set whose associated bindings have a binding written to createPhysicsConstraintOnCursor(/Hand) action path. From f78fce57d13bc73ee3c66c9fbec87326e386c0ea Mon Sep 17 00:00:00 2001 From: johnshaughnessy Date: Wed, 6 Mar 2019 13:59:56 -0800 Subject: [PATCH 09/96] wip --- src/components/cursor-controller.js | 15 ++-- src/hub.html | 59 +----------- src/systems/interactions.js | 94 ++++++++++++++++---- src/systems/userinput/resolve-action-sets.js | 42 +++++++-- 4 files changed, 119 insertions(+), 91 deletions(-) diff --git a/src/components/cursor-controller.js b/src/components/cursor-controller.js index 2219910dde..f1009f11cc 100644 --- a/src/components/cursor-controller.js +++ b/src/components/cursor-controller.js @@ -201,15 +201,16 @@ AFRAME.registerComponent("cursor-controller", { const cursorPose = userinput.get(paths.actions.cursor.pose); const rightHandPose = userinput.get(paths.actions.rightHand.pose); - this.data.cursor.object3D.visible = this.enabled && !!cursorPose; + this.data.cursor.object3D.visible = true;//this.enabled && !!cursorPose; this.line.material.visible = !!(this.enabled && rightHandPose); if (!this.enabled || !cursorPose) { return; } + const interaction = AFRAME.scenes[0].systems.interaction; let intersection; - const isGrabbing = false; // this.data.cursor.components["super-hands"].state.has("grab-start"); + const isGrabbing = !!interaction.currentlyConstrainedRoot; // this.data.cursor.components["super-hands"].state.has("grab-start"); if (!isGrabbing) { rawIntersections.length = 0; this.raycaster.ray.origin = cursorPose.position; @@ -217,7 +218,7 @@ AFRAME.registerComponent("cursor-controller", { this.raycaster.intersectObjects(this.targets, true, rawIntersections); intersection = rawIntersections.find(x => x.object.el); AFRAME.scenes[0].systems.interaction.updateCursorIntersections(rawIntersections); -// this.emitIntersectionEvents(this.prevIntersection, intersection); + // this.emitIntersectionEvents(this.prevIntersection, intersection); this.prevIntersection = intersection; this.distance = intersection ? intersection.distance : this.data.far; } @@ -230,10 +231,10 @@ AFRAME.registerComponent("cursor-controller", { } cursor.object3D.position.copy(cursorPose.position).addScaledVector(cursorPose.direction, this.distance); // The cursor will always be oriented towards the player about its Y axis, so objects held by the cursor will rotate towards the player. - getLastWorldPosition(camera.object3D, cameraPos); - cameraPos.y = cursor.object3D.position.y; - cursor.object3D.lookAt(cameraPos); - cursor.object3D.scale.setScalar(Math.pow(this.distance, 0.315) * 0.75); + //camera.object3D.getWorldPosition(cameraPos); + //cameraPos.y = cursor.object3D.position.y; + //cursor.object3D.lookAt(cameraPos); + //cursor.object3D.scale.setScalar(Math.pow(this.distance, 0.315) * 0.75); cursor.object3D.matrixNeedsUpdate = true; const cursorColor = AFRAME.scenes[0].systems["rotate-selected-object"].rotating diff --git a/src/hub.html b/src/hub.html index 5e386cb436..f6aa0db9aa 100644 --- a/src/hub.html +++ b/src/hub.html @@ -214,64 +214,9 @@ @@ -280,6 +225,7 @@ class="pen interactable" super-networked-interactable="counter: #pen-counter;" body="type: dynamic; shape: none; mass: 1;" + aggregate-and-mark-objects="offerConstraintWhenHovered: true; isPen: true;" grabbable="maxGrabbers: 1" sticky-object="autoLockOnRelease: true; autoLockOnLoad: true; autoLockSpeedLimit: 0;" hoverable @@ -319,6 +265,7 @@ { - AFRAME.scenes[0].systems.interaction.register(this.el.object3D.uuid, this.kids); - }, 3000); - } else { - AFRAME.scenes[0].systems.interaction.register(this.el.object3D.uuid, this.kids); - } + AFRAME.scenes[0].systems.interaction.register(this.el.object3D.uuid, this.kids, this.data); }, onObjectAdded: function() { @@ -36,7 +33,7 @@ AFRAME.registerComponent(AGGREGATE_AND_MARK_THREEJS_OBJECTS_FOR_INTERACTION, { o.el.addEventListener("object3dset", this.onObjectAdded); } }); - AFRAME.scenes[0].systems.interaction.register(this.el.object3D.uuid, this.kids); + AFRAME.scenes[0].systems.interaction.register(this.el.object3D, this.kids, this.data); } }); @@ -44,31 +41,90 @@ AFRAME.registerSystem("interaction", { init() { this.rootToKids = new Map(); this.kidsToRoot = new Map(); + this.rootToData = new Map(); + this.uuidToObject3D = new Map(); }, - register(root, kids) { - this.rootToKids.set(root, kids); + register(root, kids, data) { + this.uuidToObject3D.set(root.uuid, root); + this.rootToKids.set(root.uuid, kids); + this.rootToData.set(root.uuid, data); for (let kid of kids.keys()) { - this.kidsToRoot.set(kid, root); + this.kidsToRoot.set(kid, root.uuid); } }, updateCursorIntersections: function(raw) { const userinput = AFRAME.scenes[0].systems.userinput; if (!raw[0]) { - userinput.toggleSet(sets.cursorHoveringOnInteractable, false); - userinput.toggleSet(sets.cursorHoveringOnNothing, true); this.currentlyHoveredRoot = null; return; } const root = this.kidsToRoot.get(raw[0].object.uuid); if (!root) { - userinput.toggleSet(sets.cursorHoveringOnInteractable, false); - userinput.toggleSet(sets.cursorHoveringOnNothing, true); this.currentlyHoveredRoot = null; return; } - userinput.toggleSet(sets.cursorHoveringOnInteractable, true); - userinput.toggleSet(sets.cursorHoveringOnNothing, false); this.currentlyHoveredRoot = root; + }, + + tick: (function() { + const m = new THREE.Matrix4(); + return function() { + const userinput = AFRAME.scenes[0].systems.userinput; + if (!this.currentlyConstrainedRoot) { + if (!!this.currentlyHoveredRoot && this.rootToData.get(this.currentlyHoveredRoot).offerConstraintWhenHovered) { + const grab = userinput.get(paths.actions.cursor.grab); + if (grab) { + this.currentlyConstrainedRoot = this.currentlyHoveredRoot; + } + } + } else { + const drop = userinput.get(paths.actions.cursor.drop); + if (drop) { + this.currentlyConstrainedRoot = null; + } + } + + if (!!this.currentlyConstrainedRoot) { + const b = document.querySelector("#cursor").object3D; + const a = this.uuidToObject3D.get(this.currentlyConstrainedRoot); + const m = new THREE.Matrix4(); + b.matrixIsModified = true; + b.updateMatrices(); + a.matrixIsModified = true; + a.updateMatrices(); + m.getInverse(a.matrixWorld).multiply(b.matrixWorld); + a.matrix.copy(m); + a.matrixWorldNeedsUpdate = true; + a.childrenNeedMatrixWorldUpdate = true; + a.updateMatrices(); + } + }; + })() +}); + +AFRAME.registerComponent("test-track", { + tick: function() { + const b = document.querySelector("#cursor").object3D; + const a = this.el.object3D; + const m = new THREE.Matrix4(); + b.matrixIsModified = true; + b.updateMatrices(); + a.matrixIsModified = true; + a.updateMatrices(); + m.getInverse(a.parent.matrixWorld).multiply(b.matrixWorld); + a.matrix.copy(m); +// a.matrix.decompose(a.position, a.quaternion, a.scale); + a.matrixWorldNeedsUpdate = true; + a.updateMatrixWorld(); + this.foo = this.foo || 0; + this.foo += 1; + if (this.foo % 100 === 0) { + let s = ""; + for (let i = 0; i < 16; i++) { + s += "" + a.matrixWorld.elements[i] + " " + b.matrixWorld.elements[i] + "\n"; + } + console.log(s); + } } }); diff --git a/src/systems/userinput/resolve-action-sets.js b/src/systems/userinput/resolve-action-sets.js index f2e7a3e5df..a7ae06a448 100644 --- a/src/systems/userinput/resolve-action-sets.js +++ b/src/systems/userinput/resolve-action-sets.js @@ -135,16 +135,40 @@ export function resolveActionSets() { userinput.toggleSet(sets.rightHandTeleporting, rightHandTeleporting); userinput.toggleSet(sets.rightHandHoldingCamera, rightHandHoldingCamera); - userinput.toggleSet(sets.cursorHoveringOnPen, cursorHoveringOnPen); - userinput.toggleSet(sets.cursorHoveringOnCamera, cursorHoveringOnCamera); -// userinput.toggleSet(sets.cursorHoveringOnInteractable, cursorHoveringOnInteractable); - userinput.toggleSet(sets.cursorHoveringOnUI, cursorHoveringOnUI); + const interaction = AFRAME.scenes[0].systems.interaction; + userinput.toggleSet( + sets.cursorHoveringOnPen, + !!interaction.currentlyHoveredRoot && interaction.rootToData.get(interaction.currentlyHoveredRoot).isPen + ); + userinput.toggleSet( + sets.cursorHoveringOnCamera, + !!interaction.currentlyHoveredRoot && interaction.rootToData.get(interaction.currentlyHoveredRoot).isCamera + ); + userinput.toggleSet( + sets.cursorHoveringOnInteractable, + !interaction.currentlyConstrainedRoot && + !!interaction.currentlyHoveredRoot && + interaction.rootToData.get(interaction.currentlyHoveredRoot).offerConstraintWhenHovered + ); + userinput.toggleSet( + sets.cursorHoveringOnUI, + !!interaction.currentlyHoveredRoot && interaction.rootToData.get(interaction.currentlyHoveredRoot).isUI + ); userinput.toggleSet(sets.cursorHoveringOnVideo, cursorHoveringOnVideo); -// userinput.toggleSet(sets.cursorHoveringOnNothing, cursorHoveringOnNothing); - userinput.toggleSet(sets.cursorHoldingPen, cursorHoldingPen); - userinput.toggleSet(sets.cursorHoldingCamera, cursorHoldingCamera); - userinput.toggleSet(sets.cursorHoldingInteractable, cursorHoldingInteractable); - userinput.toggleSet(sets.cursorHoldingUI, cursorHoldingUI); + userinput.toggleSet(sets.cursorHoveringOnNothing, !interaction.currentlyHoveredRoot); + userinput.toggleSet( + sets.cursorHoldingPen, + !!interaction.currentlyConstrainedRoot && interaction.rootToData.get(interaction.currentlyConstrainedRoot).isPen + ); + userinput.toggleSet( + sets.cursorHoldingCamera, + !!interaction.currentlyConstrainedRoot && interaction.rootToData.get(interaction.currentlyConstrainedRoot).isCamera + ); + userinput.toggleSet(sets.cursorHoldingInteractable, !!interaction.currentlyConstrainedRoot); + userinput.toggleSet( + sets.cursorHoldingUI, + !!interaction.currentlyConstrainedRoot && interaction.rootToData.get(interaction.currentlyConstrainedRoot).isUI + ); userinput.toggleSet( sets.inputFocused, document.activeElement.nodeName === "INPUT" || document.activeElement.nodeName === "TEXTAREA" From 5db4da516bb4eae5927e591404892645d7ad8a98 Mon Sep 17 00:00:00 2001 From: johnshaughnessy Date: Thu, 14 Mar 2019 16:24:02 -0700 Subject: [PATCH 10/96] Get cursor working more cleanly --- src/hub.html | 14 +- src/systems/interactions.js | 139 +++++---------- src/systems/userinput/resolve-action-sets.js | 173 ++++--------------- 3 files changed, 85 insertions(+), 241 deletions(-) diff --git a/src/hub.html b/src/hub.html index 3edfde7c1d..fc419c216e 100644 --- a/src/hub.html +++ b/src/hub.html @@ -196,8 +196,8 @@ class="interactable" super-networked-interactable="counter: #media-counter;" ammo-body="type: static; mass: 1;" - grabbable="constraintComponentName: ammo-constraint" - hoverable + threejs-object-descendents-aggregator + offers-remote-constraint hoverable-visuals="cursorController: #cursor-controller" sound__grab="src: #sound_asset-grab; on: grabbed; poolSize: 1; positional: false;" sound__graboff ="src: #sound_asset-grab_off; on: ungrabbed; poolSize: 1; positional: false;" @@ -211,7 +211,8 @@ - +/ diff --git a/src/systems/interactions.js b/src/systems/interactions.js index ab89d1d5f5..bd464a7b5b 100644 --- a/src/systems/interactions.js +++ b/src/systems/interactions.js @@ -27,6 +27,7 @@ AFRAME.registerComponent("threejs-object-descendents-aggregator", { if (!this.descendents.has(o.uuid)) { this.descendents.add(o.uuid); o.el.addEventListener("object3dset", this.addDescendents); + o.el.addEventListener("added", this.addDescendents); } }); THREEJS_OBJECT_DESCENDENTS.associate(this.el, this.descendents); @@ -58,26 +59,24 @@ AFRAME.registerSystem("interaction", { return function() { const userinput = AFRAME.scenes[0].systems.userinput; if (this.rightRemoteConstraintTarget) { +// this.rightRemoteConstraintTarget.object3D.matrixNeedsUpdate = true; + this.rightRemoteConstraintTarget.object3D.updateMatrices(true); + if (userinput.get(paths.actions.cursor.drop)) { + this.rightRemoteConstraintTarget.removeAttribute("ammo-constraint"); this.rightRemoteConstraintTarget = null; + console.log("DROP"); } } else { if (this.rightRemoteHoverTarget && this.rightRemoteHoverTarget.components["offers-remote-constraint"]) { const grab = userinput.get(paths.actions.cursor.grab); if (grab) { this.rightRemoteConstraintTarget = this.rightRemoteHoverTarget; + this.rightRemoteConstraintTarget.setAttribute("ammo-constraint", { target: "#cursor" }); + console.log("GRAB"); } } } - - if (this.rightRemoteConstraintTarget) { - this.cursor = this.cursor || document.querySelector("#cursor").object3D; - const o = this.rightRemoteConstraintTarget.object3D; - this.cursor.updateMatrices(); - o.updateMatrices(); - o.matrix.getInverse(o.parent.matrixWorld).multiply(this.cursor.matrixWorld); - o.matrixWorldNeedsUpdate = true; - } }; })() }); From abec11adb1d4e8d5ceeb9c641a84a6577eeb0d7e Mon Sep 17 00:00:00 2001 From: johnshaughnessy Date: Fri, 15 Mar 2019 12:35:59 -0700 Subject: [PATCH 12/96] Fix initialization bug related to offset-relative-to --- src/hub.html | 9 +++++---- src/scene-entry-manager.js | 16 ++++++++-------- src/systems/interactions.js | 9 +++++---- 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/src/hub.html b/src/hub.html index 8d4b1f41e9..989146a19d 100644 --- a/src/hub.html +++ b/src/hub.html @@ -210,15 +210,16 @@ / diff --git a/src/scene-entry-manager.js b/src/scene-entry-manager.js index a6d9b8b9d4..18afa8837c 100644 --- a/src/scene-entry-manager.js +++ b/src/scene-entry-manager.js @@ -305,7 +305,8 @@ export default class SceneEntryManager { }; _setupMedia = mediaStream => { - const offset = { x: 0, y: 0, z: -1.5 }; + const offset = new THREE.Vector3(0, 0, -1.5); + let camera; const spawnMediaInfrontOfPlayer = (src, contentOrigin) => { const { entity, orientation } = addMedia( src, @@ -315,13 +316,12 @@ export default class SceneEntryManager { true ); - orientation.then(or => { - entity.setAttribute("offset-relative-to", { - target: "#player-camera", - offset, - orientation: or - }); - }); + offset.set(0, 0, -1.5); + camera = camera || document.querySelector("#player-camera").object3D; + camera.updateMatrices(); + camera.localToWorld(offset); + entity.object3D.position.copy(offset); + entity.object3D.matrixNeedsUpdate = true; return entity; }; diff --git a/src/systems/interactions.js b/src/systems/interactions.js index bd464a7b5b..ebc291fc26 100644 --- a/src/systems/interactions.js +++ b/src/systems/interactions.js @@ -1,5 +1,6 @@ import { sets } from "./userinput/sets"; import { paths } from "./userinput/paths"; +const ACTIVATION_STATES = require("aframe-physics-system/src/constants").ACTIVATION_STATES; const THREEJS_OBJECT_DESCENDENTS = { uuidToEl: new Map(), @@ -59,21 +60,21 @@ AFRAME.registerSystem("interaction", { return function() { const userinput = AFRAME.scenes[0].systems.userinput; if (this.rightRemoteConstraintTarget) { -// this.rightRemoteConstraintTarget.object3D.matrixNeedsUpdate = true; - this.rightRemoteConstraintTarget.object3D.updateMatrices(true); + this.rightRemoteConstraintTarget.object3D.matrixNeedsUpdate = true; + //this.rightRemoteConstraintTarget.object3D.updateMatrices(true); if (userinput.get(paths.actions.cursor.drop)) { + this.rightRemoteConstraintTarget.body.forceActivationState(ACTIVATION_STATES.ACTIVE_TAG); this.rightRemoteConstraintTarget.removeAttribute("ammo-constraint"); this.rightRemoteConstraintTarget = null; - console.log("DROP"); } } else { if (this.rightRemoteHoverTarget && this.rightRemoteHoverTarget.components["offers-remote-constraint"]) { const grab = userinput.get(paths.actions.cursor.grab); if (grab) { this.rightRemoteConstraintTarget = this.rightRemoteHoverTarget; + this.rightRemoteConstraintTarget.body.forceActivationState(ACTIVATION_STATES.DISABLE_DEACTIVATION); this.rightRemoteConstraintTarget.setAttribute("ammo-constraint", { target: "#cursor" }); - console.log("GRAB"); } } } From be2778418b24fba6aa5e9100041c54ff8c7e3391 Mon Sep 17 00:00:00 2001 From: johnshaughnessy Date: Fri, 15 Mar 2019 18:34:36 -0700 Subject: [PATCH 13/96] Crawl up when raycasting, rather than crawling down to descendents --- src/hub.html | 2 +- src/systems/interactions.js | 49 +++++++++---------------------------- 2 files changed, 12 insertions(+), 39 deletions(-) diff --git a/src/hub.html b/src/hub.html index 989146a19d..6fca246d6a 100644 --- a/src/hub.html +++ b/src/hub.html @@ -212,7 +212,7 @@ { - if (!this.descendents.has(o.uuid)) { - this.descendents.add(o.uuid); - o.el.addEventListener("object3dset", this.addDescendents); - o.el.addEventListener("added", this.addDescendents); - } - }); - THREEJS_OBJECT_DESCENDENTS.associate(this.el, this.descendents); + THREEJS_HOVER_TARGETS.set(this.el.object3D.uuid, this.el); } }); -AFRAME.registerComponent("offers-remote-constraint", {}); -AFRAME.registerComponent("is-ui", {}); - AFRAME.registerSystem("interaction", { init: function() { this.rightRemoteHoverTarget = null; @@ -48,12 +27,7 @@ AFRAME.registerSystem("interaction", { this.rightRemoteHoverTarget = null; return; } - const rootUuid = THREEJS_OBJECT_DESCENDENTS.descendentsToRoot.get(raw[0].object.uuid); - if (!rootUuid) { - this.rightRemoteHoverTarget = null; - return; - } - this.rightRemoteHoverTarget = THREEJS_OBJECT_DESCENDENTS.uuidToEl.get(rootUuid); + this.rightRemoteHoverTarget = findRemoteHoverTarget(raw[0].object); }, tick: (function() { @@ -61,7 +35,6 @@ AFRAME.registerSystem("interaction", { const userinput = AFRAME.scenes[0].systems.userinput; if (this.rightRemoteConstraintTarget) { this.rightRemoteConstraintTarget.object3D.matrixNeedsUpdate = true; - //this.rightRemoteConstraintTarget.object3D.updateMatrices(true); if (userinput.get(paths.actions.cursor.drop)) { this.rightRemoteConstraintTarget.body.forceActivationState(ACTIVATION_STATES.ACTIVE_TAG); From 6b4b00a9e8eb317d75cb98255ad51493eae8add8 Mon Sep 17 00:00:00 2001 From: johnshaughnessy Date: Sat, 16 Mar 2019 11:32:58 -0700 Subject: [PATCH 14/96] Cursor works with duck and camera. Not pen yet. --- src/components/hover-menu.js | 16 +++-- src/components/sticky-object.js | 20 +----- src/components/visibility-while-frozen.js | 2 +- src/hub.html | 69 ++++++++++++++++++-- src/systems/interactions.js | 61 +++++++++++++---- src/systems/userinput/resolve-action-sets.js | 7 +- 6 files changed, 130 insertions(+), 45 deletions(-) diff --git a/src/components/hover-menu.js b/src/components/hover-menu.js index 05e7f99ea3..de430d759d 100644 --- a/src/components/hover-menu.js +++ b/src/components/hover-menu.js @@ -40,7 +40,13 @@ AFRAME.registerComponent("hover-menu", { }, onHoverStateChange(e) { - this.hovering = e.type === "hover-start"; + if (!e.detail === "hovered") return; + this.hovering = false; + this.el.object3D.traverse(o => { + if (o.el && o.el.is("hovered")) { + this.hovering = true; + } + }); this.applyHoverState(); }, @@ -53,15 +59,15 @@ AFRAME.registerComponent("hover-menu", { }, play() { - this.el.addEventListener("hover-start", this.onHoverStateChange); - this.el.addEventListener("hover-end", this.onHoverStateChange); + this.el.parentNode.addEventListener("stateadded", this.onHoverStateChange); + this.el.parentNode.addEventListener("stateremoved", this.onHoverStateChange); this.el.sceneEl.addEventListener("stateadded", this.onFrozenStateChange); this.el.sceneEl.addEventListener("stateremoved", this.onFrozenStateChange); }, pause() { - this.el.removeEventListener("hover-start", this.onHoverStateChange); - this.el.removeEventListener("hover-end", this.onHoverStateChange); + this.el.parentNode.removeEventListener("stateadded", this.onHoverStateChange); + this.el.parentNode.removeEventListener("stateremoved", this.onHoverStateChange); this.el.sceneEl.removeEventListener("stateadded", this.onFrozenStateChange); this.el.sceneEl.removeEventListener("stateremoved", this.onFrozenStateChange); } diff --git a/src/components/sticky-object.js b/src/components/sticky-object.js index abde068940..dc72bdda82 100644 --- a/src/components/sticky-object.js +++ b/src/components/sticky-object.js @@ -1,10 +1,8 @@ import { getLastWorldPosition, getLastWorldQuaternion } from "../utils/three-utils"; -//TODO: decide on what these collision filters should actuallly be called, and move these somewhere else const COLLISION_LAYERS = require("../constants").COLLISION_LAYERS; /* global THREE, AFRAME */ AFRAME.registerComponent("sticky-object", { - dependencies: ["ammo-body"], schema: { autoLockOnLoad: { default: false }, @@ -13,15 +11,10 @@ AFRAME.registerComponent("sticky-object", { }, init() { - this._onGrab = this._onGrab.bind(this); - this._onRelease = this._onRelease.bind(this); this._onBodyLoaded = this._onBodyLoaded.bind(this); }, play() { - this.el.addEventListener("grab-start", this._onGrab); - this.el.addEventListener("grab-end", this._onRelease); - if (this.hasSetupBodyLoaded) return; this.hasSetupBodyLoaded = true; @@ -32,11 +25,6 @@ AFRAME.registerComponent("sticky-object", { } }, - pause() { - this.el.removeEventListener("grab-start", this._onGrab); - this.el.removeEventListener("grab-end", this._onRelease); - }, - setLocked(locked) { if (this.el.components.networked && !NAF.utils.isMine(this.el)) return; @@ -50,9 +38,7 @@ AFRAME.registerComponent("sticky-object", { } }, - _onRelease() { - // Happens if the object is still being held by another hand - if (this.el.is("grabbed")) return; + onRelease() { if ( this.data.autoLockOnRelease && (this.data.autoLockSpeedLimit === 0 || @@ -64,9 +50,7 @@ AFRAME.registerComponent("sticky-object", { this.el.setAttribute("ammo-body", { collisionFilterGroup: COLLISION_LAYERS.DYNAMIC_OBJECTS }); }, - _onGrab() { - if (!this.el.components.grabbable || this.el.components.grabbable.data.maxGrabbers === 0) return; - + onGrab() { this.el.setAttribute("ammo-body", { collisionFilterGroup: this.locked ? COLLISION_LAYERS.STICKY_OBJECTS : COLLISION_LAYERS.DYNAMIC_OBJECTS }); diff --git a/src/components/visibility-while-frozen.js b/src/components/visibility-while-frozen.js index 7963652185..c4eeb73d8c 100644 --- a/src/components/visibility-while-frozen.js +++ b/src/components/visibility-while-frozen.js @@ -23,7 +23,7 @@ AFRAME.registerComponent("visibility-while-frozen", { let hoverableSearch = this.el; while (hoverableSearch !== document) { - if (hoverableSearch.getAttribute("hoverable") !== null) { + if (hoverableSearch.getAttribute("is-remote-hover-target") !== null) { this.hoverable = hoverableSearch; break; } diff --git a/src/hub.html b/src/hub.html index 6fca246d6a..0d8a190052 100644 --- a/src/hub.html +++ b/src/hub.html @@ -196,8 +196,7 @@ class="interactable" super-networked-interactable="counter: #media-counter;" ammo-body="type: static; mass: 1;" - threejs-object-descendents-aggregator - offers-remote-constraint + is-remote-hover-target hoverable-visuals="cursorController: #cursor-controller" sound__grab="src: #sound_asset-grab; on: grabbed; poolSize: 1; positional: false;" sound__graboff ="src: #sound_asset-grab_off; on: ungrabbed; poolSize: 1; positional: false;" @@ -216,11 +215,48 @@ offers-remote-constraint destroy-at-extreme-distances ammo-body="type: dynamic; mass: 1;" - sticky-object="autoLockOnRelease; true; autoLockOnLoad: true;" + sticky-object="autoLockOnRelease: true; autoLockOnLoad: true;" destroy-at-extreme-distances set-yxz-order matrix-auto-update + position-at-box-shape-border__freeze="target:.freeze-menu;" > + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -228,7 +264,7 @@ Date: Sat, 16 Mar 2019 11:56:49 -0700 Subject: [PATCH 15/96] Get pen working with cursor --- src/components/tools/pen.js | 8 +++----- src/systems/interactions.js | 14 ++++++++++++++ src/systems/userinput/resolve-action-sets.js | 2 +- 3 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/components/tools/pen.js b/src/components/tools/pen.js index afdc2556cc..b32032be08 100644 --- a/src/components/tools/pen.js +++ b/src/components/tools/pen.js @@ -103,14 +103,12 @@ AFRAME.registerComponent("pen", { }, tick(t, dt) { - return; // replace-super-hands - const grabber = this.el.parentNode.components.grabbable.grabbers[0]; const userinput = AFRAME.scenes[0].systems.userinput; getLastWorldPosition(this.el.object3D, this.worldPosition); - if (grabber && pathsMap[grabber.id]) { - const paths = pathsMap[grabber.id]; + if (this.grabberId&& pathsMap[this.grabberId]) { + const paths = pathsMap[this.grabberId]; if (userinput.get(paths.startDrawing)) { this._startDraw(); } @@ -150,7 +148,7 @@ AFRAME.registerComponent("pen", { this.timeSinceLastDraw = time % this.data.drawFrequency; } - if (this.currentDrawing && !grabber) { + if (this.currentDrawing && !this.grabberId) { this._endDraw(); } }, diff --git a/src/systems/interactions.js b/src/systems/interactions.js index 8046c3334b..ad2c74d23b 100644 --- a/src/systems/interactions.js +++ b/src/systems/interactions.js @@ -23,6 +23,7 @@ AFRAME.registerSystem("interaction", { this.rightRemoteHoverTarget = null; this.rightRemoteConstraintTarget = null; this.grabbedUI = null; + this.grabbedPen = null; this.cursor = document.querySelector("#cursor"); }, updateCursorIntersections: function(raw) { @@ -48,11 +49,13 @@ AFRAME.registerSystem("interaction", { const userinput = AFRAME.scenes[0].systems.userinput; const drop = userinput.get(paths.actions.cursor.drop); const grab = userinput.get(paths.actions.cursor.grab); + const removePen = userinput.get(paths.actions.pen.remove); if (drop && this.grabbedUI) { this.grabbedUI.emit("grab-end", { hand: this.cursor }); this.grabbedUI = null; } + if (this.rightRemoteConstraintTarget) { this.rightRemoteConstraintTarget.object3D.matrixNeedsUpdate = true; @@ -62,6 +65,11 @@ AFRAME.registerSystem("interaction", { stickyObject.onRelease(); } + if (this.grabbedPen) { + this.grabbedPen.children[0].components["pen"].grabberId = null; + this.grabbedPen = null; + } + this.rightRemoteConstraintTarget.body.forceActivationState(ACTIVATION_STATES.ACTIVE_TAG); this.rightRemoteConstraintTarget.removeAttribute("ammo-constraint"); this.rightRemoteConstraintTarget = null; @@ -76,6 +84,12 @@ AFRAME.registerSystem("interaction", { this.grabbedUI = this.rightRemoteHoverTarget; } + const isPen = this.rightRemoteHoverTarget.components["is-pen"]; + if (isPen) { + this.rightRemoteHoverTarget.children[0].components["pen"].grabberId = "cursor"; + this.grabbedPen = this.rightRemoteHoverTarget; + } + const offersRemoteConstraint = this.rightRemoteHoverTarget.components["offers-remote-constraint"]; if (offersRemoteConstraint) { this.rightRemoteConstraintTarget = this.rightRemoteHoverTarget; diff --git a/src/systems/userinput/resolve-action-sets.js b/src/systems/userinput/resolve-action-sets.js index 0bb4ea0857..e9e34f2950 100644 --- a/src/systems/userinput/resolve-action-sets.js +++ b/src/systems/userinput/resolve-action-sets.js @@ -30,7 +30,7 @@ export function resolveActionSets() { const rightRemoteConstraintTarget = interaction.rightRemoteConstraintTarget; const rightRemoteHoverTarget = !rightRemoteConstraintTarget && interaction.rightRemoteHoverTarget; userinput.toggleSet(sets.cursorHoveringOnNothing, !rightRemoteConstraintTarget && !rightRemoteHoverTarget); - userinput.toggleSet(sets.cursorHoveringOnPen, rightRemoteHoverTarget && !!rightRemoteHoverTarget.components["pen"]); + userinput.toggleSet(sets.cursorHoveringOnPen, rightRemoteHoverTarget && !!rightRemoteHoverTarget.components["is-pen"]); userinput.toggleSet( sets.cursorHoveringOnCamera, rightRemoteHoverTarget && !!rightRemoteHoverTarget.components["camera-tool"] From 42bbb81093388e79dcff1509cc88340b6e1966aa Mon Sep 17 00:00:00 2001 From: johnshaughnessy Date: Sat, 16 Mar 2019 12:00:39 -0700 Subject: [PATCH 16/96] Remove expired notes --- notes.txt | 9 --------- 1 file changed, 9 deletions(-) delete mode 100644 notes.txt diff --git a/notes.txt b/notes.txt deleted file mode 100644 index 62700ab032..0000000000 --- a/notes.txt +++ /dev/null @@ -1,9 +0,0 @@ -I would like to replace super-hands with a system that handles interactions. -I want the replacement to make minimal use of aframe, so that we can eventually drop it. -I want the replacement to make minimal use of events, both because of performance reasons and to avoid the additional complexity dealing with the DOM brings to the problem. - -The first attempt can be seen in ca515a116928df3d164275684e20244c8abe3ec6 . The problem I encountered in this attempt is in trying to match the three.js object deep within th duck model's hierarchy that the cursor intersects with the aframe element as defined in the `interactable-media` template. This approach feels extremely error prone and confusing, so I want to think of another. - -The second attempt can be seen in a9fb0fca8a01414241f51f8e0bd17f824c8bae40 . I "solved" the problem above by grouping all threejs object3D's beneath the one associated with an entity with a given "aggregator" component on it. This works for the simple case of hovering, but I suspect that I will quickly have to change the menu systems such that the menus are not children of the object in order to continue this way. Alternatively I can keep track of which object3D's are associated with a menu and disallow the aggregation of those object3D's when trying to hover on the duck rather than the duck's menu buttons, but this seems complicated and error prone, so I am not sure I want to go down that route. I think the next steps are to start naively implementing some of the features we like that super-hands helps us provide and pay attention to and try to fix any issues that come up as I go along. - -I have an unused schema property in this attempt called `offerConstraintWhenHovered`. The thinking here is that I don't want to have a generic "hovering" -- I want the state of the interaction system to be more granular than that. What you're hovering on (rotation button vs volume slider vs duck) and how you're "hovering" (via pointing a cursor at something or intersecting it with your hand) DOES matter to us and to the input system's action sets, so I'd like to model the replacement for "hovering" to respect that. Here the (unimplemented) idea I had is that one kind of hovering will be for changing the action sets to be in a state where creating a physics constraint is a button press away. Thus when you "hover" onto something marked as offerConstraintWhenHovered, well, that's what the thing will do -- you'll end up activating an action set whose associated bindings have a binding written to createPhysicsConstraintOnCursor(/Hand) action path. From 1b6d9216afd71574fb4c77e8c8ea280cf28b186f Mon Sep 17 00:00:00 2001 From: johnshaughnessy Date: Sat, 16 Mar 2019 15:50:02 -0700 Subject: [PATCH 17/96] Fix issue where pen did not spawn on the cursor --- .../super-networked-interactable.js | 31 ++++++------------- src/components/super-spawner.js | 10 +++--- src/components/tools/pen.js | 2 +- src/systems/interactions.js | 26 +++++++++++++--- src/systems/userinput/resolve-action-sets.js | 7 +++-- 5 files changed, 41 insertions(+), 35 deletions(-) diff --git a/src/components/super-networked-interactable.js b/src/components/super-networked-interactable.js index e3184ce276..37c5ed05b0 100644 --- a/src/components/super-networked-interactable.js +++ b/src/components/super-networked-interactable.js @@ -31,8 +31,6 @@ AFRAME.registerComponent("super-networked-interactable", { this.system = this.el.sceneEl.systems.physics; this.counter = this.data.counter.components["networked-counter"]; this.hand = null; - this.currentScale = new THREE.Vector3(); - this.currentScale.copy(this.el.getAttribute("scale")); NAF.utils.getNetworkedEntity(this.el).then(networkedEl => { this.networkedEl = networkedEl; @@ -44,12 +42,8 @@ AFRAME.registerComponent("super-networked-interactable", { } }); - this._onGrabStart = this._onGrabStart.bind(this); - this._onGrabEnd = this._onGrabEnd.bind(this); this._onOwnershipLost = this._onOwnershipLost.bind(this); this._syncCounterRegistration = this._syncCounterRegistration.bind(this); - this.el.addEventListener("grab-start", this._onGrabStart); - this.el.addEventListener("grab-end", this._onGrabEnd); this.el.addEventListener("pinned", this._syncCounterRegistration); this.el.addEventListener("unpinned", this._syncCounterRegistration); this.el.addEventListener("ownership-lost", this._onOwnershipLost); @@ -58,16 +52,12 @@ AFRAME.registerComponent("super-networked-interactable", { remove: function() { this.counter.deregister(this.el); - this.el.removeEventListener("grab-start", this._onGrabStart); - this.el.removeEventListener("grab-end", this._onGrabEnd); this.el.removeEventListener("ownership-lost", this._onOwnershipLost); this.system.removeComponent(this); }, - _onGrabStart: function(e) { - if (!this.el.components.grabbable || this.el.components.grabbable.data.maxGrabbers === 0) return; - - this.hand = e.detail.hand; + onGrabStart: function(hand) { + this.hand = hand; this.hand.emit("haptic_pulse", { intensity: "high" }); if (this.networkedEl) { if (!NAF.utils.isMine(this.networkedEl)) { @@ -83,11 +73,10 @@ AFRAME.registerComponent("super-networked-interactable", { this.el.body.forceActivationState(ACTIVATION_STATES.DISABLE_DEACTIVATION); } } - this.currentScale.copy(this.el.getAttribute("scale")); }, - _onGrabEnd: function(e) { - if (e.detail.hand) e.detail.hand.emit("haptic_pulse", { intensity: "high" }); + onGrabEnd: function(hand) { + if (hand) hand.emit("haptic_pulse", { intensity: "high" }); this.el.body.forceActivationState(ACTIVATION_STATES.ACTIVE_TAG); }, @@ -99,9 +88,9 @@ AFRAME.registerComponent("super-networked-interactable", { }, _changeScale: function(delta) { - if (delta && this.el.is("grabbed") && this.el.components.hasOwnProperty("stretchable")) { - this.currentScale.addScalar(delta).clampScalar(this.data.minScale, this.data.maxScale); - this.el.setAttribute("scale", this.currentScale); + if (delta) { + this.el.object3D.updateMatrices(); + this.el.object3D.scale.addScalar(delta).clampScalar(this.data.minScale, this.data.maxScale); this.el.object3D.matrixNeedsUpdate = true; } }, @@ -120,11 +109,9 @@ AFRAME.registerComponent("super-networked-interactable", { }, tick: function() { - return; // replace-super-hands - const grabber = this.el.components.grabbable.grabbers[0]; - if (!(grabber && pathsMap[grabber.id])) return; + if (!(this.grabberId && pathsMap[this.grabberId])) return; const userinput = AFRAME.scenes[0].systems.userinput; - this._changeScale(userinput.get(pathsMap[grabber.id].scaleGrabbedGrabbable)); + this._changeScale(userinput.get(pathsMap[this.grabberId].scaleGrabbedGrabbable)); } }); diff --git a/src/components/super-spawner.js b/src/components/super-spawner.js index 8db063f65a..3aee938364 100644 --- a/src/components/super-spawner.js +++ b/src/components/super-spawner.js @@ -54,8 +54,8 @@ AFRAME.registerComponent("super-spawner", { /** * The events to emit for programmatically grabbing and releasing objects */ - grabEvents: { default: ["cursor-grab", "primary_hand_grab"] }, - releaseEvents: { default: ["cursor-release", "primary_hand_release"] }, + grabEvents: { default: ["grab-start"] }, + releaseEvents: { default: [] }, /** * The spawner will become invisible and ungrabbable for this ammount of time after being grabbed. This can prevent rapidly spawning objects. @@ -135,7 +135,7 @@ AFRAME.registerComponent("super-spawner", { const rightPose = userinput.get(paths.actions.rightHand.pose); const controllerCount = leftPose && rightPose ? 2 : leftPose || rightPose ? 1 : 0; const using6DOF = controllerCount > 1 && this.el.sceneEl.is("vr-mode"); - const hand = using6DOF ? this.data.superHand : this.data.cursorSuperHand; + const hand = this.data.cursorSuperHand; //using6DOF ? this.data.superHand : this.data.cursorSuperHand; if (this.cooldownTimeout || !hand) { return; @@ -177,9 +177,7 @@ AFRAME.registerComponent("super-spawner", { entity.components["ammo-body"].syncToPhysics(); if (!using6DOF) { - for (let i = 0; i < this.data.grabEvents.length; i++) { - hand.emit(this.data.grabEvents[i], { targetEntity: entity }); - } + AFRAME.scenes[0].systems.interaction.weWantToGrab = true; } }, diff --git a/src/components/tools/pen.js b/src/components/tools/pen.js index b32032be08..d279ff3e77 100644 --- a/src/components/tools/pen.js +++ b/src/components/tools/pen.js @@ -107,7 +107,7 @@ AFRAME.registerComponent("pen", { getLastWorldPosition(this.el.object3D, this.worldPosition); - if (this.grabberId&& pathsMap[this.grabberId]) { + if (this.grabberId && pathsMap[this.grabberId]) { const paths = pathsMap[this.grabberId]; if (userinput.get(paths.startDrawing)) { this._startDraw(); diff --git a/src/systems/interactions.js b/src/systems/interactions.js index ad2c74d23b..aad72cd9b7 100644 --- a/src/systems/interactions.js +++ b/src/systems/interactions.js @@ -25,6 +25,7 @@ AFRAME.registerSystem("interaction", { this.grabbedUI = null; this.grabbedPen = null; this.cursor = document.querySelector("#cursor"); + this.weWantToGrab = false; }, updateCursorIntersections: function(raw) { const hasIntersection = raw[0]; @@ -51,9 +52,11 @@ AFRAME.registerSystem("interaction", { const grab = userinput.get(paths.actions.cursor.grab); const removePen = userinput.get(paths.actions.pen.remove); + let didGrabEndThisFrame = false; if (drop && this.grabbedUI) { this.grabbedUI.emit("grab-end", { hand: this.cursor }); this.grabbedUI = null; + didGrabEndThisFrame = true; } if (this.rightRemoteConstraintTarget) { @@ -65,22 +68,30 @@ AFRAME.registerSystem("interaction", { stickyObject.onRelease(); } + const superNetworkedInteractable = this.rightRemoteHoverTarget.components["super-networked-interactable"]; + if (superNetworkedInteractable) { + superNetworkedInteractable.onGrabEnd(this.cursor); + } + if (this.grabbedPen) { this.grabbedPen.children[0].components["pen"].grabberId = null; this.grabbedPen = null; } - this.rightRemoteConstraintTarget.body.forceActivationState(ACTIVATION_STATES.ACTIVE_TAG); + if (!didGrabEndThisFrame) { + this.rightRemoteConstraintTarget.emit("grab-end", { hand: this.cursor }); + didGrabEndThisFrame = true; + } this.rightRemoteConstraintTarget.removeAttribute("ammo-constraint"); this.rightRemoteConstraintTarget = null; } } else { if (this.rightRemoteHoverTarget) { const grab = userinput.get(paths.actions.cursor.grab); - if (grab) { + if (grab || this.weWantToGrab) { + this.weWantToGrab = false; const isUI = this.rightRemoteHoverTarget.components["is-ui"]; if (isUI) { - this.rightRemoteHoverTarget.emit("grab-start", { hand: this.cursor }); this.grabbedUI = this.rightRemoteHoverTarget; } @@ -93,13 +104,20 @@ AFRAME.registerSystem("interaction", { const offersRemoteConstraint = this.rightRemoteHoverTarget.components["offers-remote-constraint"]; if (offersRemoteConstraint) { this.rightRemoteConstraintTarget = this.rightRemoteHoverTarget; - this.rightRemoteConstraintTarget.body.forceActivationState(ACTIVATION_STATES.DISABLE_DEACTIVATION); this.rightRemoteConstraintTarget.setAttribute("ammo-constraint", { target: "#cursor" }); const stickyObject = this.rightRemoteHoverTarget.components["sticky-object"]; if (stickyObject) { stickyObject.onGrab(); } + const superNetworkedInteractable = this.rightRemoteHoverTarget.components["super-networked-interactable"]; + if (superNetworkedInteractable) { + superNetworkedInteractable.grabberId = "cursor"; + superNetworkedInteractable.onGrabStart(this.cursor); + } + } + if (isUI || isPen || offersRemoteConstraint) { + this.rightRemoteHoverTarget.emit("grab-start", { hand: this.cursor }); } } } diff --git a/src/systems/userinput/resolve-action-sets.js b/src/systems/userinput/resolve-action-sets.js index e9e34f2950..96cbf825b2 100644 --- a/src/systems/userinput/resolve-action-sets.js +++ b/src/systems/userinput/resolve-action-sets.js @@ -30,7 +30,10 @@ export function resolveActionSets() { const rightRemoteConstraintTarget = interaction.rightRemoteConstraintTarget; const rightRemoteHoverTarget = !rightRemoteConstraintTarget && interaction.rightRemoteHoverTarget; userinput.toggleSet(sets.cursorHoveringOnNothing, !rightRemoteConstraintTarget && !rightRemoteHoverTarget); - userinput.toggleSet(sets.cursorHoveringOnPen, rightRemoteHoverTarget && !!rightRemoteHoverTarget.components["is-pen"]); + userinput.toggleSet( + sets.cursorHoveringOnPen, + rightRemoteHoverTarget && !!rightRemoteHoverTarget.components["is-pen"] + ); userinput.toggleSet( sets.cursorHoveringOnCamera, rightRemoteHoverTarget && !!rightRemoteHoverTarget.components["camera-tool"] @@ -45,7 +48,6 @@ export function resolveActionSets() { rightRemoteHoverTarget && !!rightRemoteHoverTarget.components["media-video"] ); - userinput.toggleSet(sets.cursorHoldingInteractable, !!rightRemoteConstraintTarget); userinput.toggleSet( sets.cursorHoldingPen, rightRemoteConstraintTarget && !!rightRemoteConstraintTarget.components["is-pen"] @@ -55,6 +57,7 @@ export function resolveActionSets() { rightRemoteConstraintTarget && !!rightRemoteConstraintTarget.components["camera-tool"] ); userinput.toggleSet(sets.cursorHoldingUI, !!interaction.grabbedUI); + userinput.toggleSet(sets.cursorHoldingInteractable, !!rightRemoteConstraintTarget); userinput.toggleSet( sets.inputFocused, document.activeElement.nodeName === "INPUT" || document.activeElement.nodeName === "TEXTAREA" From 1205d84715ab323e7e20a2478af4fefe06dd74a4 Mon Sep 17 00:00:00 2001 From: johnshaughnessy Date: Sat, 16 Mar 2019 16:13:00 -0700 Subject: [PATCH 18/96] Remove some uses of grab-start and grab-end events --- src/systems/interactions.js | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/src/systems/interactions.js b/src/systems/interactions.js index aad72cd9b7..4caee4daf8 100644 --- a/src/systems/interactions.js +++ b/src/systems/interactions.js @@ -75,13 +75,19 @@ AFRAME.registerSystem("interaction", { if (this.grabbedPen) { this.grabbedPen.children[0].components["pen"].grabberId = null; + if (!didGrabEndThisFrame) { + this.grabbedPen.emit("grab-end", { hand: this.cursor }); + didGrabEndThisFrame = true; + } this.grabbedPen = null; } - if (!didGrabEndThisFrame) { + const isSuperSpawner = this.rightRemoteHoverTarget.components["super-spawner"]; + if (isSuperSpawner && !didGrabEndThisFrame) { this.rightRemoteConstraintTarget.emit("grab-end", { hand: this.cursor }); didGrabEndThisFrame = true; } + this.rightRemoteConstraintTarget.removeAttribute("ammo-constraint"); this.rightRemoteConstraintTarget = null; } @@ -116,7 +122,9 @@ AFRAME.registerSystem("interaction", { superNetworkedInteractable.onGrabStart(this.cursor); } } - if (isUI || isPen || offersRemoteConstraint) { + + const isSuperSpawner = this.rightRemoteHoverTarget.components["super-spawner"]; + if (isUI || isPen || isSuperSpawner) { this.rightRemoteHoverTarget.emit("grab-start", { hand: this.cursor }); } } From 867ad0ebf1589180fb2fff368d3ad77dd9dcac46 Mon Sep 17 00:00:00 2001 From: johnshaughnessy Date: Sat, 16 Mar 2019 16:34:20 -0700 Subject: [PATCH 19/96] Don't use grab-start and grab-end for pen --- src/systems/interactions.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/systems/interactions.js b/src/systems/interactions.js index 4caee4daf8..5116e62ab5 100644 --- a/src/systems/interactions.js +++ b/src/systems/interactions.js @@ -75,10 +75,6 @@ AFRAME.registerSystem("interaction", { if (this.grabbedPen) { this.grabbedPen.children[0].components["pen"].grabberId = null; - if (!didGrabEndThisFrame) { - this.grabbedPen.emit("grab-end", { hand: this.cursor }); - didGrabEndThisFrame = true; - } this.grabbedPen = null; } @@ -124,7 +120,7 @@ AFRAME.registerSystem("interaction", { } const isSuperSpawner = this.rightRemoteHoverTarget.components["super-spawner"]; - if (isUI || isPen || isSuperSpawner) { + if (isUI || isSuperSpawner) { this.rightRemoteHoverTarget.emit("grab-start", { hand: this.cursor }); } } From adc35343c9cc71a57084bddc80d08a6625dee986 Mon Sep 17 00:00:00 2001 From: johnshaughnessy Date: Sat, 16 Mar 2019 16:52:04 -0700 Subject: [PATCH 20/96] Map the hoverable components in gltf to is-remote-hover-target --- src/gltf-component-mappings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gltf-component-mappings.js b/src/gltf-component-mappings.js index fdd41040e3..47894dd2a1 100644 --- a/src/gltf-component-mappings.js +++ b/src/gltf-component-mappings.js @@ -86,7 +86,7 @@ AFRAME.GLTFModelPlus.registerComponent("visible", "visible", (el, componentName, } }); AFRAME.GLTFModelPlus.registerComponent("spawn-point", "spawn-point"); -AFRAME.GLTFModelPlus.registerComponent("hoverable", "hoverable"); +AFRAME.GLTFModelPlus.registerComponent("hoverable", "is-remote-hover-target"); AFRAME.GLTFModelPlus.registerComponent("sticky-zone", "sticky-zone"); AFRAME.GLTFModelPlus.registerComponent("nav-mesh", "nav-mesh", (el, _componentName, componentData) => { const nav = AFRAME.scenes[0].systems.nav; From 67bf452ebfdec47c7d7b6e8abd4f26889fd4ada6 Mon Sep 17 00:00:00 2001 From: johnshaughnessy Date: Sat, 16 Mar 2019 16:59:03 -0700 Subject: [PATCH 21/96] Replace hoverable with is-remote-hover-target in spawner --- src/gltf-component-mappings.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gltf-component-mappings.js b/src/gltf-component-mappings.js index 47894dd2a1..0b38737f0e 100644 --- a/src/gltf-component-mappings.js +++ b/src/gltf-component-mappings.js @@ -207,7 +207,7 @@ AFRAME.GLTFModelPlus.registerComponent("spawner", "spawner", (el, componentName, type: TYPES.STATIC, collisionFlags: COLLISION_FLAGS.NO_CONTACT_RESPONSE }); - el.setAttribute("hoverable", ""); + el.setAttribute("is-remote-hover-target", ""); }); const publicComponents = { From 5e013034982c7a04af29b9b10df9a0f4145736f5 Mon Sep 17 00:00:00 2001 From: johnshaughnessy Date: Mon, 18 Mar 2019 10:02:50 -0700 Subject: [PATCH 22/96] Simplify control flow a bit --- src/systems/interactions.js | 60 +++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 32 deletions(-) diff --git a/src/systems/interactions.js b/src/systems/interactions.js index 5116e62ab5..5fead223c4 100644 --- a/src/systems/interactions.js +++ b/src/systems/interactions.js @@ -50,7 +50,6 @@ AFRAME.registerSystem("interaction", { const userinput = AFRAME.scenes[0].systems.userinput; const drop = userinput.get(paths.actions.cursor.drop); const grab = userinput.get(paths.actions.cursor.grab); - const removePen = userinput.get(paths.actions.pen.remove); let didGrabEndThisFrame = false; if (drop && this.grabbedUI) { @@ -88,41 +87,38 @@ AFRAME.registerSystem("interaction", { this.rightRemoteConstraintTarget = null; } } else { - if (this.rightRemoteHoverTarget) { - const grab = userinput.get(paths.actions.cursor.grab); - if (grab || this.weWantToGrab) { - this.weWantToGrab = false; - const isUI = this.rightRemoteHoverTarget.components["is-ui"]; - if (isUI) { - this.grabbedUI = this.rightRemoteHoverTarget; - } + if (this.rightRemoteHoverTarget && (grab || this.weWantToGrab)) { + this.weWantToGrab = false; + const isUI = this.rightRemoteHoverTarget.components["is-ui"]; + if (isUI) { + this.grabbedUI = this.rightRemoteHoverTarget; + } - const isPen = this.rightRemoteHoverTarget.components["is-pen"]; - if (isPen) { - this.rightRemoteHoverTarget.children[0].components["pen"].grabberId = "cursor"; - this.grabbedPen = this.rightRemoteHoverTarget; - } + const isPen = this.rightRemoteHoverTarget.components["is-pen"]; + if (isPen) { + this.rightRemoteHoverTarget.children[0].components["pen"].grabberId = "cursor"; + this.grabbedPen = this.rightRemoteHoverTarget; + } - const offersRemoteConstraint = this.rightRemoteHoverTarget.components["offers-remote-constraint"]; - if (offersRemoteConstraint) { - this.rightRemoteConstraintTarget = this.rightRemoteHoverTarget; - this.rightRemoteConstraintTarget.setAttribute("ammo-constraint", { target: "#cursor" }); - - const stickyObject = this.rightRemoteHoverTarget.components["sticky-object"]; - if (stickyObject) { - stickyObject.onGrab(); - } - const superNetworkedInteractable = this.rightRemoteHoverTarget.components["super-networked-interactable"]; - if (superNetworkedInteractable) { - superNetworkedInteractable.grabberId = "cursor"; - superNetworkedInteractable.onGrabStart(this.cursor); - } - } + const offersRemoteConstraint = this.rightRemoteHoverTarget.components["offers-remote-constraint"]; + if (offersRemoteConstraint) { + this.rightRemoteConstraintTarget = this.rightRemoteHoverTarget; + this.rightRemoteConstraintTarget.setAttribute("ammo-constraint", { target: "#cursor" }); - const isSuperSpawner = this.rightRemoteHoverTarget.components["super-spawner"]; - if (isUI || isSuperSpawner) { - this.rightRemoteHoverTarget.emit("grab-start", { hand: this.cursor }); + const stickyObject = this.rightRemoteHoverTarget.components["sticky-object"]; + if (stickyObject) { + stickyObject.onGrab(); } + const superNetworkedInteractable = this.rightRemoteHoverTarget.components["super-networked-interactable"]; + if (superNetworkedInteractable) { + superNetworkedInteractable.grabberId = "cursor"; + superNetworkedInteractable.onGrabStart(this.cursor); + } + } + + const isSuperSpawner = this.rightRemoteHoverTarget.components["super-spawner"]; + if (isUI || isSuperSpawner) { + this.rightRemoteHoverTarget.emit("grab-start", { hand: this.cursor }); } } } From 985ce03568ead098f0982f379969140dadcae737 Mon Sep 17 00:00:00 2001 From: johnshaughnessy Date: Mon, 18 Mar 2019 10:36:16 -0700 Subject: [PATCH 23/96] Disable scalabe-when-grabbed --- src/components/scalable-when-grabbed.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/scalable-when-grabbed.js b/src/components/scalable-when-grabbed.js index ef0bc1dfd8..3cd7f15fc3 100644 --- a/src/components/scalable-when-grabbed.js +++ b/src/components/scalable-when-grabbed.js @@ -8,6 +8,7 @@ const grabberToPath = { AFRAME.registerComponent("scalable-when-grabbed", { tick: function() { + return; // no grabbable component const grabber = this.el.components.grabbable.grabbers[0]; if (!grabber) return; From e5f123492a08f68ccf6634fdb9776b1d03fc9115 Mon Sep 17 00:00:00 2001 From: johnshaughnessy Date: Mon, 18 Mar 2019 11:11:27 -0700 Subject: [PATCH 24/96] Move cursor intersection logic to cursor-controller --- src/components/cursor-controller.js | 64 +++++++++++--------- src/systems/interactions.js | 63 ++++++------------- src/systems/userinput/resolve-action-sets.js | 4 +- 3 files changed, 56 insertions(+), 75 deletions(-) diff --git a/src/components/cursor-controller.js b/src/components/cursor-controller.js index 869358b1ea..3a9aaaa760 100644 --- a/src/components/cursor-controller.js +++ b/src/components/cursor-controller.js @@ -75,14 +75,19 @@ const HIGHLIGHT = new THREE.Color(23 / 255, 64 / 255, 118 / 255); const NO_HIGHLIGHT = new THREE.Color(190 / 255, 190 / 255, 190 / 255); const ROTATE_COLOR_1 = [150, 80, 150]; const ROTATE_COLOR_2 = [23, 64, 118]; -/** - * Manages targeting and physical cursor location. Has the following responsibilities: - * - * - Tracking which entities in the scene can be targeted by the cursor (`objects`). - * - Performing a raycast per-frame or on-demand to identify which entity is being currently targeted. - * - Updating the visual presentation and position of the `cursor` entity and `line` component per frame. - * - Sending an event when an entity is targeted or un-targeted. - */ + +const THREEJS_HOVER_TARGETS = new Map(); +function findRemoteHoverTarget(o) { + if (!o) return null; + const target = THREEJS_HOVER_TARGETS.get(o.uuid); + return target || findRemoteHoverTarget(o.parent); +} +AFRAME.registerComponent("is-remote-hover-target", { + init: function() { + THREEJS_HOVER_TARGETS.set(this.el.object3D.uuid, this.el); + } +}); + AFRAME.registerComponent("cursor-controller", { schema: { cursor: { type: "selector" }, @@ -93,6 +98,23 @@ AFRAME.registerComponent("cursor-controller", { objects: { default: "" } }, + updateCursorIntersection: function(intersection) { + const hoverTarget = intersection && findRemoteHoverTarget(intersection.object); + if (!hoverTarget) { + if (this.rightRemoteHoverTarget) { + this.rightRemoteHoverTarget.removeState("hovered"); + this.rightRemoteHoverTarget = null; + } + return; + } + + if (this.rightRemoteHoverTarget && hoverTarget !== this.rightRemoteHoverTarget) { + this.rightRemoteHoverTarget.removeState("hovered"); + } + hoverTarget.addState("hovered"); + this.rightRemoteHoverTarget = hoverTarget; + }, + init: function() { this.enabled = true; @@ -160,17 +182,6 @@ AFRAME.registerComponent("cursor-controller", { } }, - emitIntersectionEvents: function(prevIntersection, currIntersection) { - // if we are now intersecting something, and previously we were intersecting nothing or something else - if (currIntersection && (!prevIntersection || currIntersection.object.el !== prevIntersection.object.el)) { - this.data.cursor.emit("raycaster-intersection", { el: currIntersection.object.el }); - } - // if we were intersecting something, but now we are intersecting nothing or something else - if (prevIntersection && (!currIntersection || currIntersection.object.el !== prevIntersection.object.el)) { - this.data.cursor.emit("raycaster-intersection-cleared", { el: prevIntersection.object.el }); - } - }, - tick: (() => { const rawIntersections = []; const cameraPos = new THREE.Vector3(); @@ -195,16 +206,14 @@ AFRAME.registerComponent("cursor-controller", { const interaction = AFRAME.scenes[0].systems.interaction; let intersection; - const isGrabbing = !!interaction.rightRemoteConstraintTarget; // this.data.cursor.components["super-hands"].state.has("grab-start"); + const isGrabbing = !!interaction.rightRemoteConstraintTarget; if (!isGrabbing) { rawIntersections.length = 0; this.raycaster.ray.origin = cursorPose.position; this.raycaster.ray.direction = cursorPose.direction; this.raycaster.intersectObjects(this.targets, true, rawIntersections); - intersection = rawIntersections.find(x => x.object.el); - AFRAME.scenes[0].systems.interaction.updateCursorIntersections(rawIntersections); - // this.emitIntersectionEvents(this.prevIntersection, intersection); - this.prevIntersection = intersection; + intersection = rawIntersections[0]; + this.updateCursorIntersection(intersection); this.distance = intersection ? intersection.distance : this.data.far; } @@ -254,10 +263,5 @@ AFRAME.registerComponent("cursor-controller", { this.line.geometry.computeBoundingSphere(); } }; - })(), - - remove: function() { - this.emitIntersectionEvents(this.prevIntersection, null); - delete this.prevIntersection; - } + })() }); diff --git a/src/systems/interactions.js b/src/systems/interactions.js index 5fead223c4..13c9ae2cee 100644 --- a/src/systems/interactions.js +++ b/src/systems/interactions.js @@ -6,50 +6,25 @@ AFRAME.registerComponent("offers-remote-constraint", {}); AFRAME.registerComponent("is-ui", {}); AFRAME.registerComponent("is-pen", {}); -const THREEJS_HOVER_TARGETS = new Map(); -function findRemoteHoverTarget(o) { - if (!o) return null; - const target = THREEJS_HOVER_TARGETS.get(o.uuid); - return target || findRemoteHoverTarget(o.parent); -} -AFRAME.registerComponent("is-remote-hover-target", { - init: function() { - THREEJS_HOVER_TARGETS.set(this.el.object3D.uuid, this.el); - } -}); - AFRAME.registerSystem("interaction", { init: function() { - this.rightRemoteHoverTarget = null; this.rightRemoteConstraintTarget = null; this.grabbedUI = null; this.grabbedPen = null; this.cursor = document.querySelector("#cursor"); this.weWantToGrab = false; }, - updateCursorIntersections: function(raw) { - const hasIntersection = raw[0]; - const hoverTarget = hasIntersection && findRemoteHoverTarget(raw[0].object); - if (!hasIntersection || !hoverTarget) { - if (this.rightRemoteHoverTarget) { - this.rightRemoteHoverTarget.removeState("hovered"); - this.rightRemoteHoverTarget = null; - } - return; - } - - if (this.rightRemoteHoverTarget && hoverTarget !== this.rightRemoteHoverTarget) { - this.rightRemoteHoverTarget.removeState("hovered"); - } - hoverTarget.addState("hovered"); - this.rightRemoteHoverTarget = hoverTarget; - }, tick: (function() { return function() { const userinput = AFRAME.scenes[0].systems.userinput; const drop = userinput.get(paths.actions.cursor.drop); const grab = userinput.get(paths.actions.cursor.grab); + this.cursorController = + this.cursorController || + (document.querySelector("#cursor-controller") && + document.querySelector("#cursor-controller").components["cursor-controller"]); + const rightRemoteHoverTarget = this.cursorController.rightRemoteHoverTarget; let didGrabEndThisFrame = false; if (drop && this.grabbedUI) { @@ -67,7 +42,7 @@ AFRAME.registerSystem("interaction", { stickyObject.onRelease(); } - const superNetworkedInteractable = this.rightRemoteHoverTarget.components["super-networked-interactable"]; + const superNetworkedInteractable = rightRemoteHoverTarget.components["super-networked-interactable"]; if (superNetworkedInteractable) { superNetworkedInteractable.onGrabEnd(this.cursor); } @@ -77,7 +52,7 @@ AFRAME.registerSystem("interaction", { this.grabbedPen = null; } - const isSuperSpawner = this.rightRemoteHoverTarget.components["super-spawner"]; + const isSuperSpawner = rightRemoteHoverTarget.components["super-spawner"]; if (isSuperSpawner && !didGrabEndThisFrame) { this.rightRemoteConstraintTarget.emit("grab-end", { hand: this.cursor }); didGrabEndThisFrame = true; @@ -87,38 +62,38 @@ AFRAME.registerSystem("interaction", { this.rightRemoteConstraintTarget = null; } } else { - if (this.rightRemoteHoverTarget && (grab || this.weWantToGrab)) { + if (rightRemoteHoverTarget && (grab || this.weWantToGrab)) { this.weWantToGrab = false; - const isUI = this.rightRemoteHoverTarget.components["is-ui"]; + const isUI = rightRemoteHoverTarget.components["is-ui"]; if (isUI) { - this.grabbedUI = this.rightRemoteHoverTarget; + this.grabbedUI = rightRemoteHoverTarget; } - const isPen = this.rightRemoteHoverTarget.components["is-pen"]; + const isPen = rightRemoteHoverTarget.components["is-pen"]; if (isPen) { - this.rightRemoteHoverTarget.children[0].components["pen"].grabberId = "cursor"; - this.grabbedPen = this.rightRemoteHoverTarget; + rightRemoteHoverTarget.children[0].components["pen"].grabberId = "cursor"; + this.grabbedPen = rightRemoteHoverTarget; } - const offersRemoteConstraint = this.rightRemoteHoverTarget.components["offers-remote-constraint"]; + const offersRemoteConstraint = rightRemoteHoverTarget.components["offers-remote-constraint"]; if (offersRemoteConstraint) { - this.rightRemoteConstraintTarget = this.rightRemoteHoverTarget; + this.rightRemoteConstraintTarget = rightRemoteHoverTarget; this.rightRemoteConstraintTarget.setAttribute("ammo-constraint", { target: "#cursor" }); - const stickyObject = this.rightRemoteHoverTarget.components["sticky-object"]; + const stickyObject = rightRemoteHoverTarget.components["sticky-object"]; if (stickyObject) { stickyObject.onGrab(); } - const superNetworkedInteractable = this.rightRemoteHoverTarget.components["super-networked-interactable"]; + const superNetworkedInteractable = rightRemoteHoverTarget.components["super-networked-interactable"]; if (superNetworkedInteractable) { superNetworkedInteractable.grabberId = "cursor"; superNetworkedInteractable.onGrabStart(this.cursor); } } - const isSuperSpawner = this.rightRemoteHoverTarget.components["super-spawner"]; + const isSuperSpawner = rightRemoteHoverTarget.components["super-spawner"]; if (isUI || isSuperSpawner) { - this.rightRemoteHoverTarget.emit("grab-start", { hand: this.cursor }); + rightRemoteHoverTarget.emit("grab-start", { hand: this.cursor }); } } } diff --git a/src/systems/userinput/resolve-action-sets.js b/src/systems/userinput/resolve-action-sets.js index 96cbf825b2..c40ca66407 100644 --- a/src/systems/userinput/resolve-action-sets.js +++ b/src/systems/userinput/resolve-action-sets.js @@ -2,10 +2,12 @@ import { sets } from "./sets"; let leftTeleporter; let rightTeleporter; +let cursorController; export function resolveActionSets() { leftTeleporter = leftTeleporter || document.querySelector("#player-left-controller").components["teleporter"]; rightTeleporter = rightTeleporter || document.querySelector("#player-right-controller").components["teleporter"]; + cursorController = cursorController || document.querySelector("#cursor-controller").components["cursor-controller"]; const userinput = AFRAME.scenes[0].systems.userinput; // userinput.toggleSet(sets.leftHandHoveringOnInteractable, leftHandHoveringOnInteractable); @@ -28,7 +30,7 @@ export function resolveActionSets() { const interaction = AFRAME.scenes[0].systems.interaction; const rightRemoteConstraintTarget = interaction.rightRemoteConstraintTarget; - const rightRemoteHoverTarget = !rightRemoteConstraintTarget && interaction.rightRemoteHoverTarget; + const rightRemoteHoverTarget = !rightRemoteConstraintTarget && cursorController.rightRemoteHoverTarget; userinput.toggleSet(sets.cursorHoveringOnNothing, !rightRemoteConstraintTarget && !rightRemoteHoverTarget); userinput.toggleSet( sets.cursorHoveringOnPen, From 4ac1b4aa0a532e24270cac757bc2fe5878a7dbaa Mon Sep 17 00:00:00 2001 From: johnshaughnessy Date: Mon, 18 Mar 2019 11:21:44 -0700 Subject: [PATCH 25/96] Don't need a closure around tick --- src/systems/interactions.js | 136 ++++++++++++++++++------------------ 1 file changed, 67 insertions(+), 69 deletions(-) diff --git a/src/systems/interactions.js b/src/systems/interactions.js index 13c9ae2cee..d36c37c5bd 100644 --- a/src/systems/interactions.js +++ b/src/systems/interactions.js @@ -15,88 +15,86 @@ AFRAME.registerSystem("interaction", { this.weWantToGrab = false; }, - tick: (function() { - return function() { - const userinput = AFRAME.scenes[0].systems.userinput; - const drop = userinput.get(paths.actions.cursor.drop); - const grab = userinput.get(paths.actions.cursor.grab); - this.cursorController = - this.cursorController || - (document.querySelector("#cursor-controller") && - document.querySelector("#cursor-controller").components["cursor-controller"]); - const rightRemoteHoverTarget = this.cursorController.rightRemoteHoverTarget; + tick: function() { + const userinput = AFRAME.scenes[0].systems.userinput; + const drop = userinput.get(paths.actions.cursor.drop); + const grab = userinput.get(paths.actions.cursor.grab); + this.cursorController = + this.cursorController || + (document.querySelector("#cursor-controller") && + document.querySelector("#cursor-controller").components["cursor-controller"]); + const rightRemoteHoverTarget = this.cursorController.rightRemoteHoverTarget; - let didGrabEndThisFrame = false; - if (drop && this.grabbedUI) { - this.grabbedUI.emit("grab-end", { hand: this.cursor }); - this.grabbedUI = null; - didGrabEndThisFrame = true; - } + let didGrabEndThisFrame = false; + if (drop && this.grabbedUI) { + this.grabbedUI.emit("grab-end", { hand: this.cursor }); + this.grabbedUI = null; + didGrabEndThisFrame = true; + } - if (this.rightRemoteConstraintTarget) { - this.rightRemoteConstraintTarget.object3D.matrixNeedsUpdate = true; + if (this.rightRemoteConstraintTarget) { + this.rightRemoteConstraintTarget.object3D.matrixNeedsUpdate = true; - if (drop) { - const stickyObject = this.rightRemoteConstraintTarget.components["sticky-object"]; - if (stickyObject) { - stickyObject.onRelease(); - } + if (drop) { + const stickyObject = this.rightRemoteConstraintTarget.components["sticky-object"]; + if (stickyObject) { + stickyObject.onRelease(); + } - const superNetworkedInteractable = rightRemoteHoverTarget.components["super-networked-interactable"]; - if (superNetworkedInteractable) { - superNetworkedInteractable.onGrabEnd(this.cursor); - } + const superNetworkedInteractable = rightRemoteHoverTarget.components["super-networked-interactable"]; + if (superNetworkedInteractable) { + superNetworkedInteractable.onGrabEnd(this.cursor); + } - if (this.grabbedPen) { - this.grabbedPen.children[0].components["pen"].grabberId = null; - this.grabbedPen = null; - } + if (this.grabbedPen) { + this.grabbedPen.children[0].components["pen"].grabberId = null; + this.grabbedPen = null; + } - const isSuperSpawner = rightRemoteHoverTarget.components["super-spawner"]; - if (isSuperSpawner && !didGrabEndThisFrame) { - this.rightRemoteConstraintTarget.emit("grab-end", { hand: this.cursor }); - didGrabEndThisFrame = true; - } + const isSuperSpawner = rightRemoteHoverTarget.components["super-spawner"]; + if (isSuperSpawner && !didGrabEndThisFrame) { + this.rightRemoteConstraintTarget.emit("grab-end", { hand: this.cursor }); + didGrabEndThisFrame = true; + } - this.rightRemoteConstraintTarget.removeAttribute("ammo-constraint"); - this.rightRemoteConstraintTarget = null; + this.rightRemoteConstraintTarget.removeAttribute("ammo-constraint"); + this.rightRemoteConstraintTarget = null; + } + } else { + if (rightRemoteHoverTarget && (grab || this.weWantToGrab)) { + this.weWantToGrab = false; + const isUI = rightRemoteHoverTarget.components["is-ui"]; + if (isUI) { + this.grabbedUI = rightRemoteHoverTarget; } - } else { - if (rightRemoteHoverTarget && (grab || this.weWantToGrab)) { - this.weWantToGrab = false; - const isUI = rightRemoteHoverTarget.components["is-ui"]; - if (isUI) { - this.grabbedUI = rightRemoteHoverTarget; - } - const isPen = rightRemoteHoverTarget.components["is-pen"]; - if (isPen) { - rightRemoteHoverTarget.children[0].components["pen"].grabberId = "cursor"; - this.grabbedPen = rightRemoteHoverTarget; - } + const isPen = rightRemoteHoverTarget.components["is-pen"]; + if (isPen) { + rightRemoteHoverTarget.children[0].components["pen"].grabberId = "cursor"; + this.grabbedPen = rightRemoteHoverTarget; + } - const offersRemoteConstraint = rightRemoteHoverTarget.components["offers-remote-constraint"]; - if (offersRemoteConstraint) { - this.rightRemoteConstraintTarget = rightRemoteHoverTarget; - this.rightRemoteConstraintTarget.setAttribute("ammo-constraint", { target: "#cursor" }); + const offersRemoteConstraint = rightRemoteHoverTarget.components["offers-remote-constraint"]; + if (offersRemoteConstraint) { + this.rightRemoteConstraintTarget = rightRemoteHoverTarget; + this.rightRemoteConstraintTarget.setAttribute("ammo-constraint", { target: "#cursor" }); - const stickyObject = rightRemoteHoverTarget.components["sticky-object"]; - if (stickyObject) { - stickyObject.onGrab(); - } - const superNetworkedInteractable = rightRemoteHoverTarget.components["super-networked-interactable"]; - if (superNetworkedInteractable) { - superNetworkedInteractable.grabberId = "cursor"; - superNetworkedInteractable.onGrabStart(this.cursor); - } + const stickyObject = rightRemoteHoverTarget.components["sticky-object"]; + if (stickyObject) { + stickyObject.onGrab(); } - - const isSuperSpawner = rightRemoteHoverTarget.components["super-spawner"]; - if (isUI || isSuperSpawner) { - rightRemoteHoverTarget.emit("grab-start", { hand: this.cursor }); + const superNetworkedInteractable = rightRemoteHoverTarget.components["super-networked-interactable"]; + if (superNetworkedInteractable) { + superNetworkedInteractable.grabberId = "cursor"; + superNetworkedInteractable.onGrabStart(this.cursor); } } + + const isSuperSpawner = rightRemoteHoverTarget.components["super-spawner"]; + if (isUI || isSuperSpawner) { + rightRemoteHoverTarget.emit("grab-start", { hand: this.cursor }); + } } - }; - })() + } + } }); From 3613773a3275ff08028ce27fa7798ba6931ee91c Mon Sep 17 00:00:00 2001 From: johnshaughnessy Date: Mon, 18 Mar 2019 11:23:43 -0700 Subject: [PATCH 26/96] Unused ACTIVATION_STATES --- src/systems/interactions.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/systems/interactions.js b/src/systems/interactions.js index d36c37c5bd..acfb6193e9 100644 --- a/src/systems/interactions.js +++ b/src/systems/interactions.js @@ -1,6 +1,5 @@ import { sets } from "./userinput/sets"; import { paths } from "./userinput/paths"; -const ACTIVATION_STATES = require("aframe-physics-system/src/constants").ACTIVATION_STATES; AFRAME.registerComponent("offers-remote-constraint", {}); AFRAME.registerComponent("is-ui", {}); From a58282412c68c76327252a2bde49cbd8683b3163 Mon Sep 17 00:00:00 2001 From: johnshaughnessy Date: Mon, 18 Mar 2019 14:46:44 -0700 Subject: [PATCH 27/96] Immediately add body and shape to loaded entity --- src/components/media-loader.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/components/media-loader.js b/src/components/media-loader.js index 064133e4c4..76be4913e7 100644 --- a/src/components/media-loader.js +++ b/src/components/media-loader.js @@ -145,6 +145,12 @@ AFRAME.registerComponent("media-loader", { const { src } = this.data; if (src !== oldData.src && !this.showLoaderTimeout) { + this.el.setAttribute("ammo-body", {type: "dynamic", mass: 1}); + this.el.setAttribute("ammo-shape__loader", { + autoGenerateShape: true, + type: SHAPES.BOX, + mergeGeometry: false + }); this.showLoaderTimeout = setTimeout(this.showLoader, 100); } From 2341c7109d9dea35f1b54c6cc9f266acf98d6f1a Mon Sep 17 00:00:00 2001 From: johnshaughnessy Date: Mon, 18 Mar 2019 16:54:06 -0700 Subject: [PATCH 28/96] Get super-spawners working --- src/components/media-loader.js | 6 -- src/components/super-spawner.js | 70 ------------------- src/systems/interactions.js | 73 +++++++++++++++++--- src/systems/userinput/resolve-action-sets.js | 4 +- 4 files changed, 65 insertions(+), 88 deletions(-) diff --git a/src/components/media-loader.js b/src/components/media-loader.js index 76be4913e7..064133e4c4 100644 --- a/src/components/media-loader.js +++ b/src/components/media-loader.js @@ -145,12 +145,6 @@ AFRAME.registerComponent("media-loader", { const { src } = this.data; if (src !== oldData.src && !this.showLoaderTimeout) { - this.el.setAttribute("ammo-body", {type: "dynamic", mass: 1}); - this.el.setAttribute("ammo-shape__loader", { - autoGenerateShape: true, - type: SHAPES.BOX, - mergeGeometry: false - }); this.showLoaderTimeout = setTimeout(this.showLoader, 100); } diff --git a/src/components/super-spawner.js b/src/components/super-spawner.js index 3aee938364..3d9d2600a2 100644 --- a/src/components/super-spawner.js +++ b/src/components/super-spawner.js @@ -89,10 +89,7 @@ AFRAME.registerComponent("super-spawner", { }, init() { - this.heldEntities = new Map(); this.cooldownTimeout = null; - this.onGrabStart = this.onGrabStart.bind(this); - this.onGrabEnd = this.onGrabEnd.bind(this); this.onSpawnEvent = this.onSpawnEvent.bind(this); @@ -103,20 +100,15 @@ AFRAME.registerComponent("super-spawner", { }, play() { - this.el.addEventListener("grab-start", this.onGrabStart); - this.el.addEventListener("grab-end", this.onGrabEnd); if (this.data.spawnEvent) { this.sceneEl.addEventListener(this.data.spawnEvent, this.onSpawnEvent); } }, pause() { - this.el.removeEventListener("grab-start", this.onGrabStart); - this.el.removeEventListener("grab-end", this.onGrabEnd); if (this.data.spawnEvent) { this.sceneEl.removeEventListener(this.data.spawnEvent, this.onSpawnEvent); } - if (this.cooldownTimeout) { clearTimeout(this.cooldownTimeout); this.cooldownTimeout = null; @@ -125,10 +117,6 @@ AFRAME.registerComponent("super-spawner", { } }, - remove() { - this.heldEntities.clear(); - }, - async onSpawnEvent() { const userinput = AFRAME.scenes[0].systems.userinput; const leftPose = userinput.get(paths.actions.leftHand.pose); @@ -181,64 +169,6 @@ AFRAME.registerComponent("super-spawner", { } }, - async onGrabStart(e) { - if (this.cooldownTimeout) { - return; - } - - // This tells super-hands we are handling this grab. The user is now "grabbing" the spawner - e.preventDefault(); - - const hand = e.detail.hand; - const thisGrabId = nextGrabId++; - this.heldEntities.set(hand, thisGrabId); - - const entity = addMedia( - this.data.src, - this.data.template, - ObjectContentOrigins.SPAWNER, - this.data.resolve, - this.data.resize - ).entity; - - entity.object3D.position.copy( - this.data.useCustomSpawnPosition ? this.data.spawnPosition : this.el.object3D.position - ); - entity.object3D.rotation.copy( - this.data.useCustomSpawnRotation ? this.data.spawnRotation : this.el.object3D.rotation - ); - entity.object3D.scale.copy(this.data.useCustomSpawnScale ? this.data.spawnScale : this.el.object3D.scale); - entity.object3D.matrixNeedsUpdate = true; - - await waitForEvent("body-loaded", entity); - - // If we are still holding the spawner with the hand that grabbed to create this entity, release the spawner and grab the entity - if (this.heldEntities.get(hand) === thisGrabId) { - if (this.data.centerSpawnedObject) { - entity.body.position.copy(hand.object3D.position); - } - - for (let i = 0; i < this.data.grabEvents.length; i++) { - hand.emit(this.data.releaseEvents[i]); - hand.emit(this.data.grabEvents[i], { targetEntity: entity }); - } - } - - entity.object3D.scale.copy(this.data.useCustomSpawnScale ? this.data.spawnScale : this.el.object3D.scale); - entity.object3D.matrixNeedsUpdate = true; - - // Call syncToPhysics so that updated transforms aren't immediately overwritten - entity.components["ammo-body"].syncToPhysics(); - - this.activateCooldown(); - }, - - onGrabEnd(e) { - this.heldEntities.delete(e.detail.hand); - // This tells super-hands we are handling this release - e.preventDefault(); - }, - activateCooldown() { if (this.data.spawnCooldown > 0) { this.el.setAttribute("visible", false); diff --git a/src/systems/interactions.js b/src/systems/interactions.js index acfb6193e9..7144472103 100644 --- a/src/systems/interactions.js +++ b/src/systems/interactions.js @@ -1,5 +1,17 @@ import { sets } from "./userinput/sets"; +import { waitForEvent } from "../utils/async-utils"; import { paths } from "./userinput/paths"; +import { addMedia } from "../utils/media-utils"; +import { ObjectContentOrigins } from "../object-types"; +const ACTIVATION_STATES = require("aframe-physics-system/src/constants").ACTIVATION_STATES; + +function logMat4(mat4) { + let s = ""; + for (let i = 0; i < 16; i++) { + s += mat4.elements[i] + " "; + } + console.log(s); +} AFRAME.registerComponent("offers-remote-constraint", {}); AFRAME.registerComponent("is-ui", {}); @@ -14,7 +26,7 @@ AFRAME.registerSystem("interaction", { this.weWantToGrab = false; }, - tick: function() { + tick: async function() { const userinput = AFRAME.scenes[0].systems.userinput; const drop = userinput.get(paths.actions.cursor.drop); const grab = userinput.get(paths.actions.cursor.grab); @@ -50,12 +62,6 @@ AFRAME.registerSystem("interaction", { this.grabbedPen = null; } - const isSuperSpawner = rightRemoteHoverTarget.components["super-spawner"]; - if (isSuperSpawner && !didGrabEndThisFrame) { - this.rightRemoteConstraintTarget.emit("grab-end", { hand: this.cursor }); - didGrabEndThisFrame = true; - } - this.rightRemoteConstraintTarget.removeAttribute("ammo-constraint"); this.rightRemoteConstraintTarget = null; } @@ -74,6 +80,7 @@ AFRAME.registerSystem("interaction", { } const offersRemoteConstraint = rightRemoteHoverTarget.components["offers-remote-constraint"]; + const superSpawner = rightRemoteHoverTarget.components["super-spawner"]; if (offersRemoteConstraint) { this.rightRemoteConstraintTarget = rightRemoteHoverTarget; this.rightRemoteConstraintTarget.setAttribute("ammo-constraint", { target: "#cursor" }); @@ -84,13 +91,57 @@ AFRAME.registerSystem("interaction", { } const superNetworkedInteractable = rightRemoteHoverTarget.components["super-networked-interactable"]; if (superNetworkedInteractable) { - superNetworkedInteractable.grabberId = "cursor"; superNetworkedInteractable.onGrabStart(this.cursor); } - } + } else if (superSpawner) { + this.cursor.object3D.updateMatrices(); + this.cursor.object3D.matrix.decompose( + this.cursor.object3D.position, + this.cursor.object3D.quaternion, + this.cursor.object3D.scale + ); + const data = superSpawner.data; + const entity = addMedia(data.src, data.template, ObjectContentOrigins.SPAWNER, data.resolve, data.resize) + .entity; + entity.object3D.position.copy( + data.useCustomSpawnPosition ? data.spawnPosition : superSpawner.el.object3D.position + ); + entity.object3D.rotation.copy( + data.useCustomSpawnRotation ? data.spawnRotation : superSpawner.el.object3D.rotation + ); + entity.object3D.scale.copy(data.useCustomSpawnScale ? data.spawnScale : superSpawner.el.object3D.scale); + entity.object3D.matrixNeedsUpdate = true; - const isSuperSpawner = rightRemoteHoverTarget.components["super-spawner"]; - if (isUI || isSuperSpawner) { + superSpawner.activateCooldown(); + // WARNING: waitForEvent is semantically different than entity.addEventListener("body-loaded", ...) + // and adding a callback fn via addEventListener will not work unless the callback function + // wraps its code in setTimeout(()=>{...}, 0) + await waitForEvent("body-loaded", entity); + entity.object3D.position.copy( + data.useCustomSpawnPosition ? data.spawnPosition : superSpawner.el.object3D.position + ); + if (data.centerSpawnedObject) { + entity.body.position.copy(this.cursor.object3D.position); + } + entity.object3D.scale.copy(data.useCustomSpawnScale ? data.spawnScale : superSpawner.el.object3D.scale); + entity.object3D.matrixNeedsUpdate = true; + + this.rightRemoteConstraintTarget = entity; + this.rightRemoteConstraintTarget.setAttribute("ammo-constraint", { target: "#cursor" }); + const stickyObject = this.rightRemoteConstraintTarget.components["sticky-object"]; + if (stickyObject) { + stickyObject.onGrab(); + } + + const superNetworkedInteractable = this.rightRemoteConstraintTarget.components[ + "super-networked-interactable" + ]; + if (superNetworkedInteractable) { + superNetworkedInteractable.onGrabStart(this.cursor); + } + entity.components["ammo-body"].syncToPhysics(); + } + if (isUI) { rightRemoteHoverTarget.emit("grab-start", { hand: this.cursor }); } } diff --git a/src/systems/userinput/resolve-action-sets.js b/src/systems/userinput/resolve-action-sets.js index c40ca66407..1414fcc021 100644 --- a/src/systems/userinput/resolve-action-sets.js +++ b/src/systems/userinput/resolve-action-sets.js @@ -42,7 +42,9 @@ export function resolveActionSets() { ); userinput.toggleSet( sets.cursorHoveringOnInteractable, - rightRemoteHoverTarget && !!rightRemoteHoverTarget.components["offers-remote-constraint"] + rightRemoteHoverTarget && + (!!rightRemoteHoverTarget.components["offers-remote-constraint"] || + !!rightRemoteHoverTarget.components["super-spawner"]) ); userinput.toggleSet(sets.cursorHoveringOnUI, rightRemoteHoverTarget && !!rightRemoteHoverTarget.components["is-ui"]); userinput.toggleSet( From 0e9debc441a7bf41846daf90daa2c49d0f28e7bd Mon Sep 17 00:00:00 2001 From: johnshaughnessy Date: Tue, 19 Mar 2019 17:56:19 -0700 Subject: [PATCH 29/96] Random tiny cleanups --- src/systems/interactions.js | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/systems/interactions.js b/src/systems/interactions.js index 7144472103..e27187fe34 100644 --- a/src/systems/interactions.js +++ b/src/systems/interactions.js @@ -23,6 +23,7 @@ AFRAME.registerSystem("interaction", { this.grabbedUI = null; this.grabbedPen = null; this.cursor = document.querySelector("#cursor"); + this.cursorController = document.querySelector("#cursor-controller"); this.weWantToGrab = false; }, @@ -30,17 +31,11 @@ AFRAME.registerSystem("interaction", { const userinput = AFRAME.scenes[0].systems.userinput; const drop = userinput.get(paths.actions.cursor.drop); const grab = userinput.get(paths.actions.cursor.grab); - this.cursorController = - this.cursorController || - (document.querySelector("#cursor-controller") && - document.querySelector("#cursor-controller").components["cursor-controller"]); - const rightRemoteHoverTarget = this.cursorController.rightRemoteHoverTarget; + const rightRemoteHoverTarget = this.cursorController.components["cursor-controller"].rightRemoteHoverTarget; - let didGrabEndThisFrame = false; if (drop && this.grabbedUI) { this.grabbedUI.emit("grab-end", { hand: this.cursor }); this.grabbedUI = null; - didGrabEndThisFrame = true; } if (this.rightRemoteConstraintTarget) { @@ -71,6 +66,7 @@ AFRAME.registerSystem("interaction", { const isUI = rightRemoteHoverTarget.components["is-ui"]; if (isUI) { this.grabbedUI = rightRemoteHoverTarget; + rightRemoteHoverTarget.emit("grab-start", { hand: this.cursor }); } const isPen = rightRemoteHoverTarget.components["is-pen"]; @@ -141,9 +137,6 @@ AFRAME.registerSystem("interaction", { } entity.components["ammo-body"].syncToPhysics(); } - if (isUI) { - rightRemoteHoverTarget.emit("grab-start", { hand: this.cursor }); - } } } } From 3687dd6c453565a8e8c4585a4815ca82ede7548e Mon Sep 17 00:00:00 2001 From: johnshaughnessy Date: Tue, 19 Mar 2019 19:39:28 -0700 Subject: [PATCH 30/96] Get right hand and right cursor interactions working --- src/components/cursor-controller.js | 2 +- src/hub.html | 6 + src/systems/interactions.js | 142 ++++++++++++++++++- src/systems/userinput/resolve-action-sets.js | 46 +++++- 4 files changed, 189 insertions(+), 7 deletions(-) diff --git a/src/components/cursor-controller.js b/src/components/cursor-controller.js index 3a9aaaa760..9bd1e10534 100644 --- a/src/components/cursor-controller.js +++ b/src/components/cursor-controller.js @@ -197,7 +197,7 @@ AFRAME.registerComponent("cursor-controller", { const cursorPose = userinput.get(paths.actions.cursor.pose); const rightHandPose = userinput.get(paths.actions.rightHand.pose); - this.data.cursor.object3D.visible = true; //this.enabled && !!cursorPose; + this.data.cursor.object3D.visible = this.enabled && !!cursorPose; this.line.material.visible = !!(this.enabled && rightHandPose); if (!this.enabled || !cursorPose) { diff --git a/src/hub.html b/src/hub.html index 65eef0e212..14e882c15b 100644 --- a/src/hub.html +++ b/src/hub.html @@ -198,6 +198,8 @@ scalable-when-grabbed ammo-body="type: static; mass: 1;" is-remote-hover-target + is-hand-collision-target + offers-constraint-when-colliding hoverable-visuals="cursorController: #cursor-controller" sound__grab="src: #sound_asset-grab; on: grabbed; poolSize: 1; positional: false;" sound__graboff ="src: #sound_asset-grab_off; on: ungrabbed; poolSize: 1; positional: false;" @@ -213,7 +215,9 @@ class="interactable" super-networked-interactable="counter: #media-counter" is-remote-hover-target + is-hand-collision-target offers-remote-constraint + offers-constraint-when-colliding destroy-at-extreme-distances scalable-when-grabbed ammo-body="type: dynamic; mass: 1;" @@ -267,6 +271,8 @@ super-networked-interactable="counter: #pen-counter;" is-remote-hover-target offers-remote-constraint + is-hand-collision-target + offers-constraint-when-colliding ammo-body="type: dynamic; mass: 0.001;" sticky-object="autoLockOnRelease: true; autoLockOnLoad: true; autoLockSpeedLimit: 0;" matrix-auto-update diff --git a/src/systems/interactions.js b/src/systems/interactions.js index e27187fe34..a58341a66d 100644 --- a/src/systems/interactions.js +++ b/src/systems/interactions.js @@ -13,25 +13,159 @@ function logMat4(mat4) { console.log(s); } +const THREEJS_HAND_COLLISION_TARGETS = new Map(); +function findHandCollisionTarget(o) { + if (!o) return null; + const target = THREEJS_HAND_COLLISION_TARGETS.get(o.uuid); + return target || findHandCollisionTarget(o.parent); +} +AFRAME.registerComponent("is-hand-collision-target", { + init: function() { + THREEJS_HAND_COLLISION_TARGETS.set(this.el.object3D.uuid, this.el); + } +}); + +AFRAME.registerComponent("offers-constraint-when-colliding", {}); AFRAME.registerComponent("offers-remote-constraint", {}); AFRAME.registerComponent("is-ui", {}); AFRAME.registerComponent("is-pen", {}); +function findHandCollisionTargetForBody(body) { + const driver = AFRAME.scenes[0].systems.physics.driver; + const collisions = driver.collisions; + const rightHandPtr = Ammo.getPointer(body); + for (const key in collisions) { + const [body0ptr, body1ptr] = collisions[key]; + if (body0ptr === rightHandPtr) { + return findHandCollisionTarget(driver.els[body1ptr].object3D); + } + if (body1ptr === rightHandPtr) { + return findHandCollisionTarget(driver.els[body0ptr].object3D); + } + } +} + AFRAME.registerSystem("interaction", { init: function() { this.rightRemoteConstraintTarget = null; this.grabbedUI = null; this.grabbedPen = null; - this.cursor = document.querySelector("#cursor"); - this.cursorController = document.querySelector("#cursor-controller"); this.weWantToGrab = false; }, tick: async function() { const userinput = AFRAME.scenes[0].systems.userinput; + const rightHandDrop = userinput.get(paths.actions.rightHand.drop); + const rightHandGrab = userinput.get(paths.actions.rightHand.grab); const drop = userinput.get(paths.actions.cursor.drop); const grab = userinput.get(paths.actions.cursor.grab); - const rightRemoteHoverTarget = this.cursorController.components["cursor-controller"].rightRemoteHoverTarget; + this.cursor = this.cursor || document.querySelector("#cursor"); + this.cursorController = this.cursorController || document.querySelector("#cursor-controller"); + this.rightHand = this.rightHand || document.querySelector("#player-right-controller"); + + if (this.rightHandConstraintTarget) { + this.rightHandConstraintTarget.object3D.matrixNeedsUpdate = true; + + if (rightHandDrop) { + const stickyObject = this.rightHandConstraintTarget.components["sticky-object"]; + if (stickyObject) { + stickyObject.onRelease(); + } + + const superNetworkedInteractable = this.rightHandConstraintTarget.components["super-networked-interactable"]; + if (superNetworkedInteractable) { + superNetworkedInteractable.onGrabEnd(this.cursor); + } + + if (this.grabbedPen) { + this.grabbedPen.children[0].components["pen"].grabberId = null; + this.grabbedPen = null; + } + + this.rightHandConstraintTarget.removeAttribute("ammo-constraint"); + this.rightHandConstraintTarget = null; + } + } else { + this.rightHandCollisionTarget = + !this.rightRemoteConstraintTarget && findHandCollisionTargetForBody(this.rightHand.body); + this.cursorController.components["cursor-controller"].enabled = !this.rightHandCollisionTarget; + if (this.rightHandCollisionTarget) { + if (rightHandGrab) { + const isPen = this.rightHandCollisionTarget.components["is-pen"]; + if (isPen) { + this.rightHandCollisionTarget.children[0].components["pen"].grabberId = "player-right-controller"; + this.penInRightHand = this.rightHandCollisionTarget; + } + const offersCollisionConstraint = this.rightHandCollisionTarget.components[ + "offers-constraint-when-colliding" + ]; + const superSpawner = this.rightHandCollisionTarget.components["super-spawner"]; + if (offersCollisionConstraint) { + this.rightHandConstraintTarget = this.rightHandCollisionTarget; + this.rightHandConstraintTarget.setAttribute("ammo-constraint", { target: "#player-right-controller" }); + + const stickyObject = this.rightHandCollisionTarget.components["sticky-object"]; + if (stickyObject) { + stickyObject.onGrab(); + } + const superNetworkedInteractable = this.rightHandCollisionTarget.components["super-networked-interactable"]; + if (superNetworkedInteractable) { + superNetworkedInteractable.onGrabStart(this.rightHand); + } + } else if (superSpawner) { + this.rightHand.object3D.updateMatrices(); + this.rightHand.object3D.matrix.decompose( + this.rightHand.object3D.position, + this.rightHand.object3D.quaternion, + this.rightHand.object3D.scale + ); + const data = superSpawner.data; + const entity = addMedia(data.src, data.template, ObjectContentOrigins.SPAWNER, data.resolve, data.resize) + .entity; + entity.object3D.position.copy( + data.useCustomSpawnPosition ? data.spawnPosition : superSpawner.el.object3D.position + ); + entity.object3D.rotation.copy( + data.useCustomSpawnRotation ? data.spawnRotation : superSpawner.el.object3D.rotation + ); + entity.object3D.scale.copy(data.useCustomSpawnScale ? data.spawnScale : superSpawner.el.object3D.scale); + entity.object3D.matrixNeedsUpdate = true; + + superSpawner.activateCooldown(); + // WARNING: waitForEvent is semantically different than entity.addEventListener("body-loaded", ...) + // and adding a callback fn via addEventListener will not work unless the callback function + // wraps its code in setTimeout(()=>{...}, 0) + await waitForEvent("body-loaded", entity); + entity.object3D.position.copy( + data.useCustomSpawnPosition ? data.spawnPosition : superSpawner.el.object3D.position + ); + if (data.centerSpawnedObject) { + entity.body.position.copy(this.rightHand.object3D.position); + } + entity.object3D.scale.copy(data.useCustomSpawnScale ? data.spawnScale : superSpawner.el.object3D.scale); + entity.object3D.matrixNeedsUpdate = true; + + this.rightHandConstraintTarget = entity; + this.rightHandConstraintTarget.setAttribute("ammo-constraint", { target: "#player-right-controller" }); + const stickyObject = this.rightHandConstraintTarget.components["sticky-object"]; + if (stickyObject) { + stickyObject.onGrab(); + } + + const superNetworkedInteractable = this.rightHandConstraintTarget.components[ + "super-networked-interactable" + ]; + if (superNetworkedInteractable) { + superNetworkedInteractable.onGrabStart(this.rightHand); + } + entity.components["ammo-body"].syncToPhysics(); + } + } + } + } + + const rightRemoteHoverTarget = + !this.rightHandCollisionTarget && this.cursorController.components["cursor-controller"].rightRemoteHoverTarget; if (drop && this.grabbedUI) { this.grabbedUI.emit("grab-end", { hand: this.cursor }); @@ -47,7 +181,7 @@ AFRAME.registerSystem("interaction", { stickyObject.onRelease(); } - const superNetworkedInteractable = rightRemoteHoverTarget.components["super-networked-interactable"]; + const superNetworkedInteractable = this.rightRemoteConstraintTarget.components["super-networked-interactable"]; if (superNetworkedInteractable) { superNetworkedInteractable.onGrabEnd(this.cursor); } diff --git a/src/systems/userinput/resolve-action-sets.js b/src/systems/userinput/resolve-action-sets.js index 1414fcc021..e04cb5ea75 100644 --- a/src/systems/userinput/resolve-action-sets.js +++ b/src/systems/userinput/resolve-action-sets.js @@ -29,9 +29,51 @@ export function resolveActionSets() { // userinput.toggleSet(sets.rightHandHoldingCamera, rightHandHoldingCamera); const interaction = AFRAME.scenes[0].systems.interaction; + + const rightHandConstraintTarget = interaction.rightHandConstraintTarget; + const rightHandCollisionTarget = !rightHandConstraintTarget && interaction.rightHandCollisionTarget; + userinput.toggleSet(sets.rightHandHoveringOnNothing, !rightHandConstraintTarget && !rightHandCollisionTarget); + userinput.toggleSet( + sets.rightHandHoveringOnPen, + rightHandCollisionTarget && !!rightHandCollisionTarget.components["is-pen"] + ); + userinput.toggleSet( + sets.rightHandHoveringOnCamera, + rightHandCollisionTarget && !!rightHandCollisionTarget.components["camera-tool"] + ); + userinput.toggleSet( + sets.rightHandHoveringOnInteractable, + rightHandCollisionTarget && + (!!rightHandCollisionTarget.components["offers-remote-constraint"] || + !!rightHandCollisionTarget.components["super-spawner"]) + ); + // userinput.toggleSet( + // sets.rightHandHoveringOnUI, + // rightHandCollisionTarget && !!rightHandCollisionTarget.components["is-ui"] + // ); + userinput.toggleSet( + sets.rightHandHoveringOnVideo, + rightHandCollisionTarget && !!rightHandCollisionTarget.components["media-video"] + ); + + userinput.toggleSet( + sets.rightHandHoldingPen, + rightHandConstraintTarget && !!rightHandConstraintTarget.components["is-pen"] + ); + userinput.toggleSet( + sets.rightHandHoldingCamera, + rightHandConstraintTarget && !!rightHandConstraintTarget.components["camera-tool"] + ); + // userinput.toggleSet(sets.rightHandHoldingUI, !!interaction.grabbedUI); + userinput.toggleSet(sets.rightHandHoldingInteractable, !!rightHandConstraintTarget); + userinput.toggleSet( + sets.inputFocused, + document.activeElement.nodeName === "INPUT" || document.activeElement.nodeName === "TEXTAREA" + ); + const rightRemoteConstraintTarget = interaction.rightRemoteConstraintTarget; - const rightRemoteHoverTarget = !rightRemoteConstraintTarget && cursorController.rightRemoteHoverTarget; - userinput.toggleSet(sets.cursorHoveringOnNothing, !rightRemoteConstraintTarget && !rightRemoteHoverTarget); + const rightRemoteHoverTarget = !rightHandConstraintTarget && !rightHandCollisionTarget && !rightRemoteConstraintTarget && cursorController.rightRemoteHoverTarget; + userinput.toggleSet(sets.cursorHoveringOnNothing, !rightHandConstraintTarget && !rightHandCollisionTarget && !rightRemoteConstraintTarget && !rightRemoteHoverTarget); userinput.toggleSet( sets.cursorHoveringOnPen, rightRemoteHoverTarget && !!rightRemoteHoverTarget.components["is-pen"] From ef194a612f48905875e008e9796e683a4e9749e1 Mon Sep 17 00:00:00 2001 From: johnshaughnessy Date: Wed, 20 Mar 2019 10:17:16 -0700 Subject: [PATCH 31/96] Various cleanups --- src/components/super-spawner.js | 1 - src/systems/interactions.js | 8 +++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/components/super-spawner.js b/src/components/super-spawner.js index 3d9d2600a2..89d847b05b 100644 --- a/src/components/super-spawner.js +++ b/src/components/super-spawner.js @@ -95,7 +95,6 @@ AFRAME.registerComponent("super-spawner", { this.sceneEl = document.querySelector("a-scene"); - this.el.setAttribute("hoverable-visuals", { cursorController: "#cursor-controller", enableSweepingEffect: false }); this.tempSpawnHandPosition = new THREE.Vector3(); }, diff --git a/src/systems/interactions.js b/src/systems/interactions.js index a58341a66d..b32509c710 100644 --- a/src/systems/interactions.js +++ b/src/systems/interactions.js @@ -64,7 +64,6 @@ AFRAME.registerSystem("interaction", { this.rightHand = this.rightHand || document.querySelector("#player-right-controller"); if (this.rightHandConstraintTarget) { - this.rightHandConstraintTarget.object3D.matrixNeedsUpdate = true; if (rightHandDrop) { const stickyObject = this.rightHandConstraintTarget.components["sticky-object"]; @@ -77,9 +76,9 @@ AFRAME.registerSystem("interaction", { superNetworkedInteractable.onGrabEnd(this.cursor); } - if (this.grabbedPen) { - this.grabbedPen.children[0].components["pen"].grabberId = null; - this.grabbedPen = null; + if (this.penInRightHand) { + this.penInRightHand.children[0].components["pen"].grabberId = null; + this.penInRightHand = null; } this.rightHandConstraintTarget.removeAttribute("ammo-constraint"); @@ -173,7 +172,6 @@ AFRAME.registerSystem("interaction", { } if (this.rightRemoteConstraintTarget) { - this.rightRemoteConstraintTarget.object3D.matrixNeedsUpdate = true; if (drop) { const stickyObject = this.rightRemoteConstraintTarget.components["sticky-object"]; From ee8bbeabdfb430809cea69110baa034991418e44 Mon Sep 17 00:00:00 2001 From: johnshaughnessy Date: Wed, 20 Mar 2019 10:17:27 -0700 Subject: [PATCH 32/96] Remove unused sticky-object-zone --- src/components/sticky-object.js | 69 --------------------------------- 1 file changed, 69 deletions(-) diff --git a/src/components/sticky-object.js b/src/components/sticky-object.js index dc72bdda82..3501c9036e 100644 --- a/src/components/sticky-object.js +++ b/src/components/sticky-object.js @@ -1,5 +1,3 @@ -import { getLastWorldPosition, getLastWorldQuaternion } from "../utils/three-utils"; - const COLLISION_LAYERS = require("../constants").COLLISION_LAYERS; /* global THREE, AFRAME */ AFRAME.registerComponent("sticky-object", { @@ -66,70 +64,3 @@ AFRAME.registerComponent("sticky-object", { } } }); - -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(); - getLastWorldPosition(this.el.object3D, this.worldPosition); - getLastWorldQuaternion(this.el.object3D, this.worldQuaternion); - - //TODO: support this with ammo - // 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.object3D.matrixNeedsUpdate = true; - stickyObject.el.body.collisionResponse = false; - stickyObject.stuckTo = this; - - if (this.stuckObject && NAF.utils.isMine(this.stuckObject.el)) { - //TODO: support this with ammo - // const el = 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; - } - delete this.stuckObject; - } -}); From 9a69251cc359291a48671adebd49672d66b899ff Mon Sep 17 00:00:00 2001 From: johnshaughnessy Date: Wed, 20 Mar 2019 17:48:45 -0700 Subject: [PATCH 33/96] Get buttons working with THREE's EventDispatcher --- src/components/block-button.js | 4 +- src/components/camera-focus-button.js | 4 +- src/components/camera-tool.js | 28 +---- src/components/clone-media-button.js | 4 +- src/components/icon-button.js | 4 +- src/components/in-world-hud.js | 24 ++--- src/components/kick-button.js | 4 +- src/components/media-loader.js | 4 +- src/components/media-views.js | 20 ++-- src/components/mirror-camera-button.js | 4 +- src/components/open-media-button.js | 4 +- src/components/pin-networked-object-button.js | 4 +- src/components/quack.js | 4 +- .../remove-networked-object-button.js | 4 +- src/components/rotate-object-button.js | 24 +++-- src/components/sticky-object.js | 8 +- src/components/super-spawner.js | 6 -- src/components/text-button.js | 4 +- src/hub.html | 102 +++++++----------- src/systems/interactions.js | 28 +++-- .../devices/app-aware-touchscreen.js | 2 +- src/systems/userinput/resolve-action-sets.js | 21 +++- 22 files changed, 139 insertions(+), 172 deletions(-) diff --git a/src/components/block-button.js b/src/components/block-button.js index 8d32ef647c..2face34c07 100644 --- a/src/components/block-button.js +++ b/src/components/block-button.js @@ -14,11 +14,11 @@ AFRAME.registerComponent("block-button", { }, play() { - this.el.addEventListener("grab-start", this.onClick); + this.el.object3D.addEventListener("interact", this.onClick); }, pause() { - this.el.removeEventListener("grab-start", this.onClick); + this.el.object3D.removeEventListener("interact", this.onClick); }, block(clientId) { diff --git a/src/components/camera-focus-button.js b/src/components/camera-focus-button.js index d08e750e18..da5bbc9a4f 100644 --- a/src/components/camera-focus-button.js +++ b/src/components/camera-focus-button.js @@ -28,10 +28,10 @@ AFRAME.registerComponent("camera-focus-button", { }, play() { - this.el.addEventListener("grab-start", this.onClick); + this.el.object3D.addEventListener("interact", this.onClick); }, pause() { - this.el.removeEventListener("grab-start", this.onClick); + this.el.object3D.removeEventListener("interact", this.onClick); } }); diff --git a/src/components/camera-tool.js b/src/components/camera-tool.js index 7558bc1d41..c31976a3cf 100644 --- a/src/components/camera-tool.js +++ b/src/components/camera-tool.js @@ -67,9 +67,6 @@ AFRAME.registerComponent("camera-tool", { }, init() { - this.stateAdded = this.stateAdded.bind(this); - this.onGrab = this.onGrab.bind(this); - this.lastUpdate = performance.now(); this.localSnapCount = 0; // Counter that is used to arrange photos @@ -130,32 +127,18 @@ AFRAME.registerComponent("camera-tool", { this.el.setAttribute("hover-menu__camera", { template: "#camera-hover-menu", dirs: ["forward", "back"] }); this.el.components["hover-menu__camera"].getHoverMenu().then(() => { this.snapButton = this.el.querySelector(".snap-button"); - this.snapButton.addEventListener("grab-start", () => (this.takeSnapshotNextTick = true)); + this.snapButton.object3D.addEventListener("interact", () => { + this.takeSnapshotNextTick = true; + }); }); }, - play() { - this.el.addEventListener("stateadded", this.stateAdded); - this.el.addEventListener("grab-start", this.onGrab); - }, - - pause() { - this.el.removeEventListener("stateadded", this.stateAdded); - this.el.removeEventListener("grab-start", this.onGrab); - }, - remove() { this.cameraSystem.deregister(this.el); this.el.sceneEl.systems["camera-mirror"].unmirrorCameraAtEl(this.el); this.el.sceneEl.emit("camera_removed"); }, - stateAdded(evt) { - if (evt.detail === "activated") { - this.takeSnapshotNextTick = true; - } - }, - focus(el, track) { if (track) { this.trackTarget = el; @@ -183,14 +166,11 @@ AFRAME.registerComponent("camera-tool", { this.el.sceneEl.systems["camera-mirror"].unmirrorCameraAtEl(this.el); }, - onGrab() { - this.localSnapCount = 0; // When camera is moved, reset photo arrangement algorithm - }, - tick() { const grabber = undefined; //this.el.components.grabbable.grabbers[0]; const userinput = this.el.sceneEl.systems.userinput; if (grabber && !!pathsMap[grabber.id]) { + this.localSnapCount = 0; // TODO: When camera is moved, reset photo arrangement algorithm const grabberPaths = pathsMap[grabber.id]; if (userinput.get(grabberPaths.takeSnapshot)) { this.takeSnapshotNextTick = true; diff --git a/src/components/clone-media-button.js b/src/components/clone-media-button.js index a64cecc38e..a2c7c35efa 100644 --- a/src/components/clone-media-button.js +++ b/src/components/clone-media-button.js @@ -28,10 +28,10 @@ AFRAME.registerComponent("clone-media-button", { }, play() { - this.el.addEventListener("grab-start", this.onClick); + this.el.object3D.addEventListener("interact", this.onClick); }, pause() { - this.el.removeEventListener("grab-start", this.onClick); + this.el.object3D.removeEventListener("interact", this.onClick); } }); diff --git a/src/components/icon-button.js b/src/components/icon-button.js index 3d2c752367..65dec034ef 100644 --- a/src/components/icon-button.js +++ b/src/components/icon-button.js @@ -42,13 +42,13 @@ AFRAME.registerComponent("icon-button", { this.updateButtonState(); this.el.addEventListener("hover-start", this.onHover); this.el.addEventListener("hover-end", this.onHoverOut); - this.el.addEventListener("grab-start", this.onClick); + this.el.object3D.addEventListener("interact", this.onClick); }, pause() { this.el.removeEventListener("hover-start", this.onHover); this.el.removeEventListener("hover-end", this.onHoverOut); - this.el.removeEventListener("grab-start", this.onClick); + this.el.object3D.removeEventListener("interact", this.onClick); }, update() { diff --git a/src/components/in-world-hud.js b/src/components/in-world-hud.js index 1d00e3095f..dc05fb185c 100644 --- a/src/components/in-world-hud.js +++ b/src/components/in-world-hud.js @@ -4,10 +4,6 @@ * @component in-world-hud */ AFRAME.registerComponent("in-world-hud", { - schema: { - haptic: { type: "selector" }, - raycaster: { type: "selector" } - }, init() { this.mic = this.el.querySelector(".mic"); this.spawn = this.el.querySelector(".spawn"); @@ -60,21 +56,21 @@ AFRAME.registerComponent("in-world-hud", { this.el.sceneEl.addEventListener("stateadded", this.onStateChange); this.el.sceneEl.addEventListener("stateremoved", this.onStateChange); - this.mic.addEventListener("mousedown", this.onMicClick); - this.spawn.addEventListener("mousedown", this.onSpawnClick); - this.pen.addEventListener("mousedown", this.onPenClick); - this.cameraBtn.addEventListener("mousedown", this.onCameraClick); - this.inviteBtn.addEventListener("grab-start", this.onInviteClick); + this.mic.object3D.addEventListener("interact", this.onMicClick); + this.spawn.object3D.addEventListener("interact", this.onSpawnClick); + this.pen.object3D.addEventListener("interact", this.onPenClick); + this.cameraBtn.object3D.addEventListener("interact", this.onCameraClick); + this.inviteBtn.object3D.addEventListener("interact", this.onInviteClick); }, pause() { this.el.sceneEl.removeEventListener("stateadded", this.onStateChange); this.el.sceneEl.removeEventListener("stateremoved", this.onStateChange); - this.mic.removeEventListener("mousedown", this.onMicClick); - this.spawn.removeEventListener("mousedown", this.onSpawnClick); - this.pen.removeEventListener("mousedown", this.onPenClick); - this.cameraBtn.removeEventListener("mousedown", this.onCameraClick); - this.inviteBtn.removeEventListener("grab-end", this.onInviteClick); + this.mic.object3D.removeEventListener("interact", this.onMicClick); + this.spawn.object3D.removeEventListener("interact", this.onSpawnClick); + this.pen.object3D.removeEventListener("interact", this.onPenClick); + this.cameraBtn.object3D.removeEventListener("interact", this.onCameraClick); + this.inviteBtn.object3D.removeEventListener("interact", this.onInviteClick); } }); diff --git a/src/components/kick-button.js b/src/components/kick-button.js index 4015a6d786..1b2a284c1d 100644 --- a/src/components/kick-button.js +++ b/src/components/kick-button.js @@ -9,11 +9,11 @@ AFRAME.registerComponent("kick-button", { }, play() { - this.el.addEventListener("grab-start", this.onClick); + this.el.object3D.addEventListener("interact", this.onClick); }, pause() { - this.el.removeEventListener("grab-start", this.onClick); + this.el.object3D.removeEventListener("interact", this.onClick); }, async kick(clientId) { diff --git a/src/components/media-loader.js b/src/components/media-loader.js index 064133e4c4..1129dd8dee 100644 --- a/src/components/media-loader.js +++ b/src/components/media-loader.js @@ -304,8 +304,8 @@ AFRAME.registerComponent("media-pager", { this.prevButton = this.el.querySelector(".prev-button [text-button]"); this.pageLabel = this.el.querySelector(".page-label"); - this.nextButton.addEventListener("grab-start", this.onNext); - this.prevButton.addEventListener("grab-start", this.onPrev); + this.nextButton.object3D.addEventListener("interact", this.onNext); + this.prevButton.object3D.addEventListener("interact", this.onPrev); this.update(); this.el.emit("preview-loaded"); diff --git a/src/components/media-views.js b/src/components/media-views.js index 11144b1bd3..f57b9a0add 100644 --- a/src/components/media-views.js +++ b/src/components/media-views.js @@ -360,11 +360,11 @@ AFRAME.registerComponent("media-video", { this.timeLabel = this.el.querySelector(".video-time-label"); this.volumeLabel = this.el.querySelector(".video-volume-label"); - this.playPauseButton.addEventListener("grab-start", this.togglePlaying); - this.seekForwardButton.addEventListener("grab-start", this.seekForward); - this.seekBackButton.addEventListener("grab-start", this.seekBack); - this.volumeUpButton.addEventListener("grab-start", this.volumeUp); - this.volumeDownButton.addEventListener("grab-start", this.volumeDown); + this.playPauseButton.object3D.addEventListener("interact", this.togglePlaying); + this.seekForwardButton.object3D.addEventListener("interact", this.seekForward); + this.seekBackButton.object3D.addEventListener("interact", this.seekBack); + this.volumeUpButton.object3D.addEventListener("interact", this.volumeUp); + this.volumeDownButton.object3D.addEventListener("interact", this.volumeDown); this.updateVolumeLabel(); this.updateHoverMenuBasedOnLiveState(); @@ -685,11 +685,11 @@ AFRAME.registerComponent("media-video", { this.video.removeEventListener("play", this.onPauseStateChange); } if (this.hoverMenu) { - this.playPauseButton.removeEventListener("grab-start", this.togglePlaying); - this.volumeUpButton.removeEventListener("grab-start", this.volumeUp); - this.volumeDownButton.removeEventListener("grab-start", this.volumeDown); - this.seekForwardButton.removeEventListener("grab-start", this.seekForward); - this.seekBackButton.removeEventListener("grab-start", this.seekBack); + this.playPauseButton.object3D.removeEventListener("interact", this.togglePlaying); + this.volumeUpButton.object3D.removeEventListener("interact", this.volumeUp); + this.volumeDownButton.object3D.removeEventListener("interact", this.volumeDown); + this.seekForwardButton.object3D.removeEventListener("interact", this.seekForward); + this.seekBackButton.object3D.removeEventListener("interact", this.seekBack); } } }); diff --git a/src/components/mirror-camera-button.js b/src/components/mirror-camera-button.js index e86a1a7aed..a231584d29 100644 --- a/src/components/mirror-camera-button.js +++ b/src/components/mirror-camera-button.js @@ -30,11 +30,11 @@ AFRAME.registerComponent("mirror-camera-button", { }, play() { - this.el.addEventListener("grab-start", this.onClick); + this.el.object3D.addEventListener("interact", this.onClick); }, pause() { - this.el.removeEventListener("grab-start", this.onClick); + this.el.object3D.removeEventListener("interact", this.onClick); }, _isMirrored() { diff --git a/src/components/open-media-button.js b/src/components/open-media-button.js index 7bf3c48fd2..20c8c96c59 100644 --- a/src/components/open-media-button.js +++ b/src/components/open-media-button.js @@ -41,10 +41,10 @@ AFRAME.registerComponent("open-media-button", { }, play() { - this.el.addEventListener("grab-start", this.onClick); + this.el.object3D.addEventListener("interact", this.onClick); }, pause() { - this.el.removeEventListener("grab-start", this.onClick); + this.el.object3D.removeEventListener("interact", this.onClick); } }); diff --git a/src/components/pin-networked-object-button.js b/src/components/pin-networked-object-button.js index 631f4c689c..1044b8112b 100644 --- a/src/components/pin-networked-object-button.js +++ b/src/components/pin-networked-object-button.js @@ -34,11 +34,11 @@ AFRAME.registerComponent("pin-networked-object-button", { }, play() { - this.el.addEventListener("grab-start", this.onClick); + this.el.object3D.addEventListener("interact", this.onClick); }, pause() { - this.el.removeEventListener("grab-start", this.onClick); + this.el.object3D.removeEventListener("interact", this.onClick); }, remove() { diff --git a/src/components/quack.js b/src/components/quack.js index e97b6f8f1b..d5bb90e880 100644 --- a/src/components/quack.js +++ b/src/components/quack.js @@ -9,11 +9,11 @@ AFRAME.registerComponent("quack", { }, play: function() { - this.el.addEventListener("grab-start", this._handleGrabStart); + this.el.object3D.addEventListener("interact", this._handleGrabStart); }, pause: function() { - this.el.removeEventListener("grab-start", this._handleGrabStart); + this.el.object3D.removeEventListener("interact", this._handleGrabStart); }, _handleGrabStart: function() { diff --git a/src/components/remove-networked-object-button.js b/src/components/remove-networked-object-button.js index 47b5ef38eb..cab892a255 100644 --- a/src/components/remove-networked-object-button.js +++ b/src/components/remove-networked-object-button.js @@ -24,10 +24,10 @@ AFRAME.registerComponent("remove-networked-object-button", { }, play() { - this.el.addEventListener("grab-start", this.onClick); + this.el.object3D.addEventListener("interact", this.onClick); }, pause() { - this.el.removeEventListener("grab-start", this.onClick); + this.el.object3D.removeEventListener("interact", this.onClick); } }); diff --git a/src/components/rotate-object-button.js b/src/components/rotate-object-button.js index 2b7b97a22b..58b7019ec2 100644 --- a/src/components/rotate-object-button.js +++ b/src/components/rotate-object-button.js @@ -33,8 +33,6 @@ AFRAME.registerComponent("rotate-button", { if (!this.targetEl) { return; } - const hand = e.detail.hand; - hand.emit("haptic_pulse", { intensity: "high" }); if (!NAF.utils.isMine(this.targetEl) && !NAF.utils.takeOwnership(this.targetEl)) { return; } @@ -42,22 +40,24 @@ AFRAME.registerComponent("rotate-button", { this.targetEl.setAttribute("ammo-body", { type: "static" }); } this.rotateSystem = this.rotateSystem || AFRAME.scenes[0].systems["rotate-selected-object"]; - this.rotateSystem.startRotate(this.targetEl.object3D, hand, this.data); - e.preventDefault(); + this.rotateSystem.startRotate( + this.targetEl.object3D, + e.path === paths.actions.cursor.grab ? "cursor" : e.path === paths.actions.rightHand.grab ? "right" : "left", + this.data + ); }; this.onGrabEnd = e => { this.rotateSystem = this.rotateSystem || AFRAME.scenes[0].systems["rotate-selected-object"]; this.rotateSystem.stopRotate(); - e.preventDefault(); }; }, play() { - this.el.addEventListener("grab-start", this.onGrabStart); - this.el.addEventListener("grab-end", this.onGrabEnd); + this.el.object3D.addEventListener("holdable-button-down", this.onGrabStart); + this.el.object3D.addEventListener("holdable-button-up", this.onGrabEnd); }, pause() { - this.el.removeEventListener("grab-start", this.onGrabStart); - this.el.removeEventListener("grab-end", this.onGrabEnd); + this.el.object3D.removeEventListener("holdable-button-down", this.onGrabStart); + this.el.object3D.removeEventListener("holdable-button-up", this.onGrabEnd); } }); @@ -152,7 +152,10 @@ AFRAME.registerSystem("rotate-selected-object", { startRotate(target, hand, data) { this.target = target; - this.hand = hand.id === "cursor" ? document.querySelector("#player-right-controller").object3D : hand.object3D; + this.hand = + hand === "cursor" || hand === "right" + ? document.querySelector("#player-right-controller").object3D + : document.querySelector("#player-left-controller").object3D; this.mode = data.mode; this.rotating = true; @@ -269,6 +272,7 @@ AFRAME.registerSystem("rotate-selected-object", { if (this.mode === ROTATE_MODE.ALIGN) { this.el.camera.getWorldPosition(CAMERA_WORLD_POSITION); this.target.lookAt(CAMERA_WORLD_POSITION); + this.rotating = false; return; } diff --git a/src/components/sticky-object.js b/src/components/sticky-object.js index 3501c9036e..5d4fd65ad4 100644 --- a/src/components/sticky-object.js +++ b/src/components/sticky-object.js @@ -9,16 +9,10 @@ AFRAME.registerComponent("sticky-object", { }, init() { - this._onBodyLoaded = this._onBodyLoaded.bind(this); - }, - - play() { - if (this.hasSetupBodyLoaded) return; - this.hasSetupBodyLoaded = true; - if (this.el.body) { this._onBodyLoaded(); } else { + this._onBodyLoaded = this._onBodyLoaded.bind(this); this.el.addEventListener("body-loaded", this._onBodyLoaded, { once: true }); } }, diff --git a/src/components/super-spawner.js b/src/components/super-spawner.js index 89d847b05b..4d4b4863e9 100644 --- a/src/components/super-spawner.js +++ b/src/components/super-spawner.js @@ -51,12 +51,6 @@ AFRAME.registerComponent("super-spawner", { useCustomSpawnScale: { default: false }, spawnScale: { type: "vec3" }, - /** - * The events to emit for programmatically grabbing and releasing objects - */ - grabEvents: { default: ["grab-start"] }, - releaseEvents: { default: [] }, - /** * The spawner will become invisible and ungrabbable for this ammount of time after being grabbed. This can prevent rapidly spawning objects. */ diff --git a/src/components/text-button.js b/src/components/text-button.js index 0d02d4d818..fb0fc63763 100644 --- a/src/components/text-button.js +++ b/src/components/text-button.js @@ -40,13 +40,13 @@ AFRAME.registerComponent("text-button", { this.updateButtonState(); this.el.addEventListener("mouseover", this.onHover); this.el.addEventListener("mouseout", this.onHoverOut); - this.el.addEventListener("grab-start", this.onClick); + this.el.object3D.addEventListener("interact", this.onClick); }, pause() { this.el.removeEventListener("mouseover", this.onHover); this.el.removeEventListener("mouseout", this.onHoverOut); - this.el.removeEventListener("grab-start", this.onClick); + this.el.object3D.removeEventListener("interact", this.onClick); }, update() { diff --git a/src/hub.html b/src/hub.html index 14e882c15b..d92d9084b1 100644 --- a/src/hub.html +++ b/src/hub.html @@ -226,7 +226,7 @@ matrix-auto-update position-at-box-shape-border__freeze="target:.freeze-menu;" > - + @@ -254,10 +254,10 @@ - + - + @@ -302,7 +302,7 @@ segments-width="16" segments-height="12" > - + @@ -326,16 +326,16 @@ position-at-box-shape-border__freeze="target: .camera-menu" set-yxz-order > - + - + - + @@ -343,7 +343,7 @@ -/ +