[/fusion_text][/fusion_builder_column][/fusion_builder_row][/fusion_builder_container]

CONTROLANDO ENTIDADES

Vamos a hacer diferentes sistemas para explicar esto. Para empezar, vamos a hacer un sistema que mueva entidades, y otro que las rote. De esta manera, podemos ver cómo los diferentes sistemas funcionan.

Antes de arrancar, vamos a modificar un poco el código anterior para que cada caja spawnee en posiciones aleatorias.

 

Copy to Clipboard

 

Para empezar, algo que voy a aclarar es que moví el método Instantiate a un método que cree llamado SpawnEntity(). Más que nada por cuestiones de practicidad.

Aclarado lo anterior, lo primero que vamos a hacer es analizar el código escrito. A simple vista creamos una instancia de Random, lo inicializamos y lo utilizamos abajo. El método NextFloat3() básicamente devuelve un float3() cuyos valores en xyz van desde 0 a 1. No obstante van a encontrar una diferencia entre lo que esperan que el código haga y lo que realmente hace. Si ejecutan el código van a notar dos cosas:

  1. Spawnea todas las cajas en la misma posición.
    • Esto es porque cada vez que va a crear una caja nueva, crea DE NUEVO la estructura Random y asigna la misma seed. Misma seed = Misma secuencia de resultados.
  2. La posición SIEMPRE es la misma no importa si vuelven a correr de cero el código.
    • Esto es por lo mismo que la aclaración de arriba. Incluso si reinician, la seed generada es la misma entonces van a obtener los mismos resultados.

Ahora… Probemos qué pasa si en lugar de crear una instancia nueva de Random simplemente generamos la variable global y lo hacemos una vez. Nos quedaría de la siguiente manera.

 

Copy to Clipboard

 

Noten que ahora sí spawnean en lugares diferentes, pero la primer caja sigue spawneando en el mismo lugar. Lo cual… De momento… Está bien. :D.

 

Resultado

Así nos queda utilizando la misma variable random para generar diferentes valores.

 

Y listo. Y aprendimos de paso algo adicional. Ahora… Vamos a lo bueno.

 

Sistemas y Entidades

Vamos a empezar creando el sistema encargado de mover cajas. Para ello, primero vamos a crear un componente que represente a un objeto que se mueve. Vamos a llamarlo MovementComponentData. La parte de Data se la agregamos más que nada porque el script sólo va a contener datos, y no funcionalidad (y porque la interfaz que implementa termina en ComponentData, je). Junto a esa clase vamos a crear otra llamada MovementSystem que va a representar al sistema que mueve a todas las entidades con nuestro componente.

 

Copy to Clipboard
Copy to Clipboard

Estas van a ser nuestras dos clases principales y van a ir a la par de cada sistema nuevo que vayamos creando. Básicamente creamos el componente y el sistema que se encarga de manejarlo. De esta manera tenemos todo el behaviour que cada componente debería agregar a las entidades, centralizado en un sólo lugar. Vamos a continuación a hacer que nuestras cajas se muevan. Para ello, vamos a agregar y explicar el siguiente código en la clase MovementSystem.

Copy to Clipboard

 

Si no te explotó la cabeza con este código, entonces vamos bien. Si vieron algo de LINQ se darán cuenta que la estructura es muy similar… De hecho es igual… De hecho ES LINQ.

Al margen de que quizás sean líneas nuevas para ustedes, entienden el código? Denle una mirada línea a línea. Fijense que es bastante intuitivo lo que hace más allá de que no sepan cómo funcionan las diferentes partes. Basicamente en español dice: “Con cada una de las entidades que tengan el componente MovementComponentData… Por cada una de ellas, incrementa su valor de Translation en el eje Y”. Esto arma una query y la última parte la ejecuta (el llamado al método Run).

