From 7e135ec6b8eec32ebd41d72d2308a8decbb9c468 Mon Sep 17 00:00:00 2001 From: Kevin Lee <kevin@infinite-lee.com> Date: Fri, 16 Mar 2018 18:13:09 -0700 Subject: [PATCH] no more cursor lock; super-cursor follows around cursor screen position; look-controls are paused when an interactable is grabbed; colors changed; cursor no longer appears to be in "hovered" state when moused over the floor or table; --- src/components/super-cursor.js | 79 ++++++++++++++++++++++++++-------- src/room.css | 9 ++++ src/room.html | 43 ++++++++---------- 3 files changed, 90 insertions(+), 41 deletions(-) diff --git a/src/components/super-cursor.js b/src/components/super-cursor.js index d1b28b0f1..a500efb22 100644 --- a/src/components/super-cursor.js +++ b/src/components/super-cursor.js @@ -2,42 +2,56 @@ AFRAME.registerComponent("super-cursor", { dependencies: ["raycaster"], schema: { cursor: { type: "selector" }, - maxDistance: { type: "number", default: 3 }, - minDistance: { type: "number", default: 0.5 } + camera: { type: "selector" }, + maxDistance: { default: 3 }, + minDistance: { default: 0.5 }, + cursorColorHovered: { default: "#FF0000" }, + cursorColorUnhovered: { efault: "#FFFFFF" } }, init: function() { this.isGrabbing = false; + this.isInteractable = false; this.wasIntersecting = false; this.currentDistance = this.data.maxDistance; this.currentDistanceMod = 0; this.enabled = true; - this.isGrabbing = false; this.origin = new THREE.Vector3(); this.direction = new THREE.Vector3(); this.point = new THREE.Vector3(); - }, + this.mousePos = new THREE.Vector2(); + this.mouseDown = false; + + this.data.cursor.setAttribute("material", { color: this.data.cursorColorUnhovered }); - play: function() { this.mouseDownListener = this._handleMouseDown.bind(this); + this.mouseMoveListener = this._handleMouseMove.bind(this); this.mouseUpListener = this._handleMouseUp.bind(this); this.wheelListener = this._handleWheel.bind(this); this.enterVRListener = this._handleEnterVR.bind(this); - this.exitVRListener = this._handleExitVR.bind(this); + this.exitVRListener = this._handleExitVR.bind(this); + }, + play: function() { document.addEventListener("mousedown", this.mouseDownListener); + document.addEventListener("mousemove", this.mouseMoveListener); document.addEventListener("mouseup", this.mouseUpListener); document.addEventListener("wheel", this.wheelListener); window.addEventListener("enter-vr", this.enterVRListener); window.addEventListener("exit-vr", this.exitVRListener); + + this._enable(); }, pause: function() { document.removeEventListener("mousedown", this.mouseDownListener); + document.removeEventListener("mousemove", this.mouseMoveListener); document.removeEventListener("mouseup", this.mouseUpListener); document.removeEventListener("wheel", this.wheelListener); window.removeEventListener("enter-vr", this.enterVRListener); window.removeEventListener("exit-vr", this.exitVRListener); + + this._disable(); }, tick: function() { @@ -48,10 +62,20 @@ AFRAME.registerComponent("super-cursor", { this.isGrabbing = this.data.cursor.components["super-hands"].state.has("grab-start"); let isIntersecting = false; + const camera = this.data.camera.components.camera.camera; + const raycaster = this.el.components.raycaster.raycaster; + raycaster.setFromCamera(this.mousePos, camera); + this.origin = raycaster.ray.origin; + this.direction = raycaster.ray.direction; + this.el.setAttribute("raycaster", { origin: this.origin, direction: this.direction }); + + let className = null; + if (!this.isGrabbing) { const intersections = this.el.components.raycaster.intersections; if (intersections.length > 0 && intersections[0].distance <= this.data.maxDistance) { isIntersecting = true; + className = intersections[0].object.el.className; this.point = intersections[0].point; this.data.cursor.object3D.position.copy(this.point); this.currentDistance = intersections[0].distance; @@ -62,49 +86,70 @@ AFRAME.registerComponent("super-cursor", { } if (this.isGrabbing || !isIntersecting) { - const head = this.el.object3D; - head.getWorldPosition(this.origin); - head.getWorldDirection(this.direction); const distance = Math.min( Math.max(this.data.minDistance, this.currentDistance - this.currentDistanceMod), this.data.maxDistance ); this.currentDistanceMod = this.currentDistance - distance; - this.direction.multiplyScalar(-distance); + this.direction.multiplyScalar(distance); this.point.addVectors(this.origin, this.direction); this.data.cursor.object3D.position.copy(this.point); } - if ((this.isGrabbing || isIntersecting) && !this.wasIntersecting) { + this.isInteractable = isIntersecting && className === "interactable"; + + if ((this.isGrabbing || this.isInteractable) && !this.wasIntersecting) { this.wasIntersecting = true; - this.data.cursor.setAttribute("material", {color: "#00FF00"}); - } else if (!this.isGrabbing && !isIntersecting && this.wasIntersecting) { + this.data.cursor.setAttribute("material", { color: this.data.cursorColorHovered }); + } else if (!this.isGrabbing && !this.isInteractable && this.wasIntersecting) { this.wasIntersecting = false; - this.data.cursor.setAttribute("material", {color: "#00EFFF"}); + this.data.cursor.setAttribute("material", { color: this.data.cursorColorUnhovered }); } }, _handleMouseDown: function(e) { + this.mouseDown = true; + if (this.isInteractable) { + const lookControls = this.data.camera.components["look-controls"]; + lookControls.pause(); + } this.data.cursor.emit("action_grab", {}); }, + _handleMouseMove: function(e) { + this.mousePos.set(e.clientX / window.innerWidth * 2 - 1, -(e.clientY / window.innerHeight) * 2 + 1); + }, + _handleMouseUp: function(e) { + this.mouseDown = false; + const lookControls = this.data.camera.components["look-controls"]; + lookControls.play(); this.data.cursor.emit("action_release", {}); }, _handleWheel: function(e) { if (this.isGrabbing) this.currentDistanceMod += e.deltaY / 10; - }, + }, _handleEnterVR: function(e) { if (AFRAME.utils.device.checkHeadsetConnected() || AFRAME.utils.device.isMobile()) { - this.enabled = false; - this.data.cursor.setAttribute("visible", false); + this._disable(); } }, _handleExitVR: function(e) { + this._enable(); + }, + + _enable: function() { this.enabled = true; this.data.cursor.setAttribute("visible", true); + this.el.setAttribute("raycaster", { enabled: true }); }, + + _disable: function() { + this.enabled = false; + this.data.cursor.setAttribute("visible", false); + this.el.setAttribute("raycaster", { enabled: false }); + } }); diff --git a/src/room.css b/src/room.css index 6f2d31b19..9023e6171 100644 --- a/src/room.css +++ b/src/room.css @@ -11,3 +11,12 @@ background: #eaeaea no-repeat url("./assets/loading.gif") center center; opacity: 0.9; } + + +.a-canvas.a-grab-cursor:hover { + cursor: none; +} + +.a-canvas.a-grab-cursor:active { + cursor: none; +} diff --git a/src/room.html b/src/room.html index 4d21e693f..3102445e8 100644 --- a/src/room.html +++ b/src/room.html @@ -100,13 +100,12 @@ <a-entity gltf-model="#interactable-duck" scale="2 2 2" - class="collidable" + class="interactable" super-networked-interactable="counter: #counter; mass: 5;" body="type: dynamic; mass: 5; shape: box;" grabbable stretchable="useWorldPosition: true;" - > - </a-entity> + ></a-entity> </template> <a-mixin id="super-hands" @@ -127,21 +126,24 @@ <a-entity gltf-model="#interactable-duck" scale="2 2 2" - class="collidable" - class="collidable" + class="interactable" super-spawner="template: #interactable-template;" position="2.5 1.2 0" body="mass: 0; type: static; shape: box;" ></a-entity> - <a-sphere - id="3d-cursor" - material="color: #00EFFF" - radius=0.02 - static-body="shape: sphere;" - mixin="super-hands" - ></a-sphere> - + <a-entity + id="super-cursor" + super-cursor="cursor: #3d-cursor; camera: #player-camera;" + raycaster="objects: .collidable, .interactable; far: 10;" + > + <a-sphere + id="3d-cursor" + radius=0.02 + static-body="shape: sphere;" + mixin="super-hands" + ></a-sphere> + </a-entity> <!-- Player Rig --> <a-entity @@ -158,15 +160,8 @@ camera position="0 1.6 0" personal-space-bubble - look-controls="pointerLockEnabled: true;" - > - <a-entity - id="super-cursor" - super-cursor="cursor: #3d-cursor" - position="0 0 0" - raycaster="objects: .collidable; direction: 0 0 -1;" - ></a-entity> - </a-entity> + look-controls + ></a-entity> <a-entity id="player-left-controller" @@ -303,8 +298,8 @@ height="35" width="35" static-body - class="collidable"> - </a-plane> + class="collidable" + ></a-plane> </a-scene> </body> -- GitLab