diff --git a/package.json b/package.json index 73f3ad5bba8c7896b3e30a6328d4a3fe25f86353..efecd3d5701bab90f076beb039b995beb1be3cc6 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,7 @@ "aframe-physics-extras": "https://github.com/infinitelee/aframe-physics-extras#fix/physics-collider-crash", "aframe-physics-system": "https://github.com/donmccurdy/aframe-physics-system", "aframe-teleport-controls": "^0.3.1", + "aframe-rounded": "^1.0.3", "aframe-xr": "github:brianpeiris/aframe-xr#3162aed", "classnames": "^2.2.5", "detect-browser": "^2.1.0", diff --git a/src/assets/hud/avatar.png b/src/assets/hud/avatar.png new file mode 100644 index 0000000000000000000000000000000000000000..d604f8f18d51b481bcc0013f30e2c610100b231c Binary files /dev/null and b/src/assets/hud/avatar.png differ diff --git a/src/assets/stylesheets/2d-hud.css b/src/assets/stylesheets/2d-hud.css index a8324a5bb8b054c4da44f82aadfe96647c5cb45b..a3509f308bd4638f231ef87b714b7bdb05b5dfcf 100644 --- a/src/assets/stylesheets/2d-hud.css +++ b/src/assets/stylesheets/2d-hud.css @@ -3,12 +3,44 @@ top: 10px; display: flex; justify-content: center; - height: 60px; + align-items: center; + height: 80px; width: 100%; } -:local(.bg) { - position: absolute; +:local(.panel) { + display: flex; + justify-content: space-around; + align-items: center; + padding: 10px; + background-color: rgba(0, 0, 0, 0.35); +} + +:local(.panel.left) { + border-bottom-left-radius: 30px; + border-top-left-radius: 30px; + padding-left: 20px; + padding-right: 50px; + margin-right: -40px; +} + +:local(.panel.right) { + border-bottom-right-radius: 30px; + border-top-right-radius: 30px; + padding-right: 20px; + padding-left: 50px; + margin-left: -40px; +} + +:local(.modeButton) { + width: 80px; + height: 80px; + display: flex; + align-items: center; + justify-content: center; +} + +:local(.panel) { display: flex; justify-content: space-around; align-items: center; @@ -16,6 +48,7 @@ background-color: rgba(0, 0, 0, 0.35); } + :local(.nametag) { display: flex; justify-content: center; @@ -26,21 +59,20 @@ } :local(.avatar) { - display: flex; - width: 48px; - height: 48px; + width: 80px; + height: 80px; background-size: 100%; - background-image: url(../hud/avatar.jpg); + background-image: url(../hud/avatar.png); } :local(.mic) { display: flex; - width: 48px; - height: 48px; + width: 32px; + height: 32px; -webkit-mask: url(../hud/unmuted.png); - -webkit-mask-size: 48px; + -webkit-mask-size: 32px; mask: url(../hud/unmuted.png); - mask-size: 48px; + mask-size: 32px; background-color: white; cursor: pointer; } @@ -59,9 +91,9 @@ :local(.mic.muted) { -webkit-mask: url(../hud/muted.png); - -webkit-mask-size: 48px; + -webkit-mask-size: 32px; mask: url(../hud/muted.png); - mask-size: 48px; + mask-size: 32px; } :local(.mic.muted:active) { diff --git a/src/components/in-world-hud.js b/src/components/in-world-hud.js index aa7e8aae756207dc05a640f7d02f6c0f728b41ca..9e307e498256da344e5e2e3533baf82b09f93b6f 100644 --- a/src/components/in-world-hud.js +++ b/src/components/in-world-hud.js @@ -4,29 +4,11 @@ AFRAME.registerComponent("in-world-hud", { raycaster: { type: "selector" } }, init() { - this.bg = this.el.querySelector(".bg"); this.mic = this.el.querySelector(".mic"); - this.nametag = this.el.querySelector(".username"); - this.avatar = this.el.querySelector(".avatar"); - this.nametag.object3DMap.text.material.depthTest = false; - this.nametag.object3DMap.text.renderOrder = 1; - this.mic.object3DMap.mesh.renderOrder = 1; - this.avatar.object3DMap.mesh.renderOrder = 1; - - const line = this.data.raycaster.object3DMap.line; - line.renderOrder = 2; - line.material.depthTest = false; - // Set opacity to 0.99 to force the line to render in the - // transparent pass, so that it renders on top of the HUD - this.data.raycaster.setAttribute("line", "opacity", 0.99); const muted = this.el.sceneEl.is("muted"); this.mic.setAttribute("src", muted ? "#muted" : "#unmuted"); - const scene = this.el.sceneEl; - this.onUsernameChanged = this.onUsernameChanged.bind(this); - scene.addEventListener("username-changed", this.onUsernameChanged); - this.showCorrectMuteState = () => { const muted = this.el.sceneEl.is("muted"); this.mic.setAttribute("src", muted ? "#muted" : "#unmuted"); @@ -95,9 +77,6 @@ AFRAME.registerComponent("in-world-hud", { }, pause() { - this.nametag.removeEventListener("raycaster-intersected", this.onNametagHovered); - this.nametag.removeEventListener("raycaster-intersected-cleared", this.onNametagUnhovered); - this.el.sceneEl.removeEventListener("stateadded", this.onStateChange); this.el.sceneEl.removeEventListener("stateremoved", this.onStateChange); @@ -120,12 +99,5 @@ AFRAME.registerComponent("in-world-hud", { volume: this.volume, levels: this.levels }); - }, - - onUsernameChanged(evt) { - const { username } = evt.detail; - const width = evt.detail.username.length == 0 ? 1 : 40 / username.length; - this.nametag.setAttribute("text", "width", Math.min(width, 6)); - this.nametag.setAttribute("text", "value", username); } }); diff --git a/src/hub.html b/src/hub.html index 91e3f1c4f2f07e4f6c4e8aa4f355bc5c69d7428b..d06deef8e3249b8cf447e78375613f814858e052 100644 --- a/src/hub.html +++ b/src/hub.html @@ -29,7 +29,7 @@ <a-assets> <img id="unmuted" src="./assets/hud/unmuted.png" > <img id="muted" src="./assets/hud/muted.png" > - <img id="avatar" src="./assets/hud/avatar.jpg" > + <img id="avatar" src="./assets/hud/avatar.png" > <a-asset-item id="botdefault" response-type="arraybuffer" src="https://asset-bundles-prod.reticulum.io/bots/BotDefault_Avatar-9f71f8ff22.gltf"></a-asset-item> <a-asset-item id="botbobo" response-type="arraybuffer" src="https://asset-bundles-prod.reticulum.io/bots/BotBobo_Avatar-f9740a010b.gltf"></a-asset-item> @@ -173,11 +173,11 @@ vr-mode-toggle-visibility vr-mode-toggle-playing__hud-controller > - <a-entity in-world-hud="haptic:#player-right-controller;raycaster:#player-right-controller;" rotation="-39 0 0"> - <a-box geometry="height:0.13;width:0.6;depth:0.001" material="depthTest:false; color:#000000;opacity:0.35" class="hud bg"></a-box> - <a-image src="#unmuted" scale="-0.1 0.1 0.1" position="-0.2 0 0.001" class="hud mic" material="alphaTest:0.1;depthTest:false;"></a-image> - <a-text scale="0.3 0.3 0.3" position="0 0 0.001" class="hud username" text="width:6;alphaTest:0.1;align:center;"></a-text> - <a-image src="#avatar" scale="0.1 0.1 0.1" position="0.2 0 0.001" class="hud avatar" material="depthTest:false;"></a-image> + <a-entity in-world-hud="haptic:#player-right-controller;raycaster:#player-right-controller;" rotation="30 0 0"> + <a-rounded height="0.13" width="0.6" color="#000000" position="-0.3 -0.065 0" radius="0.065" opacity="0.35" class="hud bg"></a-rounded> + <a-image src="#unmuted" scale="0.1 0.1 0.1" position="-0.2 0 0.001" class="hud mic" material="alphaTest:0.1;"></a-image> + <a-image src="#avatar" scale="0.2 0.2 0.2" position="0 0 0.001" class="hud avatar"></a-image> + <a-image src="#unmuted" scale="0.1 0.1 0.1" position="0.2 0 0.001" class="hud mic" material="alphaTest:0.1;"></a-image> </a-entity> </a-entity> diff --git a/src/hub.js b/src/hub.js index fc843649946ff6630563dfa1c1efd78e1d2b00d1..d3bb848459f3e8db5efe557653284908c3a41163 100644 --- a/src/hub.js +++ b/src/hub.js @@ -11,6 +11,7 @@ import "naf-janus-adapter"; import "aframe-teleport-controls"; import "aframe-input-mapping-component"; import "aframe-billboard-component"; +import "aframe-rounded"; import "webrtc-adapter"; import { vive_trackpad_dpad4 } from "./behaviours/vive-trackpad-dpad4"; diff --git a/src/react-components/2d-hud.js b/src/react-components/2d-hud.js index 8d9223a072c97c670210e67e48434cfc58543d49..563ba43d823960a772473a49c5610f918ecb9c38 100644 --- a/src/react-components/2d-hud.js +++ b/src/react-components/2d-hud.js @@ -6,11 +6,15 @@ import styles from "../assets/stylesheets/2d-hud.css"; const TwoDHUD = ({ name, muted, onToggleMute }) => ( <div className={styles.container}> - <div className={cx("ui-interactive", styles.bg)}> + <div className={cx("ui-interactive", styles.panel, styles.left)}> <div className={cx(styles.mic, { [styles.muted]: muted })} onClick={onToggleMute} /> - <div className={styles.nametag}>{name}</div> + </div> + <div className={cx("ui-interactive", styles.modeButton)}> <div className={styles.avatar} /> </div> + <div className={cx("ui-interactive", styles.panel, styles.right)}> + <div className={cx(styles.mic, { [styles.muted]: muted })} onClick={onToggleMute} /> + </div> </div> ); diff --git a/src/systems/app-mode.js b/src/systems/app-mode.js index 1ef1c2cd0d7b79c75d0738717558901370320e5b..ce83545e26cb3e57321491b71d0c621862a8d23c 100644 --- a/src/systems/app-mode.js +++ b/src/systems/app-mode.js @@ -101,10 +101,10 @@ function deltaAngle(a, b) { AFRAME.registerComponent("hud-controller", { schema: { head: { type: "selector" }, - offset: { default: 1 }, // distance from hud below head, - lookCutoff: { default: -25 }, // angle at which the hud should be "on", + offset: { default: 0.7 }, // distance from hud above head, + lookCutoff: { default: 20 }, // angle at which the hud should be "on", animRange: { default: 30 }, // degrees over which to animate the hud into view - yawCutoff: { default: 100 } // yaw degrees at wich the hud should reoirent even if the user is looking down + yawCutoff: { default: 50 } // yaw degrees at wich the hud should reoirent even if the user is looking down }, init() { this.isYLocked = false; @@ -127,9 +127,9 @@ AFRAME.registerComponent("hud-controller", { const pitch = head.rotation.x * THREE.Math.RAD2DEG; const yawDif = deltaAngle(head.rotation.y, hud.rotation.y) * THREE.Math.RAD2DEG; - // Reorient the hud only if the user is looking "up", for right now this arbitrarily means the hud is 1/3 way animated away + // Reorient the hud only if the user is looking away from the hud, for right now this arbitrarily means the hud is 1/3 way animated away // TODO: come up with better huristics for this that maybe account for the user turning away from the hud "too far", also animate the position so that it doesnt just snap. - if (yawDif >= yawCutoff || pitch > lookCutoff + animRange / 3) { + if (yawDif >= yawCutoff || pitch < lookCutoff - animRange / 3) { const lookDir = new THREE.Vector3(0, 0, -1); lookDir.applyQuaternion(head.quaternion); lookDir.add(head.position); @@ -138,8 +138,8 @@ AFRAME.registerComponent("hud-controller", { hud.setRotationFromEuler(new THREE.Euler(0, head.rotation.y, 0)); } - //animate the hud into place over animRange degrees as the user aproaches the lookCutoff angle - const t = 1 - THREE.Math.clamp(pitch - lookCutoff, 0, animRange) / animRange; + // animate the hud into place over animRange degrees as the user aproaches the lookCutoff angle + const t = 1 - THREE.Math.clamp(lookCutoff - pitch, 0, animRange) / animRange; // Lock the hud in place relative to a known head position so it doesn't bob up and down // with the user's head @@ -149,16 +149,16 @@ AFRAME.registerComponent("hud-controller", { const EPSILON = 0.001; this.isYLocked = t > 1 - EPSILON; - hud.position.y = (this.isYLocked ? this.lockedHeadPositionY : head.position.y) - offset - offset * (1 - t); + hud.position.y = (this.isYLocked ? this.lockedHeadPositionY : head.position.y) + offset + (1 - t) * offset; hud.rotation.x = (1 - t) * THREE.Math.DEG2RAD * 90; // update the app mode when the HUD locks on or off // TODO: this assumes full control over current app mode reguardless of what else might be manipulating it, this is obviously wrong const AppModeSystem = sceneEl.systems["app-mode"]; - if (pitch < lookCutoff && AppModeSystem.mode !== AppModes.HUD) { + if (pitch > lookCutoff && AppModeSystem.mode !== AppModes.HUD) { AppModeSystem.setMode(AppModes.HUD); sceneEl.renderer.sortObjects = true; - } else if (pitch > lookCutoff && AppModeSystem.mode === AppModes.HUD) { + } else if (pitch < lookCutoff && AppModeSystem.mode === AppModes.HUD) { AppModeSystem.setMode(AppModes.DEFAULT); sceneEl.renderer.sortObjects = false; } diff --git a/yarn.lock b/yarn.lock index 76d6c651b95192f98f08e688fe9f38a529b5be4a..86fb13e790cda023e78086f2454a06d5263d4ef0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -190,6 +190,10 @@ aframe-lerp-component@^1.1.0: three-to-cannon "^1.2.0" webworkify "^1.4.0" +aframe-rounded@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/aframe-rounded/-/aframe-rounded-1.0.3.tgz#72c7d9c0ff02e94ee138bf217c284e187efa3cfb" + aframe-teleport-controls@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/aframe-teleport-controls/-/aframe-teleport-controls-0.3.1.tgz#7d7ef206f483ea92425a6333b0f8fb26c9596d1c"