Algo curioso de ese ForEach que vemos ahí es que básicamente los parámetros que ponemos dentro son referencias a los componentes que nos interesan dentro de las entidades que filtramos con el método WithAll<>. Y hago énfasis en eso porque vamos a armar ese ForEach de la manera que nos termine sirviendo dependiendo de cuáles sean los métodos que necesitemos. Así que la forma en la que vamos a conformar nuestros sistemas básicamente cumplen esa norma: El sistema pide todas las instancias que tengan determinado componente y les dice qué hacer.

Si ejecutan el código ahora van a ver que… Curiosamente… No pasa nada. Por qué? Lo adivinan? Falta algo. Pero qué?

El sistema en realidad está haciendo lo que le dijimos que haga: “Toma todos los objetos que tengan el componente MovementComponentData y los mueve”. El problema es que… Ninguno de nuestros cubos tiene actualmente ese componente. Por lo cual, lo único que tenemos que hacer, es agregarle ese componente a nuestros cubos y ya. Para ello vamos al bloque de código que hace aparecer a nuestros cubos y le vamos a agregar algo más.

 

Copy to Clipboard

 

Con esto lo que hacemos es que ahora todos nuestros cubos también tengan el componente MovementComponentData. Y ahora sí… Deberíamos ver a nuestras cajitas moviéndose hacia la libertad.

 

 

Ahora… Seguro se estarán preguntando: “Qué voy a comer a la noche?”… No sé… Yo me estoy preguntando eso ahora. Pero siendo más realista, probablemente quieran saber qué es eso del Translation que nunca vimos hasta ahora. Es el componente que se encarga de la parte espacial de nuestra entidad. A diferencia del sistema convencional en el que teníamos un Transform que adentro tenía posición, rotación y escala, acá todo se desglosa bastante más. O sea que nosotros vamos a tener en nuestro cubo un componente para cambiar su posición (Translation), y un componente para su rotación (Rotation). Es decir que necesitamos utilizar estos componentes para realizar las diferentes transformaciones en nuestro objeto.

Quizás otra pregunta a hacer sería: “Necesito agregarle esos componentes?”, y la respuesta sería “no en este caso”. Y digo en este caso porque al momento de convertir nuestro prefab al sistema de entidades Unity ya le agrega esos componentes (porque como el objeto en el sistema anterior los tiene, necesita ponerlos por equivalencias). También tienen otro componente que se llama LocalToWorld que posee una matrix4x4 que pueden setear y editar todos los valores de transformación juntos. Si se animan y conocen algo del tema hagan algunas pruebas y fijense cómo funciona. Sino, dejenlo para más adelante.

 

Translation, Rotation y LocalToWorld

Estos componentes los pueden visualizar en el Entity Debugger que vimos más arriba.

Antes de hacer la parte de que las cajas roten, intenten hacerla ustedes. Si bien son componentes nuevos, quizás ya se puedan dar una idea de qué se van a encontrar al intentar hacerlo y resolverlo por intuición. Intenten, si no se les ocurre a la primera, empezar a buscar info en internet. Es bueno siempre familiarizarse con eso.

Si lo anterior no resultó, dejo acá abajo el código necesario.

 

Copy to Clipboard
Copy to Clipboard

 

A modo de explicación, quizás ustedes lo resolvieron de otra forma, lo que hicimos fue:

  • math.mul
    • Multiplica dos quaterniones. Como seguramente ya saben de Unity, las rotaciones se manejan con Quaternions. Y en ECS no es diferentes. Entonces en este caso lo que hice fue multiplicar la rotación actual por el equivalente a 180 grados en el eje Y.
  • quaternion.RotateY()
    • Este método estático recibe una rotación en el eje Y representada EN RADIANES y nos devuelve el quaternion equivalente.
  • quaternion.radians()
    • Este método devuelve, dado un valor en grados, su equivalente en radianes. Se usa acá para pasarlo al método quaternion.RotateY().

Les voy a dejar como pequeño ejercicio que usen la variable speed que creamos para MovementDataComponent y RotationDataComponent.