Saltar al contenido

Construye una aplicación de RV multijugador A Frame en 10 minutos

Es hora de poner un poco de magia en nuestra escena de RV. Usar la corriente profunda es muy fácil comparado con cualquiera de las otras alternativas existentes como la Base de Fuego.

Empieza por conectar a tu cliente/usuario a la corriente profunda:

Construye una aplicación de RV multijugador A Frame en 10 minutos
Construye una aplicación de RV multijugador A Frame en 10 minutos
12345678var client =deepstream("<YOUR APP URL>");client.login({},function(success, data){if(success){startApp(data);}else{//handle login failed}});

javascript

Podemos conectar con el cliente JS de Deepstream como se muestra arriba. Para este tutorial, he usado la versión alojada de Deepstream llamada DeepstreamHub. Para ello, navega al panel de control de deepstream y crea una cuenta gratis. Luego, agrega una nueva aplicación y dale un nombre. En la página de inicio de esta aplicación, encontrarás algo llamado APP URL. Añade esta URL en el código anterior.

La corriente profunda viene con muchos mecanismos de autenticación. Para nuestra aplicación, simplemente usaremos el mecanismo NO AUTH por la simplicidad de este tutorial. Esta es la razón por la que el primer parámetro del método de login se deja vacío. También puedes elegir saltar este parámetro completamente. La devolución de llamada del método de login tiene dos parámetros: el éxito es una variable booleana, que si es verdadera implica que el login fue exitoso y los datos contienen algunos datos específicos del usuario como un ID único. Estos datos son diferentes para los distintos usuarios. Usaremos esta identificación única para diferenciar entre múltiples avatares generados por diferentes usuarios que aparecerían en la escena.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051///arranque creando un nuevo registro para cada usuariofuncióninicioApp(datos){var x =Matemáticas. random()*(10--10)+-10;var y =0;var z =0;var initialPosition ={ x: x, y: y, z: z };var myBoxColor ="#222";var currentUser = client. record.getRecord("user/"+ data.id); currentUser.whenReady(function(){ currentUser.set({ type: "a-box", attr:{ position: initialPosition, rotation: "0 0 0", color: myBoxColor, id: data.id, depth: "1", height: "1", width: "1"}});var camera =documento. getElementById("user-cam");//actualizar posición de la cámaravarnetworkTick=function(){var latestPosition = camera.getAttribute("position");var latestRotation = camera.getAttribute("rotation"); currentUser.set({ attr:{ position: latestPosition, rotation: latestRotation }});};setInterval(networkTick,100);});//cliente de características de presencia de Deepstream. presence.getAll(function(ids){ ids.forEach(subscribeToAvatarChanges);}); client.presence.subscribe((userId, isOnline)=>{if(isOnline){subscribeToAvatarChanges(userId);}else{removeAvatar(userId);}});}

javascript

Para simplificar, restringimos la rotación/movimiento del avatar sólo al eje X, manteniendo las coordenadas en los otros dos planos como cero. La posición inicial en el eje x se elige al azar para que los múltiples avatares no se amontonen en el mismo punto de la escena tan pronto como aparezcan.

a-box es una primitiva en A-Frame que puede ser usada convenientemente para crear una caja 3D con atributos básicos como dimensiones, posición, rotación, color, etc. Almacenaremos estos atributos utilizando un registro en el flujo profundo y añadiremos todas las demás partes del avatar, es decir, ojos y brazos, con respecto a la posición de esta caja (que sirve como cabeza del avatar).

Los registros son documentos en el almacén de datos en tiempo real de Deepstream. Hacemos uso de esta característica para almacenar los atributos como la identificación, posición, rotación, etc. de todos los usuarios, que más tarde serán implícitos en sus respectivos avatares.

Recuperamos un registro existente o creamos uno nuevo usando client.record.getRecord(); Nos aseguraremos de que sea un registro único para cada usuario añadiendo el id del cliente al nombre(ruta) del registro. Además, necesitamos agregar todos los atributos requeridos en este registro, incluyendo la posición inicial que se selecciona al azar. Como ya se ha dicho, seguimos el movimiento del teléfono utilizando la entidad de la cámara y actualizamos estos datos cada 100 milisegundos como se ha visto anteriormente y, por consiguiente, establecemos estos nuevos datos en el registro cada vez.

Presencia es un término común en el mundo real. Te da la información sobre el estado de conexión del usuario. En nuestro caso, mostraríamos el avatar en la escena sólo cuando un usuario se conecta (golpea la URL) y lo haríamos desaparecer tan pronto como un usuario abandona la aplicación (es decir, cierra la ventana del navegador). Además, el deepstream permite suscribirse a la presencia. Esto le permite disparar una llamada cada vez que un nuevo usuario entra o un usuario existente sale. Esto es exactamente lo que requerimos en nuestra aplicación.

En cuanto un usuario se conecta, hacemos que se suscriba a los cambios en el registro. Estos cambios, como pueden imaginar, serán en el objeto de atracción debido al cambio de posición y rotación. Nuestro objetivo es actualizar el avatar a medida que estos atributos se actualizan.

Antes de eso, primero tenemos que asegurarnos de que el avatar sea creado al menos una vez, para que actualice sus atributos. Lo hacemos usando un simple mapa de avatares donde almacenamos los ID de todos los avatares existentes.

1234//chequear si el avatar necesita ser creado o actualizadofuncionavatarExiste(id){regresar avatares.hasOwnProperty(id);}

javascript

12345678910111213//suscribirse a los cambios en los atributosfuncionessuscribirse a AvatarCambios(id){var newUser = client.record.getRecord("user/"+ id); newUser. whenReady(function(){ newUser.subscribe("attr",attr= >{if(avatarExists(id)){updateAvatar(id, newUser);}else{createAvatar(id, newUser);}});}}

javascript

Creamos un nuevo avatar estableciendo los atributos correctos (principalmente la posición y la rotación) para las partes correctas del avatar. Creo que la siguiente función es muy sencilla:

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586///add Avatar cuando el usuario entra en la aplicacióncreateAvatar(id, rec){var attr = rec. get("attr");var type = rec.get("type");var newBox =documento. createElement(type);for(var name in attr){ newBox.setAttribute(name, attr[name]);}//computar y asignar valores de posición a otras partes del avatar//wrt the boxvar leye =document.createElement("a-entity"); leye.setAttribute("mixin", "eye");var reye =document.createElement("a-entity"); reye. setAttribute("mixin", "ojo");var lpupil =documento.createElement("a-entity"); lpupil.setAttribute("mixin", "pupil");var rpupil =documento. createElement("a-entity"); rpupil.setAttribute("mixin", "pupil");var larm =documento.createElement("a-entity"); larm.setAttribute("mixin", "arm");var rarm =documento. createElement("a-entity"); rarm.setAttribute("mixin", "arm");var x = attr.position.x;var y =0;var z =0;var leyex = x +0.25;var leyey = y +0.2;var leyez = z -0. 6;var reyex = x -0.25;var reyey = y +0.2;var reyez = z -0.6;var lpx = x +0.25;var lpy = y +0.2;var lpz = z -0.8;var rpx = x -0.25;var rpy = y +0. 2;var rpz = z -0.8; leye.setAttribute("posición", leyex +" "+ leyey +" "+ leyez); leye.setAttribute("id", "leye "+ id); reye.setAttribute("posición", reyex +" "+ reyey +" "+ reyez); reye. setAttribute("id", "reye "+ id); lpupil.setAttribute("posición", lpx +" "+ lpy +" "+ lpz); lpupil.setAttribute("id", "lpupil "+ id); rpupil. setAttribute("position", rpx +" "+ rpy +" "+ rpz); rpupil.setAttribute("id", "rpupil "+ id);var larmx = x -0.5;var larmy = y -1.8;var larmz = z;var rarmx = x +0. 5;var rarmy = y -1.8;var rarmz = z; larm.setAttribute("posición", larmx +" "+ larmy +" "+ larmz); larm.setAttribute("id", "larm "+ id); larm. setAttribute("rotación", "0 0 -10"); rarm.setAttribute("posición", rarmx +" "+ rarmy +" "+ rarmz); rarm.setAttribute("id", "rarm "+ id); rarm. setAttribute("rotación", "0 0 10");//wrap the whole avatar inside a single entityvar avatarRoot =document.createElement("a-entity"); avatarRoot. appendChild(newBox); avatarRoot.appendChild(leye); avatarRoot.appendChild(reye); avatarRoot.appendChild(lpupil); avatarRoot.appendChild(rpupil); avatarRoot. appendChild(larm); avatarRoot.appendChild(rarm);var scene =document.getElementById("scene"); scene.appendChild(avatarRoot); avatars[id]= avatarRoot;}

javascript

Las posiciones relativas de los ojos y los brazos con respecto a la caja se aplican manualmente. Esto se hace más fácil con el uso de una herramienta de inspección visual que viene con el A-Frame.

Envolvemos todas las partes del avatar en un elemento raíz para que sea más fácil aplicar los cambios de atributos a todo el avatar y evitar una situación de tipo zombi en la que una de las partes esté desorientada respecto a las demás. Esto también facilita la eliminación del avatar completo cuando un usuario cierra la sesión.

Si un avatar ya existe, simplemente actualizamos su posición y rotación a partir de los datos que se actualizan continuamente en el objeto de atracción en el registro de usuario. Si se desplaza hacia arriba a la función subscribeToAvatarChanges(), observará que updateAvatar() es una función de devolución de llamada a una suscripción de registro. En el deepstream, la función callback se dispara cada vez que cambian los datos del registro/ruta suscrita. Esto hace que sea muy fácil para nosotros actualizar continuamente el avatar real también, de acuerdo con los datos cambiantes.

123456789//actualizar Avatar según los atributos cambiantesfunctionupdateAvatar(id, userRecord){var avatar = avatars[id];var position = userRecord.get("attr.position");var rotation = userRecord.get("attr.rotation"); avatar.setAttribute("position", position); avatar.setAttribute("rotation", rotation);}

javascript

Por último, tenemos que asegurarnos de que el avatar sea eliminado de la escena cada vez que un usuario cierra la sesión. Esto se puede hacer usando la presencia manejando la bandera de cierre de sesión en la devolución de llamada. Aquí hay algunas cosas que necesitas hacer cuando un usuario cierra la sesión:

123456//eliminar Avatar cuando el usuario sale de la aplicacióneliminarAvatar(id){var scene =documento.getElementById("escena"); scene.removeChild(avatars[id]); client.record.getRecord("user/"+ id).delete();}

javascript

Empezamos quitando el avatar completo de la escena. También nos aseguramos de eliminar el registro correspondiente para asegurarnos de no desperdiciar espacio de almacenamiento innecesario.