Multijugador sin servidor

Sincroniza el estado de la escena entre jugadores.

Decentraland ejecuta las escenas localmente en el navegador del jugador. Por defecto, los jugadores pueden verse entre sí e interactuar directamente, pero cada jugador interactúa con el entorno de forma independiente. Los cambios en el entorno no se comparten entre jugadores por defecto.

Ver el mismo contenido en el mismo estado es extremadamente importante para que los jugadores interactúen de maneras más significativas.

Hay tres maneras de sincronizar el estado de la escena, para que todos los jugadores vean lo mismo:

Las dos primeras opciones se cubren en este documento. Son más simples, ya que no requieren servidor. La desventaja es que dependes más de las velocidades de conexión de los jugadores, y el estado de la escena no se persiste cuando todos los jugadores salen de la escena.

Marcar una entidad como sincronizada

En el Creator Hubarrow-up-right, marca una entidad como sincronizada añadiendo un componente Multiplayer a ella. Incluye una casilla de verificación para cada uno de los otros componentes en la entidad, permitiéndote seleccionar cuáles actualizar.



Para marcar una entidad como sincronizada mediante código, usa la syncEntity función:

El syncEntity la función toma las siguientes entradas:

  • arreglo incluye:: Una referencia a la entidad a sincronizar

  • componentIds: Una lista de los componentes que necesitan ser sincronizados de esa entidad. Es un arreglo que puede contener tantos elementos como sea necesario. Todos los valores deben ser componentId propiedades.

  • entityEnumId: (opcional) Un id único que se usa de forma consistente por todos los jugadores, ver Acerca del id de enum.

No todas las entidades o componentes necesitan ser sincronizados. Elementos estáticos como un árbol que permanece en el mismo lugar no requieren sincronización. En las entidades que sí sincronices, solo los componentes que cambian con el tiempo deberían ser sincronizados. Por ejemplo, si un cubo cambia de color al hacer clic, debes sincronizar solo el componente Material, no el MeshRenderer o el Transform, ya que esos nunca cambiarán.

circle-info

💡 Consejo: Si los datos que quieres compartir no existen como un componente, define un componente personalizadoarrow-up-right que contenga esos datos.

Acerca del id de enum

El entityEnumId de una entidad debe ser único. No está relacionado con el entityId local asignado en engine.addEntity(), que se genera automáticamente y puede variar entre jugadores que ejecutan la misma escena. El entityEnumId de una entidad debe definirse explícitamente en el código y ser único.

Establecer explícitamente este ID es importante para evitar inconsistencias si una condición de carrera hace que una parte de la escena cargue antes que otra. Tal vez para el jugador A la puerta en la escena sea la entidad 512, pero para el jugador B esa misma puerta es la entidad 513. En ese caso, si el jugador A abre la puerta, el jugador B ve en su lugar que se mueve todo el edificio.

circle-info

💡 Consejo: Crea un enum en tu escena, para mantener referencias claras a cada id sincronizable en tu escena.

Aquí el enum EntityEnumId se usa para etiquetar entidades con un identificador único, asegurando que cada cliente reconozca la entidad modificada, independientemente del orden de creación.

circle-exclamation

Entidades creadas por un jugador

Si una entidad se crea como resultado de una interacción del jugador, y esta entidad debe sincronizarse con otros jugadores, la entidad no necesita un entityEnumId. Puedes usar syncEntity() pasando solo la entidad y la lista de componentes. Un valor único para entityEnumId se asigna automáticamente tras bambalinas.

Todas las entidades instanciadas al iniciar la escena necesitan tener un ID asignado manualmente. Eso es para asegurar que todos los jugadores usen el mismo ID en cada una. Cuando un solo jugador está a cargo de instanciar una entidad, no son necesarios IDs explícitos. Otros jugadores reciben actualizaciones sobre esta nueva entidad con un ID ya asignado, por lo que no hay riesgo de desajustes de ID.

Por ejemplo, en una escena de batalla de bolas de nieve, cada vez que un jugador lanza una bola de nieve, está instanciando una nueva entidad que se sincroniza con otros jugadores. La bola de nieve no necesita un entityEnumId único.

Parented entities

El padre de una entidad normalmente se define vía el componente parent propiedad en el Transform . Esta propiedad sin embargo apunta al id de entidad local del padre, el cual podría variar, ver Acerca del id de enum. Para parentear entidades que necesitan ser sincronizadas, o que tienen hijos que necesitan ser sincronizados, usa el parentEntity() function en lugar de la Transform.

