Sistemas

Aprende cómo se usan los sistemas para actualizar el estado de la escena

Las escenas de Decentraland dependen de systems para actualizar cualquier dato a lo largo del tiempo, incluida la información almacenada en el componentsarrow-up-right.



systems son lo que hace que las escenas sean dinámicas; son funciones que se ejecutan periódicamente en cada tick del bucle de juego de la escena, cambiando lo que se renderizará.

El siguiente ejemplo muestra una declaración básica de un sistema:

La función en un sistema puede realizar cualquier cosa que desees. Normalmente, actuará sobre todas las entidades que cumplen ciertos queryarrow-up-right, siguiendo cierta lógica para cambiar los valores almacenados en los componentes de la entidad.

En el ejemplo anterior, el sistema MoveSystem es una función que se ejecuta en cada tick del bucle de juego, cambiando la posición de cada entidad en la escena que tiene un Transform.



Puedes tener múltiples sistemas en tu escena para desacoplar diferentes comportamientos, haciendo tu código más limpio y más fácil de escalar y reutilizar. Por ejemplo, un sistema podría encargarse de la física, otro podría hacer que una entidad obstáculo se mueva de un lado a otro continuamente, y otro podría manejar la IA de los personajes.

Múltiples sistemas pueden actuar sobre una sola entidad. Por ejemplo, un personaje no jugador podría moverse por sí mismo según una IA, pero también verse afectado por la gravedad si camina accidentalmente desde un acantilado. En ese escenario, los sistemas de física y de IA ni siquiera necesitan conocerse entre sí. Independientemente reevalúan su estado actual en cada tick del bucle de juego e implementan su propia lógica separada.

La función del sistema

La función de un sistema se ejecuta periódicamente, una vez por cada tick del bucle de juego. Esto ocurre automáticamente, no necesitas llamar explícitamente a esta función desde ninguna parte de tu código.

En una escena de Decentraland, puedes pensar en el bucle de juego como la agregación de todas las funciones de los sistemas en tu escena.

circle-exclamation

Manejar entidades por referencia

Algunos componentes y sistemas están pensados para usarse solo en una entidad de la escena. Por ejemplo, en una entidad que almacena la puntuación de un juego o quizás una puerta principal que es única en la escena. Para acceder a una de esas entidades dentro de un sistema, puedes simplemente referirte a la entidad o a sus componentes por nombre en las funciones del sistema.

Para proyectos más grandes, recomendamos que mantengas las definiciones de sistemas en archivos separados de la instanciación de entidades y componentes.

Recorrer una consulta de componentes

Muchas veces, tu escena tendrá múltiples entidades del mismo tipo que tendrán comportamientos similares. Por ejemplo, muchas puertas que se pueden abrir, o muchos enemigos que pueden atacar al jugador. Tiene sentido manejar todas estas entidades similares en un solo sistema, iterando sobre la lista y realizando las mismas comprobaciones en cada una.

No quieres que la función de un sistema itere sobre el conjunto completo de entidades en la escena, ya que esto podría ser muy costoso en términos de potencia de procesamiento. Para evitar esto, puedes consultar componentsarrow-up-right, para iterar solo sobre las entidades relevantes.

Por ejemplo, tu escena puede tener un PhysicsSystem que calcula el efecto de la gravedad sobre las entidades de tu escena. Algunas entidades en tu escena, como los árboles, no están destinadas a moverse nunca; por lo que sería inteligente evitar calcular los efectos de la gravedad sobre estas. Puedes definir un HasPhysics componente para marcar las entidades que podrían verse afectadas por la gravedad, y luego hacer que PhysicsSystem solo gestione las entidades devueltas por esta consulta.

Delta time entre frames

La función en un sistema puede opcionalmente incluir un argumento llamado El ejemplo anterior ejecuta un raycast recurrente cada 0.1 segundos. Usa un componente timer y la propiedad, de tipo maxDistance (representando delta time).

delta time representa el tiempo que pasó desde el último tick del bucle de juego, en segundos.

Las escenas de Decentraland se actualizan por defecto a 30 ticks por segundo. Esto significa que el El ejemplo anterior ejecuta un raycast recurrente cada 0.1 segundos. Usa un componente timer y la propiedad argumento pasado a todos los sistemas tenderá a ser igual a 1/30 (0.0333...).

