diff --git a/src/room.js b/src/room.js index a687dca43f54086f2462b926338cb4fe55366298..014069ae03729397260ca0d152cdf3a107d067d3 100644 --- a/src/room.js +++ b/src/room.js @@ -40,6 +40,7 @@ import "./components/spawn-controller"; import "./components/bone-visibility"; import "./systems/personal-space-bubble"; +import "./systems/app-mode"; import "./elements/a-gltf-entity"; diff --git a/src/systems/app-mode.js b/src/systems/app-mode.js new file mode 100644 index 0000000000000000000000000000000000000000..10f26cf0f1563760a143e26577cb67c8e94815fc --- /dev/null +++ b/src/systems/app-mode.js @@ -0,0 +1,75 @@ +/* global AFRAME, console, setTimeout, clearTimeout */ + +const AppModes = Object.freeze({ DEFAULT: "default", HUD: "hud" }); +AFRAME.registerSystem("app-mode", { + init() { + console.log("init app mode system"); + this.setMode(AppModes.DEFAULT); + }, + + setMode(newMode) { + if (Object.values(AppModes).includes(newMode) && newMode !== this.mode) { + this.mode = newMode; + this.el.emit("appmode-change", { mode: this.mode }); + } + } +}); + +AFRAME.registerComponent("mode-responder-toggle", { + multiple: true, + schema: { + mode: { type: "string" }, + invert: { type: "boolean", default: false } + }, + + init() { + const AppModeSystem = this.el.sceneEl.systems["app-mode"]; + this.el.sceneEl.addEventListener("appmode-change", e => { + this.updateComponentState(e.detail.mode === this.data.mode); + }); + this.updateComponentState(AppModeSystem.mode === this.data.mode); + }, + + updateComponentState(isModeActive) { + const componentName = this.id; + this.el.components[componentName][isModeActive !== this.data.invert ? "play" : "pause"](); + } +}); + +AFRAME.registerComponent("mode-responder-hudstate", { + init() { + this.el.sceneEl.addEventListener("appmode-change", e => { + switch (e.detail.mode) { + case AppModes.HUD: + this.el.setAttribute("material", "color", "green"); + this.el.setAttribute("scale", "2 1 1"); + break; + case AppModes.DEFAULT: + this.el.setAttribute("material", "color", "white"); + this.el.setAttribute("scale", "0.3 0.3 1"); + break; + } + }); + } +}); + +AFRAME.registerComponent("hud-detector", { + dependencies: ["raycaster"], + + init() { + const AppModeSystem = this.el.sceneEl.systems["app-mode"]; + + let hoverTimeout; + this.el.addEventListener("raycaster-intersection", e => { + console.log("raycast hit", e.detail.els, e.detail.intersections); + hoverTimeout = setTimeout(() => { + AppModeSystem.setMode(AppModes.HUD); + }, 500); + }); + this.el.addEventListener("raycaster-intersection-cleared", e => { + console.log("raycast clear", e.detail.clearedEls); + AppModeSystem.setMode(AppModes.DEFAULT); + clearTimeout(hoverTimeout); + }); + } +}); diff --git a/templates/room.hbs b/templates/room.hbs index d56e30738aa48e8a0ffff9cbeb070f009f4cef91..1803a9c4d4048f8f505e488f880f786c1d51a98b 100644 --- a/templates/room.hbs +++ b/templates/room.hbs @@ -115,8 +115,19 @@ spawn-controller="radius: 4;" wasd-to-analog2d character-controller="pivot: #player-camera" + mode-responder-toggle__character-controller="mode: hud; invert: true;" ik-root > + <a-plane + class="hud" + mode-responder-hudstate + position="0 0.7 -0.7" + rotation="-28.9 0 0" + scale="0.3 0.3 1" + material="side:double" + > + </a-plane> + <a-entity id="player-camera" class="camera" @@ -124,6 +135,8 @@ position="0 1.6 0" personal-space-bubble look-controls + raycaster="objects: .hud; interval: 100; showLine: true; direction: 0 0 -1; origin: 0 -0.05 0;" + hud-detector ></a-entity> <a-entity