diff --git a/public/index.html b/public/index.html index e12e192910bbe15d4c69eab76a9772b18d8b999b..d7d57d9c635af8ecc5281fc8e6554bf282d98b17 100644 --- a/public/index.html +++ b/public/index.html @@ -36,11 +36,12 @@ matcolor-audio-feedback="objectName: DodecAvatar_Head_0" scale-audio-feedback avatar-customization + personal-space-invader ></a-entity> </script> <script id="hand-template" type="text/html"> - <a-box class="hand" scale="0.2 0.1 0.3"></a-box> + <a-box class="hand" personal-space-invader scale="0.2 0.1 0.3"></a-box> </script> <script id="nametag-template" type="text/html"> @@ -55,7 +56,7 @@ <a-entity id="player-rig" networked wasd-controls snap-rotation="pivotSrc: #head"> <a-sphere scale="0.1 0.1 0.1"></a-sphere> - <a-entity id="head" camera="userHeight: 1.6" look-controls networked="template:#head-template;showLocalTemplate:false;"></a-entity> + <a-entity id="head" camera="userHeight: 1.6" personal-space-bubble look-controls networked="template:#head-template;showLocalTemplate:false;"></a-entity> <a-entity id="nametag" networked="template:#nametag-template;showLocalTemplate:false;"></a-entity> diff --git a/src/index.js b/src/index.js index 6889117a313f18fd2871130643b771437b0f0ffe..a54e9b8f13e73e18495e42ad1c65e7858df3c4a7 100644 --- a/src/index.js +++ b/src/index.js @@ -13,6 +13,8 @@ import "./components/nametag-transform"; import "./components/avatar-customization"; import "./components/mute-state-indicator"; +import "./systems/personal-space-bubble"; + import { generateName } from "./utils"; NAF.schemas.add({ diff --git a/src/systems/personal-space-bubble.js b/src/systems/personal-space-bubble.js new file mode 100644 index 0000000000000000000000000000000000000000..9087ec5a4614c0d80a400e13cca0382bf69236a0 --- /dev/null +++ b/src/systems/personal-space-bubble.js @@ -0,0 +1,93 @@ +var invaderPos = new AFRAME.THREE.Vector3(); +var bubblePos = new AFRAME.THREE.Vector3(); + +AFRAME.registerSystem("personal-space-bubble", { + init() { + this.invaders = []; + this.bubbles = []; + }, + + registerBubble(el) { + this.bubbles.push(el); + }, + + unregisterBubble(el) { + var index = this.bubbles.indexOf(el); + + if (index !== -1) { + this.bubbles.splice(index, 1); + } + }, + + registerInvader(el) { + var networkedEl = NAF.utils.getNetworkedEntity(el); + var owner = NAF.utils.getNetworkOwner(networkedEl); + + if (owner !== NAF.clientId) { + this.invaders.push(el); + } + }, + + unregisterInvader(el) { + var index = this.invaders.indexOf(el); + + if (index !== -1) { + this.invaders.splice(index, 1); + } + }, + + tick() { + // Update matrix positions once for each space bubble and space invader + for (var i = 0; i < this.bubbles.length; i++) { + this.bubbles[i].object3D.updateMatrixWorld(true); + } + + for (var i = 0; i < this.invaders.length; i++) { + this.invaders[i].object3D.updateMatrixWorld(true); + } + + // Loop through all of the space bubbles (usually one) + for (var i = 0; i < this.bubbles.length; i++) { + var bubble = this.bubbles[i]; + + bubblePos.setFromMatrixPosition(bubble.object3D.matrixWorld); + + var radius = bubble.components["personal-space-bubble"].data.radius; + var radiusSquared = radius * radius; + + // Hide the invader if inside the bubble + for (var j = 0; j < this.invaders.length; j++) { + var invader = this.invaders[j]; + + invaderPos.setFromMatrixPosition(invader.object3D.matrixWorld); + + var distanceSquared = bubblePos.distanceTo(invaderPos); + + invader.object3D.visible = distanceSquared > radiusSquared; + } + } + } +}); + +AFRAME.registerComponent("personal-space-invader", { + init() { + this.el.sceneEl.systems["personal-space-bubble"].registerInvader(this.el); + }, + + remove() { + this.el.sceneEl.systems["personal-space-bubble"].unregisterInvader(this.el); + } +}); + +AFRAME.registerComponent("personal-space-bubble", { + schema: { + radius: { type: "number", default: 0.8 } + }, + init() { + this.system.registerBubble(this.el); + }, + + remove() { + this.system.unregisterBubble(this.el); + } +});