diff --git a/src/components/icon-button.js b/src/components/icon-button.js new file mode 100644 index 0000000000000000000000000000000000000000..eab80803f4d85ad425a6d5a0c71fc8f6f9ddc333 --- /dev/null +++ b/src/components/icon-button.js @@ -0,0 +1,57 @@ +AFRAME.registerComponent("icon-button", { + schema: { + image: { type: "string" }, + hoverImage: { type: "string" }, + activeImage: { type: "string" }, + activeHoverImage: { type: "string" }, + active: { type: "boolean" }, + haptic: { type: "selector" } + }, + + init() { + this.onHover = () => { + this.hovering = true; + this.updateButtonState(); + this.emitHapticPulse(); + }; + this.onHoverOut = () => { + this.hovering = false; + this.updateButtonState(); + }; + this.onClick = () => { + this.emitHapticPulse(); + }; + }, + + emitHapticPulse() { + if (this.data.haptic) { + this.data.haptic.emit("haptic_pulse", { intensity: "low" }); + } + }, + + play() { + this.updateButtonState(); + this.el.addEventListener("mouseover", this.onHover); + this.el.addEventListener("mouseout", this.onHoverOut); + this.el.addEventListener("click", this.onClick); + }, + + pause() { + this.el.removeEventListener("mouseover", this.onHover); + this.el.removeEventListener("mouseout", this.onHoverOut); + this.el.removeEventListener("click", this.onClick); + }, + + update() { + this.updateButtonState(); + }, + + updateButtonState() { + const hovering = this.hovering; + const active = this.data.active; + + const image = active ? (hovering ? "activeHoverImage" : "activeImage") : hovering ? "hoverImage" : "image"; + + this.el.setAttribute("src", this.data[image]); + } +}); diff --git a/src/components/in-world-hud.js b/src/components/in-world-hud.js index 9e307e498256da344e5e2e3533baf82b09f93b6f..6b6c28bfc2cc97f1a3a776f9c4c12edd867457a3 100644 --- a/src/components/in-world-hud.js +++ b/src/components/in-world-hud.js @@ -5,99 +5,41 @@ AFRAME.registerComponent("in-world-hud", { }, init() { this.mic = this.el.querySelector(".mic"); + this.freeze = this.el.querySelector(".freeze"); - const muted = this.el.sceneEl.is("muted"); - this.mic.setAttribute("src", muted ? "#muted" : "#unmuted"); - - this.showCorrectMuteState = () => { - const muted = this.el.sceneEl.is("muted"); - this.mic.setAttribute("src", muted ? "#muted" : "#unmuted"); + this.updateButtonStates = () => { + this.mic.setAttribute("icon-button", "active", this.el.sceneEl.is("muted")); + this.freeze.setAttribute("icon-button", "active", this.el.sceneEl.is("frozen")); }; + this.updateButtonStates(); this.onStateChange = evt => { - if (evt.detail !== "muted") return; - this.showCorrectMuteState(); - }; - - this.onMicHover = () => { - this.hoveredOnMic = true; - this.data.haptic.emit("haptic_pulse", { intensity: "low" }); - this.mic.setAttribute("material", "color", "#1DD"); - }; - - this.onMicHoverExit = () => { - this.hoveredOnMic = false; - this.mic.setAttribute("material", "color", "#FFF"); - this.showCorrectMuteState(); + if (!(evt.detail === "muted" || evt.detail === "frozen")) return; + this.updateButtonStates(); }; - this.onMicDown = () => { - this.data.haptic.emit("haptic_pulse", { intensity: "medium" }); - this.el.sceneEl.removeEventListener("micAudio", this.onAudioFrequencyChange); - this.mic.setAttribute("material", "color", this.el.sceneEl.is("muted") ? "#0FA" : "#F33"); + this.onMicClick = () => { this.el.emit("action_mute"); - window.setTimeout(() => { - this.mic.setAttribute("material", "color", "#FFF"); - this.el.sceneEl.addEventListener("micAudio", this.onAudioFrequencyChange); - }, 150); - }; - - this.onClick = () => { - if (this.hoveredOnMic) { - this.onMicDown(); - } }; - this.onAudioFrequencyChange = e => { - if (this.hoveredOnMic) return; - const red = 1.0 - e.detail.volume / 10.0; - this.mic.object3DMap.mesh.material.color = { r: red, g: 9, b: 9 }; + this.onFreezeClick = () => { + this.el.emit("action_freeze"); }; - - this.el.sceneEl.addEventListener("mediaStream", evt => { - this.ms = evt.detail.ms; - const ctx = THREE.AudioContext.getContext(); - const source = ctx.createMediaStreamSource(this.ms); - this.analyser = ctx.createAnalyser(); - this.levels = new Uint8Array(this.analyser.frequencyBinCount); - source.connect(this.analyser); - }); }, play() { - this.mic.addEventListener("raycaster-intersected", this.onMicHover); - this.mic.addEventListener("raycaster-intersected-cleared", this.onMicHoverExit); - this.el.sceneEl.addEventListener("stateadded", this.onStateChange); this.el.sceneEl.addEventListener("stateremoved", this.onStateChange); - this.el.addEventListener("click", this.onClick); - - this.el.sceneEl.addEventListener("micAudio", this.onAudioFrequencyChange); + this.mic.addEventListener("click", this.onMicClick); + this.freeze.addEventListener("click", this.onFreezeClick); }, pause() { this.el.sceneEl.removeEventListener("stateadded", this.onStateChange); this.el.sceneEl.removeEventListener("stateremoved", this.onStateChange); - this.el.removeEventListener("click", this.onClick); - - this.el.sceneEl.removeEventListener("micAudio", this.onAudioFrequencyChange); - }, - - tick: function() { - if (!this.analyser) return; - - this.analyser.getByteFrequencyData(this.levels); - - let sum = 0; - for (let i = 0; i < this.levels.length; i++) { - sum += this.levels[i]; - } - this.volume = sum / this.levels.length; - this.el.emit("micAudio", { - volume: this.volume, - levels: this.levels - }); + this.mic.removeEventListener("click", this.onMicClick); + this.freeze.removeEventListener("click", this.onFreezeClick); } }); diff --git a/src/hub.html b/src/hub.html index 973461f270e5b2f412421d8f3ba5ed06b4dc3328..8f5491682717686a3eb09374018d020830983b0a 100644 --- a/src/hub.html +++ b/src/hub.html @@ -29,9 +29,18 @@ > <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.png" > + <img id="mute_off" src="./assets/hud/mute_off.png" > + <img id="mute_off-hover" src="./assets/hud/mute_off-hover.png" > + <img id="mute_on" src="./assets/hud/mute_on.png" > + <img id="mute_on-hover" src="./assets/hud/mute_on-hover.png" > + <img id="bubble_off" src="./assets/hud/bubble_off.png" > + <img id="bubble_off-hover" src="./assets/hud/bubble_off-hover.png" > + <img id="bubble_on" src="./assets/hud/bubble_on.png" > + <img id="bubble_on-hover" src="./assets/hud/bubble_on-hover.png" > + <img id="freeze_off" src="./assets/hud/freeze_off.png" > + <img id="freeze_off-hover" src="./assets/hud/freeze_off-hover.png" > + <img id="freeze_on" src="./assets/hud/freeze_on.png" > + <img id="freeze_on-hover" src="./assets/hud/freeze_on-hover.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> @@ -176,10 +185,10 @@ vr-mode-toggle-playing__hud-controller > <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-rounded height="0.13" width="0.48" color="#000000" position="-0.24 -0.065 0" radius="0.065" opacity="0.35" class="hud bg"></a-rounded> + <a-image icon-button="image: #mute_off; hoverImage: #mute_off-hover; activeImage: #mute_on; activeHoverImage: #mute_on-hover" scale="0.1 0.1 0.1" position="-0.17 0 0.001" class="hud mic" material="alphaTest:0.1;"></a-image> + <a-image icon-button="image: #freeze_off; hoverImage: #freeze_off-hover; activeImage: #freeze_on; activeHoverImage: #freeze_on-hover" scale="0.2 0.2 0.2" position="0 0 0.001" class="hud freeze"></a-image> + <a-image icon-button="image: #bubble_off; hoverImage: #bubble_off-hover; activeImage: #bubble_on; activeHoverImage: #bubble_on-hover" scale="0.1 0.1 0.1" position="0.17 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 34d2812823ff6b2aa3926dbf5f20afa6c47da577..699c124090ab680333c04b122da5fce65d7b541e 100644 --- a/src/hub.js +++ b/src/hub.js @@ -50,6 +50,7 @@ import "./components/gltf-model-plus"; import "./components/gltf-bundle"; import "./components/hud-controller"; import "./components/freeze-controller"; +import "./components/icon-button"; import ReactDOM from "react-dom"; import React from "react";