UNPKG

networked-aframe

Version:

A web framework for building multi-user virtual reality experiences.

195 lines (173 loc) 7.44 kB
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>Nametag Example — Networked-Aframe</title> <meta name="description" content="Nametag — Networked-Aframe" /> <script src="https://aframe.io/releases/1.6.0/aframe.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/4.8.1/socket.io.min.js"></script> <script src="/easyrtc/easyrtc.js"></script> <script src="/dist/networked-aframe.js"></script> <script src="https://cdn.jsdelivr.net/gh/c-frame/aframe-extras@7.5.2/dist/aframe-extras.controls.min.js"></script> <script src="https://cdn.jsdelivr.net/npm/aframe-environment-component@1.3.7/dist/aframe-environment-component.min.js"></script> <script src="/js/spawn-in-circle.component.js"></script> <script> // Temporary workaround for template declaration; see issue 167 NAF.schemas.getComponentsOriginal = NAF.schemas.getComponents; NAF.schemas.getComponents = (template) => { if (!NAF.schemas.hasTemplate('#head-template')) { NAF.schemas.add({ template: '#head-template', components: [ { component: 'position', requiresNetworkUpdate: NAF.utils.vectorRequiresUpdate(0.001) }, { component: 'rotation', requiresNetworkUpdate: NAF.utils.vectorRequiresUpdate(0.5) }, // In this example, we don't sync the material.color itself, like the basic example; // we instead sync player-info, which includes color setting + updating. // (you can see an example of the other pattern in the basic.html demo) 'player-info' ] }); } if (!NAF.schemas.hasTemplate('#rig-template')) { NAF.schemas.add({ template: '#rig-template', components: [ { component: 'position', requiresNetworkUpdate: NAF.utils.vectorRequiresUpdate(0.001) }, { component: 'rotation', requiresNetworkUpdate: NAF.utils.vectorRequiresUpdate(0.5) } ] }); } const components = NAF.schemas.getComponentsOriginal(template); return components; }; </script> <script> window.ntExample = { randomColor: () => { return '#' + new THREE.Color(Math.random(), Math.random(), Math.random()).getHexString(); } }; AFRAME.registerComponent('player-info', { // notice that color and name are both listed in the schema; NAF will only keep // properties declared in the schema in sync. schema: { name: { type: 'string', default: 'user-' + Math.round(Math.random() * 10000) }, color: { type: 'color', // btw: color is just a string under the hood in A-Frame default: window.ntExample.randomColor() } }, init: function () { this.head = this.el.querySelector('.head'); this.nametag = this.el.querySelector('.nametag'); this.ownedByLocalUser = this.el.id === 'player'; if (this.ownedByLocalUser) { // populate the html overlay with the correct name on init this.nametagInput = document.getElementById('username-overlay'); this.nametagInput.value = this.data.name; // add the initial color to the html overlay color picker button document.querySelector('#color-changer').style.backgroundColor = this.data.color; document.querySelector('#color-changer').style.color = this.data.color; } }, // here as an example, not used in current demo. Could build a user list, expanding on this. listUsers: function () { console.log( 'userlist', [...document.querySelectorAll('[player-info]')].map((el) => el.components['player-info'].data.name) ); }, newRandomColor: function () { this.el.setAttribute('player-info', 'color', window.ntExample.randomColor()); }, update: function () { if (this.head) this.head.setAttribute('material', 'color', this.data.color); if (this.nametag) this.nametag.setAttribute('value', this.data.name); } }); </script> </head> <body> <!-- This <button> and <input> will overlay on top of the A-Frame canvas--this style is all you need. Note the onclick and oninput attributes; on every call, they will run .setAttribute() for the player-info component's data. NAF will keep that property in sync, since 'name' and 'color' are declared in the schema of the 'player-info' component --> <button id="color-changer" style="z-index: 100; bottom: 24px; left: 24px; position: fixed" onclick="let newColor = window.ntExample.randomColor(); document.getElementById('player').setAttribute('player-info', 'color', newColor); document.querySelector('#color-changer').style.backgroundColor = newColor; document.querySelector('#color-changer').style.color = newColor; " ></button> <input id="username-overlay" style="z-index: 100; bottom: 24px; left: 48px; position: fixed" oninput="document.getElementById('player').setAttribute('player-info', 'name', this.value)" /> <a-scene networked-scene=" room: nametag; debug: true; adapter: wseasyrtc; " renderer="physicallyCorrectLights: true;" > <a-assets> <template id="rig-template"> <a-entity></a-entity> </template> <template id="head-template"> <a-entity class="avatar" player-info> <a-sphere class="head" scale="0.2 0.22 0.2"></a-sphere> <a-entity class="face" position="0 0.05 0"> <a-sphere class="eye" color="white" position="0.06 0.05 -0.16" scale="0.04 0.04 0.04"> <a-sphere class="pupil" color="black" position="0 0 -1" scale="0.2 0.2 0.2"></a-sphere> </a-sphere> <a-sphere class="eye" color="white" position="-0.06 0.05 -0.16" scale="0.04 0.04 0.04"> <a-sphere class="pupil" color="black" position="0 0 -1" scale="0.2 0.2 0.2"></a-sphere> </a-sphere> </a-entity> <!-- here we add a text component for a nametag; the value will be updated by the player-info component --> <a-text class="nametag" value="?" rotation="0 180 0" position=".25 -.35 0" side="double" scale=".5 .5 .5" ></a-text> </a-entity> </template> </a-assets> <a-entity environment="preset:starry;groundColor:#000000;"></a-entity> <a-entity light="type:ambient;intensity:0.5"></a-entity> <a-entity id="rig" movement-controls="fly:true;" spawn-in-circle="radius:3" networked="template:#rig-template;"> <a-entity id="player" camera position="0 1.6 0" look-controls networked="template:#head-template;" visible="false" ></a-entity> </a-entity> </a-scene> </body> </html>