Si el procesamiento de un frame tarda menos tiempo que este intervalo, entonces el engine esperará el tiempo restante para mantener las actualizaciones con un ritmo regular y El ejemplo anterior ejecuta un raycast recurrente cada 0.1 segundos. Usa un componente timer y la propiedad se mantendrá igual a 1/30 .



Si el procesamiento de un frame tarda más que 1/30 segundos, el dibujo de ese frame se retrasa. El engine entonces intenta terminar ese frame y mostrarlo tan pronto como sea posible. Luego procede al siguiente frame e intenta mostrarlo 1/30 segundos después del último frame. No compensa por el retraso anterior.



Idealmente, deberías evitar que tu escena pierda frames, ya que impacta la calidad de la experiencia del jugador. Dado que esto depende de la potencia de procesamiento de la máquina del jugador, siempre existe la posibilidad y tu escena debe estar preparada para manejarlo de forma elegante.

El El ejemplo anterior ejecuta un raycast recurrente cada 0.1 segundos. Usa un componente timer y la propiedad la variable es útil cuando el procesamiento de frames excede el tiempo por defecto. Suponiendo que el frame actual tomará tanto tiempo como el anterior, esta información puede usarse para calcular cuánto ajustar un cambio gradual, de modo que la tasa de cambio parezca constante y en proporción al retraso entre frames.

Ver posicionamiento de la entidadarrow-up-right para ejemplos de cómo usar El ejemplo anterior ejecuta un raycast recurrente cada 0.1 segundos. Usa un componente timer y la propiedad para hacer el movimiento más suave.

Bucle en un intervalo de tiempo

Si quieres que un sistema ejecute algo en un intervalo de tiempo regular, puedes hacerlo combinando el El ejemplo anterior ejecuta un raycast recurrente cada 0.1 segundos. Usa un componente timer y la propiedad argumento con un temporizador.

Para casos de uso más complejos, donde puede haber múltiples retardos y bucles creados dinámicamente, puede valer la pena definir un componente personalizado para almacenar un valor de temporizador individual para cada entidad. Ver Custom componentsarrow-up-right.

Orden de ejecución de sistemas

En algunos casos, cuando tienes múltiples sistemas ejecutándose, puede interesarte qué sistema se ejecuta primero en tu escena.

Por ejemplo, podrías tener un physics sistema que actualiza la posición de las entidades en la escena, y otro boundaries sistema que asegura que ninguna de las entidades esté posicionada fuera de los límites de la escena. En este caso, quieres asegurarte de que el boundaries sistema se ejecute al final. De lo contrario, el physics sistema podría mover entidades fuera de los límites de la escena pero el boundaries sistema no lo descubrirá hasta que se ejecute de nuevo en el siguiente frame.

Al agregar un sistema al engine, establece un priority opcional para determinar cuándo se ejecuta el sistema en relación con otros sistemas.

Los sistemas con un número de prioridad más bajo se ejecutan primero, por lo que un sistema con prioridad 1 se ejecuta antes que uno con prioridad 5.

Los sistemas a los que no se les da una prioridad explícita tienen una prioridad por defecto de 0, por lo que estos se ejecutan primero.

Si dos sistemas tienen el mismo número de prioridad, no hay forma de saber con certeza cuál de ellos se ejecutará primero.

Eliminar un sistema

Una instancia de un sistema puede añadirse o eliminarse del engine para activarlo o desactivarlo.

Si un sistema está definido pero no se agrega al engine, su función no es llamada por el engine.

Para eliminar un sistema, primero debes darle un nombre cuando lo agregues al engine, para que luego puedas referirte al sistema.

Una escena puede potencialmente tener múltiples instancias del mismo sistema ejecutándose juntas, por lo que necesitas decirle al engine cuál de ellas eliminar.

Otra forma de eliminar un sistema es declarar un puntero al sistema y luego pasar ese puntero al engine.removeSystem() método.

Ten en cuenta que el puntero es a la instance del sistema, no a la clase del sistema. En el ejemplo anterior, engine.removeSystem() no se está pasando mySystem (la declaración de la clase del sistema). Se está pasando mySystemInstance (la instancia que fue añadida al engine).

Puedes usar el método a continuación para hacer que un sistema se autotermine cuando su propósito esté cumplido.

Última actualización