Ten en cuenta que tanto el padre como el hijo se sincronizan con syncEntity, por lo que todos los jugadores tienen un entendimiento común de qué ids son usados por ambas entidades. Esto es necesario incluso si los componentes del padre pueden que nunca necesiten cambiar. En este ejemplo, el syncEntity incluye un arreglo vacío de componentes, para evitar sincronizar componentes innecesarios.

circle-exclamation

Cuando las entidades son parentadas vía la función parentEntity() , también puedes hacer uso de las siguientes funciones auxiliares:

  • removeParent(): Deshacer los efectos de parentEntity(). Requiere que pases solo la entidad hija. El nuevo padre de la entidad se convierte en la entidad raíz de la escena. La entidad padre original no se elimina de la escena.

  • getParent(): Devuelve la entidad padre de la entidad que pasaste.

  • getChildren(): Devuelve la lista de hijos de la entidad que pasaste, como un iterable.

  • getFirstChild(): Devuelve el primer hijo en la lista para la entidad que pasaste.

Comprobar el estado de sincronización

Cuando un jugador acaba de cargar en una escena, puede que aún no esté sincronizado con otros jugadores que lo rodean. Si el jugador empieza a alterar el estado del juego antes de estar sincronizado, esto podría causar problemas en tu juego. Recomendamos siempre comprobar que un jugador esté sincronizado antes de permitirle editar cualquier cosa de la escena.

Si un jugador sale de los parcelas de la escena, también estará fuera de sincronización con la escena mientras esté parado afuera. Así que también es importante que los sistemas de la escena manejen ese escenario, ya que la escena sigue ejecutándose mientras el jugador está cerca. Una vez que el jugador regresa, se le actualiza automáticamente con cualquier cambio del estado de la escena.

Puedes comprobar si el estado de la escena está actualmente sincronizado para un jugador mediante la función isStateSyncronized() Esta función devuelve un booleano, que es true si el jugador ya está sincronizado con la escena.

Por ejemplo, podrías incluir esta comprobación en un sistema, y bloquear cualquier interacción si esta función devuelve false.

Enviar mensajes explícitos con MessageBus

Iniciar un message bus

Crea un objeto message bus para manejar los métodos necesarios para enviar y recibir mensajes entre jugadores.

Enviar mensajes

Usa la .emit comando del message bus para enviar un mensaje a todos los demás jugadores en la escena.

Cada mensaje puede contener una carga útil como segundo argumento. La carga útil es del tipo Object, y puede contener cualquier dato relevante que desees enviar.

circle-info

💡 Consejo: Si necesitas que un único mensaje incluya datos de más de una variable, crea un tipo personalizado para contener todos estos datos en un solo objeto.

Recibir mensajes

Para manejar mensajes de todos los demás jugadores en esa escena, usa .on. Cuando usas esta función, proporcionas una cadena de mensaje y defines una función a ejecutar. Cada vez que llega un mensaje con una cadena coincidente, la función dada se ejecuta una vez.

circle-exclamation

Ejemplo completo de MessageBus

Este ejemplo usa un message bus para enviar un nuevo mensaje cada vez que se hace clic en el cubo principal, generando un nuevo cubo en una posición aleatoria. El mensaje incluye la posición del nuevo cubo, para que todos los jugadores vean estos nuevos cubos en las mismas posiciones.

Probar una escena multijugador localmente

Si lanzas una vista previa de la escena y la abres en dos (o más) ventanas diferentes del Explorer, cada ventana abierta será interpretada como un jugador separado, y un servidor de comunicaciones simulado mantendrá a estos jugadores sincronizados.

Interactúa con la escena en una ventana, luego cambia a la otra para ver que los efectos de esa interacción también son visibles allí.

Usando el Creator Hub, haz clic en el botón Vista previa una segunda vez, y eso abre una segunda ventana del Explorer de Decentraland. Debes conectarte en ambas ventanas con direcciones diferentes. Las mismas sesiones permanecerán abiertas mientras la escena se recarga.



Como alternativa, puedes abrir una segunda ventana del Explorer escribiendo lo siguiente en la barra de direcciones del navegador:

decentraland://realm=http://127.0.0.1:8000&local-scene=true&debug=true&open-deeplink-in-new-instance=true

Escenas para un solo jugador

Si tu escena está desplegada en un Decentraland Worldarrow-up-right, puedes convertirla en una escena para un solo jugador. Los jugadores no se verán entre sí, no podrán chatear ni ver los efectos de las acciones de los demás.

Para hacer esto, configura el scene.json archivo de la escena para establecer el fixedAdapter a offline:offlineLa escena no tendrá ningún Communication Service y cada usuario que se una a ese world siempre estará solo.

Ejemplo:

Última actualización